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);
});
Related
I am trying to call service method in Angularjs. The service method is called alright, however IT DOES not return any value to the function that called it in the controller.
I will be glad if anyone can help me. This is my Code bellow.
logosStreams.factory("processPaypal", ['$http', '$timeout', '$q', '$state',function($http, $timeout, $q, $state){
var transCall = {};
var transcallPromise2 = $q.defer();
return {
onSuccesfulPayment: function(payment) {
console.log("payment success: " + JSON.stringify(payment, null, 4));
transcallPromise2.resolve(payment);
},
onAuthorizationCallback: function(authorization) {
console.log("authorization: " + JSON.stringify(authorization, null, 4));
//return authorization;
},
createPayment: function(data) {
// for simplicity use predefined amount
var paymentDetails = new PayPalPaymentDetails("0", "0", "0");
var payment = new PayPalPayment(data.amt, "USD", data.name, "Sale",
paymentDetails);
return payment;
},
buyInFutureBtn : function(e) {
// future payment
PayPalMobile.renderFuturePaymentUI(this.onAuthorizationCallback, this.onUserCanceled);
},
profileSharingBtn : function(e) {
// profile sharing
PayPalMobile.renderProfileSharingUI(["profile", "email", "phone","address", "futurepayments", "paypalattributes"],
this.onAuthorizationCallback, this.onUserCanceled);
},
buyNowBtn : function(data) {
// single payment
PayPalMobile.renderSinglePaymentUI(this.createPayment(data), this.onSuccesfulPayment, this.onUserCanceled);
return transcallPromise2.promise;
},
onPrepareRender: function() {
},
onUserCanceled: function(result) {
console.log(result);
transcallPromise2.reject(result);
}
}
}])
Inside the controller call the buyNowBtn methond
processPaypal.buyNowBtn($scope.MMParams).then(function(response){
console.log(response);
})
One of the possible reason that it does not return value is that your promise is not resolved. Your promise will only be resolved when you call onSuccessfulPayment().
Can you also put the code where your onSuccessfulPayment() function is executed.
You have returned the promise object on the buyNow function execution...try to return the promise as part of the returned object where you have returned all the function hookups.
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.
I'm trying to replicate a couchDB like system.
My backend is Parse server and my frontend is Ionic (1)
What i'm trying to achieve is to fasten my application with localstorage.
Currently:
GetUserAds
-> Has localstorage?
--> Yes
---> Return localstorage
--> No
---> Get database call
----> Return and put local
But what i really would like is the local return to fetch the database in background and return that data as well if it's changed
This is because my application has many users and changes a lot.
Could i do something like this.
getUserAds(user).then(function(data) {
//Local data
}).then(function(dataDB) {
//Database updated data
})
You could use the notify callback provided on angular promises:
function UserService($timeout, $q) {
var users = ["user1", "user2"]; //localStorage.getItem('users');
function get() {
var deferred = $q.defer();
//call your backend here $http.get('....')
$timeout(function() {
//if(remoteUsers !== users) {
deferred.resolve({local: false, users: users.concat('user3')});
//}
}, 3000);
$timeout(function() {
if(users) {
deferred.notify({local: true, users: users});
}
}, 100)
return deferred.promise;
}
return {
get: get
};
}
and in your controller
function MyCtrl($scope, $users) {
$scope.name = 'Superhero';
$scope.myUsers = [];
$users.get()
.then(setUsers, null, setUsers);
function setUsers(users) {
$scope.myUsers = users;
}
}
Here you can see a little jsfiddle: http://jsfiddle.net/Lvc0u55v/1596/
You can do that if you use this service from the Angular API:
Angular Promises.
This is how I would do it:
getUserAds(user).then(function(response) {
// useMyData
});
function getUserAds {
if( thereIsLocalData ) {
return getLocalData(); // this returns a $q promise
} else {
return getDataDB() // Here I'm returning an $http Promise
}
}
function getDataDB (params) {
return $http.get(host, params, {}); // I'm returning the $http Promise!
}
function getLocalData (params) {
return $q(function(resolve, reject) {
resolve(myLocalData);
}); // return the $q promise!
}
This way you are using local communications the same way as Online communications and you can simplify your logic.
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;
I am unable to wrap my brain around the concept of asynchronous requests.
I have a controller for my view, which is creating an object instance from a provider:
va.controller('VaCtrl',function($scope,$shipment){
$scope.shipment = $shipment.Shipment();
});
The provider:
Shipment.provider('$shipment',function(){
this.$get = function($http){
function Shipment(){
}
Shipment.prototype.fetchShipment = function(){
var shipment = undefined;
$http.post('../sys/core/fetchShipment.php',{
// some data to POST
}).then(function(promise){
shipment = promise.data;
});
return shipment;
};
return {
Shipment: function(){
return new Shipment();
}
}
}
});
My goal is to get access to the data from Shipment.prototype.fetchShipment() inside my controller. My approach:
$scope.fetchShipment = function(){
var shipment = $scope.shipment.fetchShipment();
console.log(shipment); // undefined
};
However, this will return undefined.
I read about $q, and defers, promises and callbacks, and now i am like WTF; all i want to do is to push the retrieved data to my controller, what is the best possible way to do so?
You should modify your code as shown below to return the promise from fetchshipment directly, and then use then() inside your controller.
Shipment.prototype.fetchShipment = function(){
return $http.post('../sys/core/fetchShipment.php',{
// some data to POST
})
};
$scope.fetchShipment = function(){
var shipment = $scope.shipment.fetchShipment().then(function(data){;
console.log(data);
});
};
Explanation to Code :
Calling $http return a promise which is resolved when you get the data from the server. In the code above, I have returned $http.post from service function which returns a promise. So in the controller you are waiting for promise to be resolved, and when the promise is resolved, the result is logged to the console.
Read about more promise documentation on angular:
http://docs.angularjs.org/api/ng.$q
http://docs.angularjs.org/api/ng.$http
Just the give you an example how to get your example working with your own promise.
It's much more simple if you use $http builtin promise, so it's an $q-example:
angular.module('myApp', []).controller("myAppCtrl", function ($scope, $shipment) {
$shipment.Shipment().fetchShipment().then(function (shipment) {
$scope.shipment = shipment
});
}).provider('$shipment', function () {
this.$get = function ($http, $q) {
function Shipment() {
}
Shipment.prototype.fetchShipment = function () {
var defered = $q.defer();
demodata = {name: "jan", id:8282};
$http.post('/echo/json/', 'json=' + encodeURIComponent(angular.toJson(demodata)), {
headers: {
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
}
}).then(function (response) {
//resolve promise
defered.resolve(response.data);
});
return defered.promise;
};
return {
Shipment: function () {
return new Shipment();
}
}
}
});
<div ng-controller="myAppCtrl">{{shipment}}</div>
JSFiddle (use JSFiddle echo-service as data provider):
http://jsfiddle.net/alfrescian/ayke2/
More about promises:
http://blog.parse.com/2013/01/29/whats-so-great-about-javascript-promises/
http://www.egghead.io/video/o84ryzNp36Q
AngularJS : Where to use promises?
stackoverflow.com/questions/15604196/… egghead.io/video/o84ryzNp36Q