How to programatically chain two js functions? - javascript

I'm trying to solve how I can to chain several js functions (two in this case). I have one javascript function to save() an another for saveAndPrint(). I need to chain the call because I need the id generated in save() to forward it for printing in the second one. Probably I just could use only one function to do both things but I'd like to learn how to do this. At the moment I just getting an 'undefined' because second function starts before the first one finishes.
Here is the code:
$scope.save = function () {
var receipt = {
documentType: 'RCI',
expirationDate: new moment().format('YYYY-MM-DD'),
person: {id: $scope.financeDocuments[0].person.id},
payments: getPayments(),
promotions: [],
creationDate: new moment().format('YYYY-MM-DD'),
compensatedDocuments: getDocumentsToPay()
};
financeDocumentService.save(receipt, function (response) {
receipt = response;
$uibModalInstance.close(response);
}).$promise.then(function (data) {
return receipt;
});
};
$scope.saveAndPrint = function() {
var document = $scope.save();
$window.location.href = "#/finance/receipt_show/"+document.id;
};
Thanks a lot!

First return the promise:
$scope.save = function () {
var receipt = {
documentType: 'RCI',
expirationDate: new moment().format('YYYY-MM-DD'),
person: {id: $scope.financeDocuments[0].person.id},
payments: getPayments(),
promotions: [],
creationDate: new moment().format('YYYY-MM-DD'),
compensatedDocuments: getDocumentsToPay()
};
//RETURN the promise
͟r͟e͟t͟u͟r͟n͟ financeDocumentService.save(receipt, function (response) {
receipt = response;
$uibModalInstance.close(response);
}).$promise.then(function (data) {
return receipt;
});
};
Then chain from the promise:
$scope.saveAndPrint = function() {
var promise = $scope.save();
promise.then(function(receipt) {
$window.location.href = "#/finance/receipt_show/"+document.id;
});
};
For more information,
AngularJS $q Service API Reference - Chaining Promises
You`re Missing the Point of Promises

Related

How to return data from promise inside JSON object? angularjs

This is my first time when I try to return data from promise inside JSON object and I stuck with this task
So common way is something like this
service js
app.factory("dataService", ["$http",
function ($http) {
function getData(id) {
return $http.get('endpoint', id)
.then(function (response) {
return response.data
});
}
return {
getData: getData
}
}])
controller js
$scope.data = {}
dataService.getData($routeParams.id)
.then (function (res) {
$scope.data = res
});
this works fine and everybody is happy
now I'm trying to assign data inside object
controller js
angular.forEach($scope.properties, function (item) {
$scope.data.properties.push({
order: item.number,
name: item.name,
value: item.value,
items: $scope.getProp(item.id)
})
});
$scope.getProp = function (id) {
return dataService.single(id)
.then (function (res) {return res});
};
service js
function single(id) {
return $http.get('endpoint' + "/" + id)
.then(function (response) {
return response.data
})
}
and now I'm getting JSON object with promise and $$state inside
I understand the nature of this problem but solution for this problem is out of range of my knowledges, so could somebody help me deal with it ?
One way to make it work is:
$scope.data.properties = [];
var promiseList = $scope.properties.map(function(item) {
var promise = $scope.getProp(item.id);
return promise.then(function (data) {
var newItem = {
id: item.id,
order: item.number,
name: item.name,
value: item.value,
items: data
};
$scope.data.properties.push(newItem);
return newItem;
});
});
$q.all(promiseList).then(function(itemList) {
console.log(itemList);
//More code here
});
The above example creates a list of promises that return objects that have the items property populated with data from the promise returned from $scope.getProps.
In addition it pushes each populated item to scope. Because the asynchronous XHRs may not complete in the order that they were started, the scope list may not be in the same order as the original.
The $q.all method however will wait for all the XHRs to complete and return the list in the original order.

How to resolve function and call other function in angular

I have two functions and I want to call one function after other only first function is resolved successfully.
$scope.createNewWorkModule = function (data, selectedUser) {
$scope.workOrderInfo = $localStorage.workOrderInfo;
$scope.createNewWorkOrder($scope.workOrderInfo).then(function (response) {
$scope.workOrderId = $localStorage.workOrderId;
var newWM = {
name: data.name,
};
$scope.myPromise = operationsFactory.createWorkModule(angular.toJson(newWM)).success(function (response) {
$rootScope.workModules = response.result;
return $scope.workOrder;
})
});
};
$scope.createNewWorkOrder = function (data) {
var newWD = {
name: data.name,
description: data.description,
user_id: $cookies.userId
};
$scope.myPromise = operationsFactory.createWorkOrder(angular.toJson(newWD)).success(function (response) {
$localStorage.workOrderId = response.result.id;
})
return $localStorage.workOrderId;
};
I am trying to call $scope.createNewWorkOrder with .then but it is giving error that
TypeError: Cannot read property 'then' of undefined
at Scope.$scope.createNewWorkModule (work-order-create-controller.js:36)
at $parseFunctionCall (angular.js:12158).
How do I fix this?
Update:
Unable to update the view with data retrieved:
<div class="panel panel-default">
<div class="panel-heading font-bold">
<span>List of Work Modules</span>
</div>
<ul ng-repeat="wm in workModules" style="list-style: none">
<li>{{wm.name}}</li>
<li>{{wm.description}}</li>
</ul>
</div>
Your asynchronous functions should always return the promises.
Make sure the then success functions always return the values needed by the next handler in the chain (and don't use the deprecated .success method as that doesn't chain correctly, always use .then but be aware of the slightly different parameter is gets from $http results).
Also try not to put things into $scope unless you really need them there, probably many of your functions can be just functions and the values could be local variables in the controller.
Note that once you are using .then you can issue a new call at the end of one success handler and process the result with another .then at the same level, no need to nest things further.
$scope.createNewWorkModule = createNewWorkModule; // Do you need both this
$scope.createNewWorkOrder = createNewWorkOrder; // and this?
function createNewWorkModule(data, selectedUser) {
$scope.workOrderInfo = $localStorage.workOrderInfo;
return createNewWorkOrder($scope.workOrderInfo)
.then(function (workOrderId) {
$scope.workOrderId = workOrderId;
var newWM = {
name: data.name,
};
return operationsFactory.createWorkModule(angular.toJson(newWM));
})
.then(function (response) {
// here we have response from the createWorkModule call
$rootScope.workModules = response.data.result;
return $scope.workOrder;
});
};
function createNewWorkOrder(data) {
var newWD = {
name: data.name,
description: data.description,
user_id: $cookies.userId
};
return operationsFactory.createWorkOrder(angular.toJson(newWD))
.then(function (response) {
var workOrderId = $localStorage.workOrderId = response.data.result.id;
return workOrderId;
})
};
You are getting error then is not a function, because the value returned is undefined as $localStorage.workOrderId is resolved async. Ideally you should return a promise.
return operationsFactory.createWorkOrder(angular.toJson(newWD)).success(function (response) {
$localStorage.workOrderId = response.result.id;
return $localStorage.workOrderId;
});

Returning a value in AngularJS

I wrote an angular service which querys a db and should return the Categories:
(function() {
'use strict';
angular.module('budget')
.service('CategoriesService', ['$q', CategoriesService]);
function CategoriesService($q) {
var self = this;
self.loadCategories = loadCategories;
self.saveCategorie = saveCategorie;
self.datastore = require('nedb');
self.db = new self.datastore({ filename: 'datastore/default.db', autoload : true});
function saveCategorie (categorie_name) {
var entry = {name: categorie_name,
type: 'categorie'}
self.db.insert(entry);
};
function loadCategories () {
self.db.find({type: 'categorie'}, function (err, docs) {
var categories = docs;
return categories;
});
};
return {
loadCategories: self.loadCategories,
saveCategorie: self.saveCategorie
};
}
})();
When I console.log inside the function loadCategories() it returns me an array of 6 objects (the objects from the database) but outside of the function it just gives me undefined.
I am calling via the controller with CategoriesService.loadCategories()
So I think I might have to do something thas called promise but Iam not sure about that.
How can I get acctual data back from this service?
First of all you don't need to return anything from the service factory recipe, you just need to assign a method to the this variable.
At least, you need:
// service.js
self.loadCategories = function() {
var deferred = $q.defer();
db.find({type: 'categorie'}, function (err, docs) {
deferred.resolve(docs);
});
return deferred.promise;
};
// controller.js
service
.loadCategories()
.then(function(categories) {
$scope.categories = categories;
})
;
you need to return your promise first so just add one more return and you are good to go...
function loadCategories () {
// you need to return promise first and you can resolve your promise in your controller
return self.db.find({type: 'categorie'}, function (err, docs) {
var categories = docs;
return categories;
});
};

jQuery asynchronous issue undefined value

I am having difficulties with Javascript's asynchronous functions.
Code displayed below is so far almost entire code I have and I can't get it to work.
I ma trying to use Eventful API to pull some data from the server, and display it in my frontend which is created by jQuery.
So, the problem is following: function search, which is calling function Eventful.prototype.searchanje always ends up with undefined value, while a few seconds later, function searchanje console logs actual/recieved data.
I am fairly new to jQuery, and I was wondering if there is any kind of "template" for handling these things, concretely for waiting until the function returns value and then proceeding with next operations.
So far I have tried using deferred and promises, and read quite a lot tutorials and stackoverflow answers on similar subjects, but I can't get it to work properly.
Or, if deferred and promises are the right way to go, could you show me the way it is supposed to be done?
Thanks in advance
'use strict';
function Eventful(_name) {
var name = _name;
var appKey = 'appKey';
var that = this;
return {
getName: function() {
return name;
},
getAppKey: function() {
return appKey;
},
search: function() {
that.searchanje(appKey).then(function(oData) {
console.log('oData');
});
}
};
}
Eventful.prototype.searchanje = function(appKey) {
var oArgs = {
app_key: appKey,
q: 'sport',
where: 'Zagreb',
date: '2013061000-2015062000',
page_size: 5,
sort_order: 'popularity',
};
EVDB.API.call('/events/search', oArgs, function(oData) {
console.log(oData);
return oData();
});
};
On the line
EVDB.API.call('/events/search', oArgs, function(oData) {
you are passing a CALLBACK function. This function (the one that starts function(oData)) is not executed immediately. It is executed asynchronously, when the result of your API call is returned.
Try putting console.log() statements around your code, and watch the order they appear in the console. For example:
function Eventful(_name) {
var name = _name;
var appKey = 'appKey';
var that = this;
return {
getName: function() {
return name;
},
getAppKey: function() {
return appKey;
},
search: function() {
console.log('Search function called');
that.searchanje(appKey).then(function(oData) {
console.log('searchanje returned with data:');
console.log('oData');
});
}
};
}
Eventful.prototype.searchanje = function(appKey) {
console.log('function searchanje being called with appKey: ', appKey);
var oArgs = {
app_key: appKey,
q: 'sport',
where: 'Zagreb',
date: '2013061000-2015062000',
page_size: 5,
sort_order: 'popularity',
};
console.log('Calling EVDB.API.call');
EVDB.API.call('/events/search', oArgs, function(oData) {
console.log('EVDB.API callback executing with data:');
console.log(oData);
return oData();
});
console.log('finished calling EVDB.API.call');
};
I wonder if a better way ahead might be to "promisify" EVDB.API.call().
(function(app_key) {
var appKeyObj = { 'app_key': app_key },
EVDB.API.callAsync = function(path, params) {
return $.Deferred(function(dfrd) {
EVDB.API.call(path, $.extend(appKeyObj, params), function(oData) {
if (oData.error === "1") {
//translate oData.status and oData.description into a javascript Error object
// with standard .name and .message properties.
err = new Error(oData.description);
err.name = oData.status;
dfrd.reject(err);
} else {
dfrd.resolve(oData);
}
});
});
});
})('myAppKey'); //hard-coded app key
Notes:
The global namespace is avoided by :
using a self-executing anonymous wrapper
extending the EVDB.API namespace.
The "Async" suffix for a promisified method has a precendent in bluebird
From the little I understand of EVDB.API, EVDB.API.call() does just about everything, hence the single method EVDB.API.callAsync(). If necessary, further async methods could be added to EVDB.API
You might choose to use a dedicated promise lib such as bluebird or when.js in place of jQuery, In addition to including the lib, mods to the above code would be minor.
Now, instead of calling EVDB.API.call(path, params, callback) you would call EVDB.API.callAsync(path, params) to be returned a Promise.
var params = {
//app_key will be inserted automatically
q: 'sport',
where: 'Zagreb',
date: '2013061000-2015062000',
page_size: 5,
sort_order: 'popularity'
};
EVDB.API.callAsync('/events/search', params).then(function(oData) {
console.log(oData);
}, function(err) {
console.error(err);
});

How to resolve my promise calls in my case

I was trying to reduce my promise objects in my service. I have something like
angular.module('myApp').service('testService', ['Employees','$q',
function(Employees, $q) {
var service = {};
var firstEmp;
var deferred = $q.defer();
Employees.query({
Id: 123
}, function(objects) {
firstEmp = objects[0];
deferred.resolve(objects);
})
service.getFirstEmployee = function() {
var deferredtwo = $q.defer();
// return deferredtwo.promise;
//How to solve the double promise defer in my case
//First promise is wait for the whole employees
//this one is to return first employee
deferred.promise.then(function(){
deferredtwo.resolve(firstEmp);
})
return deferredtwo.promise;
}
return service;
]);
Controller
testService.getFirstEmployee.then(function(firstEmployee){
console.log(firstEmployee) <---show first employee
})
I am not sure how to resolve the double promise objects. Can anyone help me? Thanks a lot!
If your ultimate objective is just to get the first employee, then you don't need all this "double promise" stuff at all. Just resolve one promise with the first employee:
angular.module('myApp').service('testService', ['Employees','$q',
function(Employees, $q) {
var pFirstEmployee = $q(function (resolve) {
Employees.query({ Id: 123 }, function(objects) {
resolve(objects[0]);
});
});
return {
getFirstEmployee: function() {
return pFirstEmployee;
}
};
}
]);
If you want two methods - one that returns a promise for all employees returned from the query, and another that returns just the first one from that set, just create a promise for all the employees and chain off of that:
angular.module('myApp').service('testService', ['Employees','$q',
function(Employees, $q) {
var pAllEmployees = $q(function (resolve) {
Employees.query({ Id: 123 }, resolve);
}),
pFirstEmployee = pAllEmployees.then(function (employees) {
return employees[0];
});
return {
getAllEmployees: function() {
return pAllEmployees;
},
getFirstEmployee: function() {
return pFirstEmployee;
}
};
}
]);
After the clarification I guess this is what you want:
angular.module('myApp').service('testService', ['Employees','$q',
function(Employees, $q) {
var service = {};
var deferred = $q.defer();
Employees.query({Id: 123}, function(objects) {
firstEmp = objects[0];
deferred.resolve(objects);
});
service.getFirstEmployee = function() {
return deferred.promise.then(function(employees){
return employees[0];
});
}
return service;
]);

Categories

Resources