promisses inside loop in npm Q - javascript

I am implementing a code to save all tags to db. I am rejecting the promise if even 1 error is caught. Below code for reference.
module.exports = {
save_tag: function(tag, id) {
//Some logic to validate a tag goes here
return db.save(tag,id); //db.save is a promise;
},
save_tags: function(tags, post_id) {
var def = Q.defer();
_.forEach(tags, function(tag, key) {
self.save_tag(tag, post_id).then(null, def.reject);
});
return def.promise;
}
};
I would like to know how can I resolve the promise in save_tags function if all tags are saved successfully in save_tag function.
I am using npm Q library.

module.exports = {
save_tag: function(tag, id) {
return db.save(tag,id); // db.save is a promise;
},
save_tags: function(tags, post_id) {
var savedTags = _.map(tags, function(tag) {
return self.save_tag(tag, post_id);
});
return Q.all(savedTags);
}
};
https://github.com/kriskowal/q/wiki/API-Reference#promiseall

self.save_tag(tag, post_id).then(function _returnOK(){
//def.resolve();
}).fail(function _returnFail(){
//def.reject();
});
I think it will resolve.

Related

Jasmine - How do I mock a finally call?

I have a test that creates a controller like such...
this.createScope = function(scope) {
if (scope) {
this.scope = scope;
} else {
this.scope = $rootScope.$new();
}
this.controller = $controller("menuController", {
"$scope": this.scope,
updateActionList: function() {
return {
finally: function() {}
};
}
});
};
I added this part...
updateActionList: function() {
return {
finally: function() {}
};
}
Because when I run my tests, all of them fail because....
TypeError: undefined is not an object (evaluating 'updateActionList().finally')
updateActionList() is a local function that is called in the actual code like this...
updateActionList().finally(function() {
//Do stuff
});
updateActionList() returns a promise from getThings() with a .then and a .finally blocks.
I just want the finally block to resolve itself really so the tests can pass.
Or is there some other thing I need to do? I'm not sure why the finally is undefined.
So this call...
updateActionList().finally(function() {
//Do stuff
});
returns a promise from some other function, essentially my problem was that the function returning the promise before updateActionList() mock needed another finally call.
this.getThings = jasmine.createSpy("getThings").and.returnValue({
then: function(cb) {
cb(self.mockPlugins);
return {
finally: function(cb) {
cb();
return {
finally: function(cb) {
cb();
}
};
}
};
}
});

Error in Returning Promise ,Getting Error as .then is not a function in Angular JS

I am getting the error as modifyProduct.then is not a function, I have read through some article and it says because I have not returned any promises, How I can achieve this, Can someone help me
Here I am calling modifyProduct inside executionFromCompany function and then I am using executionFromCompany inside the controller
var app = angular.module('myApp', ["chart.js"]);
app.factory('ProductsService', function($http) {
function getProduct() {
return $http.get('finalmsodetails.json').then(function(response) {
//console.log(response.data);
return response.data;
});
}
function modifyProduct() {
return getProduct().then(function(rawData) {
newtest = rawData;
//console.log('test', newtest.length);
var lightData = rawData.map(function(item) {
// use Object.assign to prevent mutating original object
var newItem = Object.assign({}, item);
var lightExecutions = item.executions.map(function(d) {
var ld = {
id: d.id,
orderId: d.orderId,
executionStatus: d.executionStatus,
executedOn: d.executedOn,
executedBy: d.executedBy,
executedByDisplay: d.executedByDisplay,
};
return ld;
});
newItem.executions = lightExecutions;
return newItem;
});
return lightData;
});
}
function executionFromCompany() {
return modifyProduct.then(function(lightData) {
executionByCompany = $filter('filter')(lightData.executions, function(inputs) {
if ((inputs.executedBy == 'a')) return inputs;
});
console.log(executionByCompany);
return executionByCompany;
});
}
return {
getProduct: getProduct,
modifyProduct: modifyProduct,
executionFromCompany: executionFromCompany
};
});
app.controller('MainCtrl', function($scope, ProductsService) {
ProductsService.executionFromCompany().then(function(value) {
console.log(value);
}, function(err) {
// Here will be if there was an error
})
});
modifyProduct is a function, not an object
change this
modifyProduct.then
to this
modifyProduct().then

PushService.initPush.then is not a function

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);
});

Unit testing Angular filter which relies on service

I'm attempting to test a custom filter I've built. The issue I'm running into is that this filter relies on an asynchronous call through a service. Below is my relevant filter code first, then my current test:
.filter('formatValue', ['serverService', '_', function(serverService, _) {
var available = null;
var serviceInvoked = false;
function formatValue(value, code) {
var details = _.findWhere(available, {code: code});
if (details) {
return details.unitSymbol + parts.join('.');
} else {
return value;
}
}
getAvailable.$stateful = true;
function getAvailable(value, code) {
if (available === null) {
if (!serviceInvoked) {
serviceInvoked = true;
serverService.getAvailable().$promise.then(function(data) {
available = data;
});
}
} else {
return formatValue(value, code);
}
}
return getAvailable;
}])
test:
describe('filters', function() {
beforeEach(function() {
module('underscore');
module('gameApp.filters');
});
beforeEach(module(function($provide) {
$provide.factory('serverService', function() {
var getAvailable = function() {
return {
// mock object here
};
};
return {
getAvailable: getAvailable
};
});
}));
describe('formatValue', function() {
it('should format values', inject(function(formatValueFilter) {
expect(formatValueFilter(1000, 'ABC')).toEqual('å1000');
}));
});
});
The error I'm encountering when running my tests is:
TypeError: 'undefined' is not an object (evaluating 'serverService.getAvailable().$promise.then')
Your mock service needs to return a resolved promise. You can do this by injecting $q and returning $q.when(data)
However, I would think about refactoring this filter first. Filters are intended to be fast computations and probably should not be dependent on an asynchronous call. I would suggest moving your http call to a controller, then pass in the data needed to the filter.

Order function call

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;

Categories