Angularjs $q is Not Returning Promise - javascript

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.

Related

How to pass param from controller to service in AngularJs

I'm currently working on a project to help me better understand angularjs! I am currently stuck on how to pass a parameter from the controller to service.
In my program, I have created a function called "GetForecastByLocation" when a user types in an input clicks on a button. From there I want to take their input and then pass it to the http call in service.js.
Originally, $http.get was in a long giant string of the API url, but I googled around and it seems that I'm supposed to use parameters when trying to change a portion of the string. As of right now, I know parameter is hardcoded to a specific city, but I want to take new input and pass the value of vm.city to the $http.get call.
If any one can help I would greatly appreciate it. Thank you!
controller.js
var app = angular.module('weatherApp.controllers', [])
app.controller('weatherCtrl', ['$scope','Data',
function($scope, Data) {
$scope.getForecastByLocation = function(myName) {
$scope.city = myName;
Data.getApps($scope.city);},
Data.getApps(city)
.then(function(data)){
//doing a bunch of things like converting units, etc
},
function(res){
if(res.status === 500) {
// server error, alert user somehow
} else {
// probably deal with these errors differently
}
}); // end of function
}]) // end of controller
service.js
.factory('Data', function($http, $q) {
var data = [],
lastRequestFailed = true,
promise;
return {
getApps: function() {
if(!promise || lastRequestFailed) {
promise = $http.get('http://api.openweathermap.org/data/2.5/weather?',{
params: {
q: Tokyo,
}
})
.then(function(res) {
lastRequestFailed = false;
data = res.data;
return data;
}, function(res) {
return $q.reject(res);
});
}
return promise;
}
}
});
Passing arguments to a factory method is no different than passing arguments to a plain old function.
First, set up getApps to accept a parameter:
.factory('Data', function($http, $q){
// ...
return {
getApps: function(city){
promise = $http.get(URL, {
params: {q: city}
}).then( /* ... */ );
// ...
return promise;
}
};
});
Then pass it your argument:
$scope.getForecastByLocation = function(myName) {
$scope.city = myName;
Data.getApps($scope.city);
}
It's just like setting a value to a function's context variable.
Services.js
Simple example of a service.
.factory('RouteService', function() {
var route = {}; // $Object
var setRoute_ = function(obj)
{
return route = obj;
};
var getRoute_ = function()
{
if(typeof route == 'string')
{
return JSON.parse(route);
}
return null;
};
return {
setRoute: setRoute_,
getRoute: getRoute_
};
})
Controllers.js
Simple example of Service usage:
.controller('RoutesCtrl', function ($scope, RouteService) {
// This is only the set part.
var route = {
'some_key': 'some_value'
};
RouteService.setRoute(route);
})

angularJS closure causes $HTTP.get to not return my array of JSON objects

