I need to make submitAdapterAuthentication() function to work the first getUserRoles() function, but with the current implementation of the getUserRoles() function is being executed first that submitAdapterAuthentication(). How can I fix this?
checkOnline().then(function(onl) {
userObj.isLoginOnline = onl;
}).then(function() {
submitAdapterAuthentication(user, pass);
}).then(function() {
getUserRoles();
});
function submitAdapterAuthentication(user, pass) {
var invocationData = {
parameters : [ user, pass ],
adapter : "adapterAuth",
procedure : "submitLogin"
};
ch.submitAdapterAuthentication(invocationData, {
onFailure : function(error) {
WL.Logger.log("ERROR ON FAIL: ", error);
},
onSuccess : function() {
WL.Client.updateUserInfo({
onSuccess : function() {
//return promise
WL.Client.updateUserInfo({
onSuccess : function() {
}
});
}
});
}
});
}
// my function to obtain roles
// It should be performed after submitAdapterAuthentication
function getUserRoles(){
var arrayRoles = [];
var attributes = WL.Client.getUserInfo(realm, "attributes");
if(attributes){
if(attributes.roles){
arrayRoles.push(attributes.roles);
}
}
}
When chaining promises, if you return anything but another promise from a then() callback, the resulting promise will be resolved immediately with the value undefined.
In order to make sure your callbacks are executed in the order you specified, just make sure each callback is returning a promise at the end. If you want to return some value from a callback, wrap it in a $q.when(). In this case it looks like you are not using any intermediary return values, so you can just wrap any arbitrary value in a $q.when() to make sure a promise is returned:
checkOnline().then(function(onl) {
userObj.isLoginOnline = onl;
return $q.when(true);
}).then(function() {
submitAdapterAuthentication(user, pass);
return $q.when(true);
}).then(function() {getUserRoles();});
Based on your latest edit, it looks like ch.submitAdapterAuthentication() is likely returning a promise. If this is the case, you should return this promise from the function:
return ch.submitAdapterAuthentication(invocationData, {...
And then return this promise in the then callback:
then(function() {return submitAdapterAuthentication(user, pass);})
If ch.submitAdapterAuthentication() does not return a $q promise, you will have to wrap it yourself:
var deferred = $q.defer();
ch.submitAdapterAuthentication(invocationData, {
onFailure : function(error) {
WL.Logger.log("ERROR ON FAIL: ", error);
deferred.reject(error);
},
onSuccess : function() {
WL.Client.updateUserInfo({
onSuccess : function() {
deferred.resolve();
}
});
}
});
return deferred.promise;
Related
I am trying to have a service return a promise, but keep getting PushService.initPush.then is not a function
Here is my service:
app.service('PushService', function($log, $q, $ionicPopup) {
return {
initPush: function() {
var deferred = $q.defer();
MFPPush.initialize (
function(successResponse) {
console.log("Successfully intialized push: " + successResponse);
deferred.resolve();
},
function(failureResponse) {
console.log("Failed to init push: " + JSON.stringify(failureResponse));
deferred.resolve();
}
)
return deferred;
}
}
}
And my controller:
PushService.initPush.then(function(response) {
console.log(response);
})
But am getting PushService.initPush.then is not a function why does this keep happening, to me it looks like I am returning a promise? I have been following this tutorial http://chariotsolutions.com/blog/post/angularjs-corner-using-promises-q-handle-asynchronous-calls/ and looked at this SO question Processing $http response in service but cant get it to work.
Thanks for the help
First, you need to call initPush method, not just access its property.
Second, in $q there's a not-so-subtle difference between deferred and promise APIs: the former is about modifying its state, and the second is about deciding what to do when it's settled (resolved or rejected). So you actually need to return deferred.promise (instead of deferred).
Finally, I'd recommend using $q constructor pattern instead, like shown in the doc:
initPush: function() {
return $q(function(resolve, reject) {
MFPPush.initialize(
function(successResponse) {
console.log("Successfully intialized push: " + successResponse);
resolve(successResponse);
},
function(failureResponse) {
console.log("Failed to init push: " + JSON.stringify(failureResponse));
reject(failureResponse);
}
);
});
}
As a matter of fact, if you don't need logging here, you can write it out as simple as ...
return $q(function(resolve, reject) {
MFPPush.initialize(resolve, reject);
});
I've search for a sollution but I didn't find something like that.
I'm using angular, I want to call a function inside another function, and wait for its response.
the 2nd function is:
self.changeProvider = function() {
var contexec = false;
if (!checkIsFit()) {
contexec = true;
} else {
contexec = false;
}
if (contexec) {
var modalOptions = {
closeButtonText: $translate.instant('closeButtonText'),
actionButtonText: $translate.instant('ok'),
headerText: $translate.instant('changeProvidertitle'),
bodyTemplate: '../themes/default/src/app/shoppingCart/changeProvider/changeProvider.tpl.html',
margin: true
};
var modalDefaults = {
backdrop: 'static',
templateUrl: '../themes/default/src/app/shoppingCart/changeProvider/changeProvider.tpl.html',
controller: 'ChangeProviderCtrl',
size: 'sm',
resolve: {
modalData: function() {
return {
data: $scope.arrayToChangeProvider
};
}
}
};
modalService.showModal(modalDefaults, modalOptions)
.then(function(result) {
//some stuff
});
}
};
And the other function:
var checkIsFit = function() {
if ( $scope.cabstatus != 4 ) {
return false;
} else {
var modalOptions = {
closeButtonText: $translate.instant('closeButtonText'),
actionButtonText: $translate.instant('ok'),
headerText: $translate.instant('cabisfittedtitle'),
bodyTemplate: '../themes/default/src/app/shoppingCart/checkIsFit/checkIsFit.tpl.html',
margin: true
};
var modalDefaults = {
backdrop: 'static',
templateUrl: '../themes/default/src/app/shoppingCart/checkIsFit/checkIsFit.tpl.html',
controller: 'CheckIsFitCtrl',
size: 'sm',
resolve: {
modalData: function() {
return {
};
}
}
};
modalService.showModal(modalDefaults, modalOptions)
.then(function(result) {
if (result.msg === 'ok') {
var params = {
token: $scope.token,
fkidpedido: $scope.pendingOrderLineList[0].FK_IDPEDIDO,
userid : $scope.userid
};
shoppingCartService.postResetAgr(params, function() {
return true;
}, function() {
/*Notification.error({
message: $translate.instant('components.activity.actions.deleteActivityError')
});*/
});
return false;
} else {
return true;
}
});
}
};
The problem is the function changeProvider still executing and opens the modal first to resolve the funcion checkIsFit()
I want to wait checkIsFit is resolved and then continue with the functions of changeProvider
I cannot include the checkIsFit() functionallity inside changeProvider because I want to use checkIsFit() into another functions.
Any help will be appreciate.
Thanks in advance
I believe what you're looking for are deferred objects and promises. Check out the documentation for $q:
https://docs.angularjs.org/api/ng/service/$q
I'd recommend giving this a good read because this is a really important and powerful concept for ANY Javascript developer.
At the essence, deferred objects and promises allow you run asynchronous processes and callback to a function when a process is complete.
The modalService.showmodal method returns a promise. Create functions that return those promises.
var modalPromise1Fn = function () {
var promise1 =
modalService.showModal(modalDefaults1, modalOptions2)
.then(function(result) {
//some stuff
});
return promise1;
};
var modalPromise2Fn = function () {
var promise2 =
modalService.showModal(modalDefaults2, modalOptions2)
.then(function(result) {
//some stuff
});
return promise2;
};
This use the .then method of the first promise to chain the second promise.
var derivedPromise =
modalPromise1Fn().then( function() {
var promise2 = modalPromise2Fn();
//return to chain the second promise
return promise2;
});
From the Docs:
Chaining promises
Because calling the .then method of a promise returns a new derived promise, it is easily possible to create a chain of promises.
It is possible to create chains of any length and since a promise can be resolved with another promise (which will defer its resolution further), it is possible to pause/defer resolution of the promises at any point in the chain. This makes it possible to implement powerful APIs .
-- AngularJS $q Service API Reference -- Chaining Promises
I am using Angular resourse to get my data from an API, in this way:
var getAccountListPerUser = function () {
return $resource(uri, {}, {
get: {
headers: service.getDefaultHeaderRequest(),
method: 'GET',
transformResponse: function (data) {
var accountList = [];
try {
accountList = JSON.parse(data);
} catch (e) {
accountList = [];
}
return accountList;
},
isArray: true,
cache: true
}
}).get().$promise;
};
In my controller I have to use it and another two service functions defined in the same way.
var promiseResourcesAccountList = usrWebUserService.getAccountListPerUser();
promiseResourcesAccountList.then(function(result){
$scope.usersWithAccountsAndProfiles = result;
var filteredProfiles = [];
for (var account in result) {
...
}
$scope.filteredProfiles = filteredProfiles;
});
And:
var promiseResourcesEditUser = usrWebUserService.getResourcesUser(currentUser);
promiseResourcesEditUser.then(function (result) {
usrWebUserFactory.mapBasicPreferences($scope, result);
});
And then another very similar, this information loads data in three divs, but I want to show them only when all the three functions have completed correctly. I think I have to chain the result of the promises. How can I do that?
You can chain them like:
promiseResourcesAccountList.then(function(result){
///whatever processing
//return a promise
return promiseResourcesEditUser()
}).then(function(){
return anotherPromise();
}).then(function(){
//update scope here
});
alternatively, you could also use $q.all([promise1, promise2, promise3]).then(...);
#terpinmd is correct. Chaining promises is pretty simple. Say you have a service with a "getWidgets" that returns a promise, and you want to use the response from that service to call another service, "getWidgetOwners" that will return another promise :
Assumptions
getWidgets returns an array of widget objects.
getWidgetOwners accepts an array of ownerIds
How To:
service.getWidgets()
.then(function(widgets) {
return widgets.map(function(widget) { // extract ownerIds
return widget.ownerId;
});
})
.then(service.getWidgetOwners) // pass array of ownerId's to
.then(function(owners) { // the next service
console.log(owners);
});
I have an array of validation checks and one happens to be using ajax to check for an address. I needed the entire array to return true and fire sequentially before submitting a form. I tried using promises but to no avail.
Here's the issue. If I either enter an incorrect address or leave the input(s) blank then it doesn't submit the form (good). But when I actually enter a valid address the form submits despite the fact that my other validations in the validations array have false values. What am I doing wrong?
var validations = [validateInputPresence, validatePassword, validateAddress];
$continueButton.on('click', function() {
toggleSpinner();
subscribe().then(function() {
submitForm(); // This is firing even when some values are false in the array
}, function() {
toggleSpinner();
});
});
function subscribe() {
var promises = validations.map(function(validation) {
return validation();
});
return Promise.all(promises);
}
function validatePassword() {
var password = $password.val();
var format = /^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])[^+&\n]{8,}$/;
return validateInput(format.test(password));
}
function validateAddress() {
return new Promise(function (resolve, reject) {
$.ajax({
type: 'POST',
url: '/address/validate',
data: $form.serialize(),
dataType: 'json',
success: function(response) {
var hasValidAddres = response.Data === 200;
validateInput(hasValidAddres);
hasValidAddres ? resolve() : reject();
},
error: function() {
toggleSpinner();
}
});
});
}
function validateInput(validation) {
if (validation) {
return true;
} else {
return false;
}
}
The main problem is that you don't return the Promise in the validateInput() function. You can't reject a promise returned by Promise.all via returning a false in one of its function.
Read more about Promise.all, the quote below is taken from MDN
If something passed in the iterable array is not a promise, it's converted to one by Promise.resolve.
So actually anything, but Promise will be treated as being resolved.
What you should do is write the validateInput function to return a promise.
function validateInput(validation) {
return new Promise(function(resolve, reject) {
if (validation) {
resolve();
} else {
reject();
}
});
}
What am I doing wrong?
You've never tested whether the values in the array were true or false. You did most of the promise stuff correctly, and subscribe() returns a promise for an array of boolean values. If you want to test whether all of them are true, you will need to do that explicitly:
subscribe.then(function(results) {
if (results.every(Boolean)) // all are true
submitForm();
else // some are false
…;
}, function(err) {
// some validations threw an exception
});
I would like to perform the same action after a promise has either been fulfilled with a success result or failure, ie I want to perform the same action for the success and error handler and then continue to send down the result of the promise to the appropriate erroe/success handlers.
var pleaseWaitPromise = playAudioAsync("please wait");
myLongRunningPromise().then(function tempSuccessHandler(result) {
pleaseWaitPromise.cancel();
return result;
}, function tempErrorHandler(error) {
pleaseWaitPromise.cancel();
return WinJS.Promise.wrapError(error);
}).done(function realSuccessHandler(result) {
console.info(result);
}, function realError(error) {
console.error(error);
});
Is there a more elegant way to stop the pleaseWaitPromise, which could also be a function call instead of a promise (like clearInterval)
jfriend is right you'd typically want finally here - it does exactly what your code above does. Sadly WinJS promises do not feature .finally at the moment so unless you'd like to shim it (patching it on the prototype of WinJS.promise) you're stuck with it.
You can also put it as a function:
function always(prom, fn){
return prom.then(function(v){ fn(v); return v; },
function(e){ fn(e); return WinJS.Promise.wrapError(error); });
}
Which would look like:
always(myLongRunningPromise(),
pleaseWaitPromise.cancel();
})).done(function realSuccessHandler(result) {
console.info(result);
}, function realError(error) {
console.error(error);
});
Sorry, but I don't understand the extra step, wouldn't this just do what you want?
var pleaseWaitPromise = playAudioAsync("please wait");
myLongRunningPromise().then(function tempSuccessHandler(result) {
pleaseWaitPromise.cancel();
console.info(result);
}, function tempErrorHandler(error) {
pleaseWaitPromise.cancel();
console.error(error);
});
edit: second try
I know it is a known anti-pattern, but what if you return a Promise that never fails? Something like:
function neverFails(myLongRunningPromise, pleaseWaitPromise){
return new WinJS.Promise(function (complete){
myLongRunningPromise().then(function () {
pleaseWaitPromise.cancel();
console.info(result);
return complete();
}, function (error) {
pleaseWaitPromise.cancel();
console.error(error);
return complete();
});
});
}
Does that make sense?