I am getting closer in my quest for a JSON response. In this example, the events variable gets populated AFTER it's returned, causing a blank output. I need it to wait. I have read that a promise is the way to go... but not sure how that would work... in my console.log you can see the array but Events.all(); returns null.
.factory('Events', function($http) {
var events="";
$http.get('http://appserver.falconinet.com/events.lasso').then(function(resp) {
events = resp.data;
console.log(events);
}, function(err) {
console.error('ERR', err);
// err.status will contain the status code
})
return {
all: function() {
return events;
},
get: function(eventId) {
for (var i = 0; i < events.length; i++) {
if (events[i].id === parseInt(eventId)) {
return events[i];
}
}
return null;
}
}
})
and here is my controller:
// events
.controller('EventsCtrl', function($scope, Events) {
$scope.events = Events.all();
})
.controller('EventDetailCtrl', function($scope, $stateParams, Events) {
$scope.event = Events.get($stateParams.eventId);
})
Following will return the promise created by $http as well as caches the loading of all events.
.factory('Events', function ($http, $q) {
function loadEvents(id) {
var promise = $http.get('http://appserver.falconinet.com/events.lasso', {cache: true});
// return the promise
return promise.then(function (resp) {
var events = resp.data;
if (id) {
// returns item or promise rejection
return getEventById(id, events);
} else {
return events;
}
}).catch (function (err) {
console.log('Events error ', err);
});
}
// helper function , returns event or promise rejection
function getEventById(id, events) {
for (var i = 0; i < events.length; i++) {
if (events[i].id === parseInt(eventId)) {
return events[i];
}
}
return $q.reject('None found');
}
return {
all: function () {
return loadEvents();
},
get: function (eventId) {
return loadEvents(eventId);
}
}
});
Then in controllers you need to resove your data in the promise then callback
.controller('EventsCtrl', function($scope, Events) {
Events.all().then(function(events){
$scope.events = events;
});
})
.controller('EventDetailCtrl', function($scope, $stateParams, Events) {
Events.get($stateParams.eventId).then(function(event){
$scope.event = event;
});
})
As you mentioned, wrapping your actual process in a new promise is the way to go. In order to do so, the usage of this factory needs some tweaks. Lemme try to write a sample from your script, but I don't promise to get it working on the first try :)
.factory('Events', function($http, $q) {
return {
all: function() {
var myPromise = $q.defer();
$http.get('http://appserver.falconinet.com/events.lasso')
.then(function(resp) {
myPromise.resolve(resp.data);
}, function(err) {
myPromise.reject(err);
});
return myPromise.promise;
},
get: function(eventId) {
var myPromise = $q.defer();
$http.get('http://appserver.falconinet.com/events.lasso')
.then(function(resp) {
var events = resp.data;
for (var i = 0; i < events.length; i++) {
if (events[i].id === parseInt(eventId)) {
myPromise.resolve(events[i]);
}
}
}, function(err) {
myPromise.reject(err);
});
return myPromise.promise;
}
}
});
Besides everything, this can be improved as you placer but I found pretty straightforward to do so after knowing how to handle promises.
Using them would be like this:
// Get all
Events.all().then(function(events){
$scope.events = events;
});
// Get one
Events.get(eventId).then(function(event){
$scope.events = event;
});
Related
I have a following function which uses streaming-query-rows of mysql node js module. How can i unit test the below function and also i want to mock the database behavior instead of connecting to database while unit test.
'processRow' and ''wirteCsvFile'' function both are synchronous task.
function executeTask(sql_connection,sql_query) {
let query = sql_connection.query(sql_query);
let showInfo = {};
let showids = [];
query
.on('error', (error) => {
console.error(`error executing query --> ${error}`);
})
.on('result', function (row) {
sql_connection.pause();
processRow(row, showInfo, showids, function () {
sql_connection.resume();
});
})
.on('end', function () {
showids.forEach(showid => {
if (showInfo[showid].faults.length === 0) {
delete showInfo[showid];
}
});
wirteCsvFile(showInfo, (error, done) => {
if (error) {
console.error(error);
} else {
console.log("done");
process.exit();
}
})
});
}
You can stub the query function to return whatever you want instead of making request to database:
sinon.stub(connection, "query").callsFake(() => /* whatever you want here */);
You should also break executeTask into smaller functions, for ex:
function errorHandler(error) {
console.error(`error executing query --> ${error}`);
}
function resultHandler(data, row) {
sql_connection.pause();
processRow(row, data.showInfo, data.showids, function() {
sql_connection.resume();
});
}
function endHandler(data) {
data.showids.forEach(showid => {
if (data.showInfo[showid].faults.length === 0) {
delete data.showInfo[showid];
}
});
wirteCsvFile(data.showInfo, (error, done) => {
if (error) {
console.error(error);
} else {
console.log("done");
process.exit();
}
})
}
function executeTask(sql_connection, sql_query) {
let query = sql_connection.query(sql_query);
let data = {
showInfo: {},
showids: [],
};
query.on('error', errorHandler)
.on('result', resultHandler.bind(null, data))
.on('end', endHandler.bind(null, data));
}
Now you can test errorHandler, resultHandler, endHandler separately
What I'm thinking is we can mock the sql_connection with a class of Event Emitter.
const sinon = require("sinon");
const assert = require('assert');
const EventEmitter = require('events');
const src = require('....'); // your source file that contain `executeTask`
// Create mock emitter
class QueryEmitter extends EventEmitter {}
describe('test execute task', function() {
const queryEmitter = new QueryEmitter();
// we build mock connection that contains all methods used as in `sql_connection`
const conn = {
query: sinon.stub().returns(queryEmitter),
pause: sinon.spy(),
resume: sinon.spy()
};
const query = 'SELECT *';
before(function() {
src.executeTask(conn, query);
});
it('calls query', function() {
assert(conn.query.calledWith(query));
});
it('on result', function() {
queryEmitter.emit('result');
assert(conn.pause.called);
// assert if processRow is called with correct arguments
// assert if conn.resume is called
});
it('on end', function() {
queryEmitter.emit('end');
// assert if writeCsvFile is called
});
// probably is not needed since you only call console.log here
it('on error', function() {
queryEmitter.emit('error');
});
});
Hope it helps
var job = new cronJob('* * * * * *', function () {
Draft.find().then(data => {
var finalData = data;
finalData.forEach(function(item2) {
if (item2.scheduledTime === 'now') {
finalData.forEach(function (item) {
var psms = {
phoneno: item.senderdata,
sender: item.senderName,
message: item.message
}
var obj = psms;
var finalpostsms = obj.phoneno.split("\n").map(s => ({ ...obj,
phoneno: +s
}));
Profsms.bulkCreate(finalpostsms).then(function (data) {
if (data) {
console.log("successfully moved in profsms mysql");
} else {
console.log("failed");
}
})
});
} else {
console.log('Better you be in drafts..manual input');
}
//delete from draft
if (item2.scheduledTime === 'now') {
Draft.findOneAndRemove({
_id: item2._id
}, function (err, employee) {
if (err)
console.log('err');
console.log('Successfully deleted from draft');
});
} else {
console.log('You cant delete from drafts hahaha because no sendnow statement');
}
});
});
}, function () {
console.log('DelCron Job finished.');
}, true, 'Asia/Calcutta');
This above code, working as asynchronously.
I want the above code to be work as synchronous, need some answers. I am a newbie for JS development
Is it possible to do with async await? i dont know how to write async await code.
Your callback should be
async function(){
let data = await Draft.find();
...process data;
}
This is an async await sample code, you can modify based on your need. But first you need to use Node that support async syntax. I believe node 8 LTS is already have async/await feature.
function get() {
// your db code block
return Promise.resolve(7);
}
async function main() {
const r = await get();
console.log(r);
}
main();
I have a function, it has a $http.post for login purpose. If success, another $http.post will call a php file that fetches data from database. The problem is that, when I am trying to load the data from localStorage it returns me null. Why is it so?
$scope.loginUser = function ()
{
var data =
{
username: $scope.loginInfo.username,
password: $scope.loginInfo.password
}
$http.post("endpoints/login.php", data).success(function(response)
{
if(response==="ERROR")
{
//DONT DO ANYTHING
}
else
{
localStorage.setItem("token", JSON.stringify(response));
console.log("loginController: name is this " + localStorage);
fetchDataFunction(data);
$state.go("application");
//$state.go("application", result);
}
}).error(function(error)
{
console.error(error);
});
}
fetchDataFunction = function(data)
{
$http.post("endpoints/fetchData.php", data).success(function(response)
{
localStorage.setItem("data", JSON.stringify(response));
}).error(function(error)
{
console.error(error);
});
}
You can return the $http.post, which will return a promise, and then all your code will work in the correct order:
$scope.loginUser = function () {
login($scope.loginInfo).then(function (response) {
localStorage.setItem("token", JSON.stringify(response));
console.log("loginController: name is this " + localStorage.getItem("token"));
fetchDataFunction(data).then(function () {
localStorage.setItem("data", JSON.stringify(response));
console.log(localStorage.getItem("data"));
$state.go("application");
}).catch(function (error) {
console.error(error);
});
}).catch(function (response) {
console.error(error);
});
};
var login = function (user) {
return post("endpoints/login.php", user);
};
var fetchDataFunction = function (data) {
return post("endpoints/fetchData.php", data);
};
var post = function (url, data) {
var deferred = $q.defer;
$http.post(url, data).then(function (response) {
if (response === "ERROR") {
deferred.reject(response);
}
else {
deferred.resolve(response);
}
}).catch(function (error) {
deferred.reject(error);
});
return deferred;
};
Notes:
You will need to make sure you inject $q into your controller along with $http
You should use localStorage.getItem() when recalling information from the global object
You should use then/catch instead of success/error, as these are now depreciated: https://docs.angularjs.org/api/ng/service/$http
I have this factory:
'use strict';
angular.module('testCon').factory('UserService', function ($http) {
return {
getAll: function () {
return $http.get('http://localhost:1337/api/user');
}
}
});
And this controller:
'use strict';
angular.module('testCon').controller('UserController', function ($scope, UserService) {
$scope.users = [];
UserService.getAll().then(
function (data) {
$scope.users = data.data;
}, function (err) {
}
);
});
Can I somehow avoid the data.data I would like to have only data. What is it that forces me to do data.data in order to see it in the scope?
Simply you can't avoid that. You could make that as one time change by returning only a response.data from getAll method. Then all the consumer will get direct data.
Code
angular.module('testCon').factory('UserService', function ($http) {
return {
getAll: function () {
return $http.get('http://localhost:1337/api/user').then(function(response){
return response.data
});
}
}
});
You can try something like this:
'use strict';
angular.module('testCon').factory('UserService', function ($http) {
return {
getAll: function () {
return $http.get('http://localhost:1337/api/user').then(function (response) {
return response.data;
});
}
}
});
Then keep the other function as:
'use strict';
angular.module('testCon').controller('UserController', function ($scope, UserService) {
$scope.users = [];
UserService.getAll().then(
function (data) {
$scope.users = data;
}, function (err) {
}
);
});
What happens is that the first promise return is chained with the second then(..) but the second one gets the extracted data. It's a cool thing about promises.
.factory('MY', function($http){
return {
mustafa: function(){
var factory = {};
var url = '/uzak/remote.php?callback=JSON_CALLBACK';
var yarro = $http.get(url).success(function(response){
return response.data);
});
return yarro;
}
}
})
.controller('nbgCtrl', function() {
$scope.mangas = MY.mustafa();
})
I wanna use json data above like. But it isn't working. Could you guys help me?
You can return the promise, and then resolve it in the controller:
.factory('MY', function($http){
return {
mustafa: function() {
var url = '/uzak/remote.php?callback=JSON_CALLBACK';
return $http.get(url);
}
};
})
Finally, you have to inject the service to the controller.
.controller('nbgCtrl', function($scope, MY) {
MY.mustafa().success(function(response) {
$scope.mangas = response.data;
);
});