I have the following 3 methods in my module.factory dataservice I am using Angular 1.5
getCannedJSON . This function works as intended and i would like the others to behave the same way. I copy and pasted the JSON i got from my webAPI in postman and put this in to the function. It returns an array of objects like i want.
getDataFromAPI. For some reason I cannot get this function to return the response. The console.log(response) has exactly the data I want aka the same data as getCannedJSON. Instead it returns a d {$$State: object} any idea how i could alter this code to change have it return in the same format as the getCannedJson method?
getDataFromApiWithDynamicUrl this is no different than the above method but it will take a dyanmic url for the web api. It workds fine minus it not returning an array list of json objects it instead returns the same $$State object.
I would like getDataFromAPI to return the same array of all the objects in the json request like getCannedJson does. Any ideas where I am messing up. Below is a screenshot of the two different types of objects they are returning via console.log I would like the data at the bottom to look like the data at the top.
The code for the dataService module factory is below
(function (module) {
'use strict';
DataService.$inject = ['$http', '$q'];
function DataService($http, $q) {
var getDataFromAPI = function () {
var returnthis;
return $http({ //this top level returns instead
url: "http://localhost:34183/api/quality/month",
dataType: 'json',
method: 'GET',
}).success(function (response) {
console.log("This Response shown below is pefect! but it wont return....");
console.log(response);
return (response);//This never returns
}).error(function(error){
console.log(error);
});
return returnthis;
};
var getDataFromApiWithDynamicUrl = function (pathurl) { // this is version 2 of the method i want to work where i can dynamically change the url to the path
return $http.get(pathurl);
};
var getCannedJSON = function ($http) {
return [{
"hockeyTeam": "Sharks",
"PlayoffRecord": {
"wins": "0"
},
},
{
"hockeyTeam": "Pengiuns",
"PlayoffRecord": {
"wins": "1"
},
}
];
};
return {
getDataFromAPI: getDataFromAPI,
getDataFromApiWithDynamicUrl: getDataFromApiWithDynamicUrl,
getCannedJSON: getCannedJSON
};
}
module.factory('DataService', DataService);
})(angular.module('MyCoolModule'));
below is the code where i call these methods to consume the JSON data in my controller.
(function (module) {
'use strict';
hockeyViewController.$inject = ['DataService'];
function hockeyViewController(DataService) {
var vm = this;
vm.headers = [
{ name: 'Hockey Team', key: 'hockeyTeam' },
{ name: 'Record', key: 'PlayoffRecord'}
];
vm.cannedData = angular.copy(DataService.getCannedJSON());
vm.getDataFromAPI = DataService.getDataFromAPI();
vm.getDataFromAPIwithCustomURL = [];
DataService.getDataFromApiWithDynamicUrl("http://localhost:34183/api/quality/month").then(function(response){
console.log("this response should work - and it does it in the right format");
console.log(response.data);// this looks perfect
vm.getDataFromAPIwithCustomURL = response.data;
return response.data;
}, function (error) {
console.log(error);
});
vm.testMonthResults2 = angular.copy(DataService.getDataFromApiWithDynamicUrl("http://localhost:34183/api/quality/month"));
console.log("canned json Data- works great");
console.log(vm.cannedData);// this works perfectly
console.log("this is the data results with dynamic url - returns wrong object the $$state ");
console.log(vm.getDataFromAPI);// returns $$state not array of objects
console.log(vm.getDataFromAPIwithCustomURL); // this returns [] which is wrong
console.log(DataService.getDataFromApiWithDynamicUrl("http://localhost:34183/api/quality/month"));
// this doesnt work either
}
function reportTabularViewDirective() {
return {
restrict: "E",
controller: hockeyViewController,
controllerAs: 'vm',
bindToController: true,
scope: {
},
templateUrl: "app/widgets/hockey-view.html"
};
}
module.directive('hockeyView', hockeyViewDirective);
})(angular.module('MyCoolModule'));
Can try this one
var getDataFromAPI = function () {
return $http({
url: "/api/quality/month", // try using relative path
dataType: 'json',
method: 'GET',
}).then(function(response) {
console.log(response);
return respose.data;
}, function(error) {
console.log(error);
return [];
});
};
But better to use like: service return only promise and in controller use then function to handle response
In service:
var getDataFromAPI = function() {
return $http.get('/api/quality/month');
};
in controller:
DataService.getDataFromAPI().then(function(response) {
console.log(response.data);
}, function(error) {
console.log(error);
});
You get a $promise object by calling DataService.getDataFromAPI(). You need to handle the $promise object to get the response.
DataService.getDataFromAPI().then(function(response) {
// console.log(response);
})
The same applies when you getDataFromApiWithDynamicUrl() function.
For more info, see doc:
$http
$q

How to make a simulated sync AJAX call in AngularJS?

I have this script in my app.js:
app.run(['$http', '$location', 'myAppConfig', function ($http, $location, myAppConfig) {
if (myAppConfig.webAPIPath.main == '') {
var getconfigDone = false;
$http.get('fileHandler.ashx?action=getconfig')
.then(function (result) {
if (JSON.parse(result.data.Data).APIURL !== undefined && JSON.parse(result.data.Data).APIURL != '') {
var apiURL = JSON.parse(result.data.Data).APIURL;
if (apiURL.lastIndexOf('/') + 1 == apiURL.length) {
apiURL = apiURL.substring(0, apiURL.lastIndexOf('/'))
}
myAppConfig.webAPIPath.main = apiURL + "/";
myAppConfig.webAPIPath.account = myAppConfig.webAPIPath.main + '/api/OnlineApplicationPortal/v1/Account/';
myAppConfig.webAPIPath.dashboard = myAppConfig.webAPIPath.main + '/OnlineApplicationPortal/v1/Dashboard/';
}
else {
$location.path('Action/Welcome/apiUrlError');
}
//debugger
getconfigDone = true;
}, function (response) { debugger }
);
}
}]);
Also I have got this factory object which uses the myAppConfig in app.js:
(function () {
angular
.module('app.data')
.factory('accountDS', ['$http', '$routeParams', 'myAppConfig', function ($http, $routeParams, myAppConfig) {
var pathPrefix = myAppConfig.webAPIPath.account;
var createAccount = function (account, email) {
var OnlineApplicationPortalModel = {
Name: account.firstName,
Surname: account.lastName,
Email: email,
Password: account.password
};
return $http.post(pathPrefix + 'CreateAccount', OnlineApplicationPortalModel)
.then(function (response) {
return response;
});
};
var confirmEmail = function () {
var data = {
guid: $routeParams.guid
};
return $http.post(pathPrefix + 'ConfirmEmail', data)
.then(function (response) {
return response;
});
}
return {
createAccount: createAccount,
confirmEmail: confirmEmail
};
}]);
})();
The service object needs to use myAppConfig.webAPIPath.account which is resolved in the function in app.js run function. Now the problem is sometimes the browser reaches the service code sooner than than the AJAX call is returned, a race condition. I know that it is not possible in AngularJS to make a sync AJAX call. So how can I solve this?
If I correctly understand you, you want to myAppConfig.webAPIPath.account resolve this value to use it later in your code, but ajax call which provides you value for this variable is not always called before assignment. I think you could use https://docs.angularjs.org/api/ng/service/$q to solve your problem. Your code in myAppConfig should be inside function, so you can call it inside your factory and return deferred object, which then when your .account variable is set should call code from accountDS factory.

how to retrieve data by id with angularfire

i used a tutorial to create a angularfire chat app. it is a standalone app that uses ui-router. I integrated it succssfully as a view in my app but that is not practical. I need to be able to use the chat on any view I am at. I am stuck at moving a resolve function to a controller. I have read some docs and I believe it is returning a promise that I need to resolve in the controller. the link to the tutorial is here.
tutorial
here is the ui-router I am trying to get away from
.state('channels.direct', {
url: '/{uid}/messages/direct',
templateUrl: 'views/chat/_message.html',
controller: 'MessageController',
controllerAs: 'messageCtrl',
resolve: {
messages: function ($stateParams, MessageService, profile) {
return MessageService.forUsers($stateParams.uid, profile.$id).$loaded();
},
channelName: function ($stateParams, UserService) {
return UserService.all.$loaded().then(function () {
return '#' + UserService.getDisplayName($stateParams.uid);
});
}
}
})
The message service
var channelMessagesRef = new Firebase(AppConstant.FirebaseUrl + 'channelMessages');
var userMessagesRef = new Firebase(AppConstant.FirebaseUrl + 'userMessages')
return {
forChannel: function (channelId) {
return $firebaseArray(channelMessagesRef.child(channelId));
},
forUsers: function (uid1, uid2) {
var path = uid1 < uid2 ? uid1 + '/' + uid2 : uid2 + '/' + uid1;
return $firebaseArray(userMessagesRef.child(path));
}
};
the user service
var usersRef = new Firebase(AppConstant.FirebaseUrl + 'users');
var connectedRef = new Firebase(AppConstant.FirebaseUrl + '.info/connected');
var users = $firebaseArray(usersRef);
return {
setOnline: function (uid) {
var connected = $firebaseObject(connectedRef);
var online = $firebaseArray(usersRef.child(uid + '/online'));
connected.$watch(function () {
if (connected.$value === true) {
online.$add(true).then(function (connectedRef) {
connectedRef.onDisconnect().remove();
});
}
});
},
getGravatar: function (uid) {
return '//www.gravatar.com/avatar/' + users.$getRecord(uid).emailHash;
},
getProfile: function (uid) {
return $firebaseObject(usersRef.child(uid));
},
getDisplayName: function (uid) {
return users.$getRecord(uid).displayName;
},
all: users
};
here is what I have so far in the controller
$scope.directMessage = function (uid) {
UserService.all.$loaded().then(function () {
$scope.selectedChatUser = '#' + UserService.getDisplayName(uid);
});
$scope.selectedChatUserMessages = MessageService.forUsers(uid, profile.$id).$loaded();
};
I am returning the
$scope.selectedChatUser
fine. the issue is with the Message Service
this is the what i am currently returning from the message service
$$state: Object
__proto__: Promise
how do i resolve this?
You're trying to return from inside a promise in your channelName function.
The object you're getting back is an unresolved promise. You want the resolved data from the promise injected into your controller.
You need to create a to return from this function.
.state('channels.direct', {
url: '/{uid}/messages/direct',
templateUrl: 'views/chat/_message.html',
controller: 'MessageController',
controllerAs: 'messageCtrl',
resolve: {
messages: function ($stateParams, MessageService, profile) {
return MessageService.forUsers($stateParams.uid, profile.$id).$loaded();
},
channelName: function ($stateParams, UserService, $q) {
// create a deferred for this function
var deferred = $q.defer();
// load async data with UserService.all's promise
UserService.all.$loaded()
.then(function () {
var name = UserService.getDisplayName($stateParams.uid);
deferred.resolve(name);
});
// return promise
return deferred.promise;
}
}
})
However in getDisplayName I would just recommend returning back the object rather than just the name, as the entire set is synchronized by Firebase.

AngularJS: Working with callbacks and promises

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

Categories