Angular $q returning resolved promise - angularjs

I have a variable this.eligible which I would like to assign to the value of a returned promise instead of the actual promise object.
userService
this.eligible = this.sweepstakesService.checkUser(data);
sweepstakesService
checkUser({profileId}) {
var deferred = this.$q.defer();
var id = profileId.replace(/[{}]/g, "");
this.$q.when(this.getGuid(id)
.then(guid => this.determineEligibility(guid))
.catch(this.handleError))
.then(function(data){
deferred.resolve(data);
});
return deferred.promise;
}
getGuid(profileId){
return this.resourcesService.guid.save({id:profileId}).$promise.then(data => data.guid);
}
determineEligibility(response){
return this.resourcesService.eligibility.save({id:response}).$promise.then(data => data.isEligible);
}
handleError(response){
console.log(response);
}
Currently I'm returning Promise{$$state: Object} instead of the actual resolved value.

In order to access the result of a promise, you need to provide a callback to the then method on the promise object, which will be called asynchronously as soon as the result is available.
this.sweepstakesService.checkUser(data)
.then(function(value){
this.eligible = value;
});

When you're using promise, you're performing some asynchronous request, so you have to pass some callback function in order to retrieve your data, and wait for it.
You can use the $q.defer() promise manager, from the deferred API.
$q.defer() get 2 methods :
resolve(value) : which resolve our associated promise, by giving her the final value
reject(reason) : which resolve an promise error.
Don't forget that you are doing some asynchronous work...
Moreover, a good tips can be to save the current context into a variable, in order to bind your data.
Controller
(function(){
function Controller($scope, Service) {
//Save the current context of our controller
var self = this;
self.success = '';
self.fail = '';
//Declare our promise
var promise1 = Service.get(2);
var promise2 = Service.get(6);
promise1.then(function(response){
//Retrieve our response and set it to our success variable
//We use self as our Controller context
self.success = response;
}).catch(function(error){
self.success = error;
});
promise2.then(function(response){
self.fail = response;
}).catch(function(error){
//Retrieve our error and set it to our fail variable
self.fail = error;
});
}
angular
.module('app', [])
.controller('ctrl', Controller);
})();
Service
(function(){
function Service($http, $q) {
function get(n){
//using $q.defer() from deferred API
var defer = $q.defer();
//Simulate latency
setTimeout(function(){
n < 3
? defer.resolve(n)
: defer.reject('Error');
}, 1500);
//Return our promise
return defer.promise;
}
return {
get: get
}
}
angular
.module('app')
.factory('Service', Service);
})();
Then, you can instantiate your controller by using the controllerAs syntax.
HTML
<body ng-app='app' ng-controller='ctrl as self'>
<div>Success : {{self.success}}</div>
<div>Fail : {{self.fail}}</div>
</body>
You can see an example on this Working Plunker

Related

$http in angularjs does not work

I have a piece of Code in angularjs. If I hard code the value of http response it is displaying the response when I use the http method in angularjs it is not displaying. Whenever request sends to server i get error function. I dont know where I am wrong. Here is the code
(function() {
'use strict';
angular
.module('MyApp', ['ngMaterial', 'ngMessages', 'material.svgAssetsCache'])
.controller('DemoCtrl', DemoCtrl);
function DemoCtrl($timeout, $q, $log, $http, $scope) {
var self = this;
self.simulateQuery = false;
self.isDisabled = false;
self.repos = loadAll();
self.querySearch = querySearch;
self.selectedItemChange = selectedItemChange;
self.searchTextChange = searchTextChange;
function querySearch(query) {
var results = query ? self.repos.filter(createFilterFor(query)) : self.repos,
deferred;
if (self.simulateQuery) {
deferred = $q.defer();
$timeout(function() {
deferred.resolve(results);
}, Math.random() * 1000, false);
return deferred.promise;
} else {
return results;
}
}
function searchTextChange(text) {
$log.info('Text changed to ' + text);
}
function selectedItemChange(item) {
$log.info('Item changed to ' + JSON.stringify(item));
}
function loadAll() {
$log.info('test');
var repos;
repos = [];
$http.get('http://melkban24.ir/city/json/2').success(function(response) {
$scope.repos = response.data;
});
return repos.map(function(repo) {
repo.value = repo.nameCity.toLowerCase();
$log.info(repo.value);
return repo;
});
}
function createFilterFor(query) {
var lowercaseQuery = angular.lowercase(query);
return function filterFn(item) {
return (item.value.indexOf(lowercaseQuery) === 0);
};
}
}
})();
$http.get() is asynchronous, so the .success() callback won't be called until after your function has returned. That means loadAll() cannot return the data. Try not to confuse $scope.repos with the local variable repos as they are quite different things.
Don't use the deprecated .success() method at all. Use .then() as it will return a promise which is compatible with other uses of promises in angular.
Move the map code inside the .then callback and if you want loadAll() to return anything make it return the promise that .then() returns. That way anything that calls loadAll() can wait on the promise to complete.
function loadAll() {
return $http.get('http://melkban24.ir/city/json/2').then(function(result){
var repos = result.data.data;
return repos.map(function (repo) {
repo.value = repo.nameCity.toLowerCase();
return repo;
});
$scope.repos = repos;
});
}
Now you have two ways to get at the data: it will appear as the repos value in the scope once it has been retrieved. If used in an angular template the page will show the new data. Or call loadAll() and use the promise to get at the returned data:
loadAll().then(function(repos) { ... });
You should also consider including code for the case where $http.get() fails. Pass it an error callback as well.
Also, as #Rakeschand points out in the comments, the next step should be to move all the $http code out of the controller and into a service. You still end up calling a function that returns a promise, but code to convert the received data into the data you actually want can be removed from the controller.

How Can Asynchronous Function Result Be returned and Saved to firebase in AngularFire

I have created the service below.
app.factory('userProfileFactory', ['FBDB', 'searchParam', function(FBDB, searchParam) {
var personalKey;
return {
userProfile: function(searchEmail) {
var deferred = $q.defer();
var FBref = new Firebase(FBDB).child('items');
var promise = FBref.orderByChild('email')
.startAt(searchEmail)
.endAt(searchEmail)
.on('value', function(snapshot) {
var data = snapshot.val();
personalKey = Object.keys(data)[0];
deferred.resolve(personalKey);
});
return deferred.promise;
}
};
}]);
My Controller is as below. The issue is that it takes a moment for results to be returned. So when the $save function is called outside factory function, it reports an 'undefined variable'. How can I make it work when $save is outside?
app.controller('profileCtrl', ['userProfileFactory', 'FBDB', '$firebaseArray', function(userProfileFactory, FBDB, $firebaseArray) {
var FBref = new Firebase(FBDB).child('items');
userProfileFactory.userProfile().then(function(res){
var personalKey = res;
item.personalKey = res;
//$firebaseArray(FBref)$save(item); It works here. But moved this from here...
})
$firebaseArray(FBref)$save(item); //...to here. It does not work.
}]);
In your code, the line:
$firebaseArray(FBref)$save(item);
will execute before the resolve function:
function(res){
var personalKey = res;
item.personalKey = res;
}
The resolve function waits for the userProfileFactory.userProfile() promise to resolve (data to be returned) before executing, whereas the firebase.save line does not. You need to put it back inside of the then(resolve) function.

how to get the resolved value within promise in angularjs

how to get the resolved value directly in angular promise?
I want to get the string "ok" in below function, not the promise object.
anybody help??
var getReturn = function() {
var defer = $q.defer();
var promise = defer.promise;
defer.resolve("ok");
return promise.then(function (value) {
console.log(value);
return(value);
});
};
Since the function is not asynchronous, there's no need for a promise. So the correct way doing so will be:
var getReturn = function() {
return "ok";
}
If you still want this as a promise you should do as follows:
var getReturn = function() {
var defer = $q.defer();
setTimeout(function() {
defer.resolve("ok");
},0)
return defer.promise;
};
And wherever you call the function do the then:
getReturn().then(function (value) {
console.log(value);
});
You can't actually do that when you are dealing with promises. Promises are meant to be awaited or deferred until the expected value is ready meaning you should get the value only in it's "then" block especially if it's an $http promise.

How to return a promise and have it be rejected without using a $timeout

I'm in a spot where I need to return a promise, that would otherwise be returned by a server http request, and I need it to be rejected, so I don't needlessly hit the server. I've been trying to make and return a rejected promise, something like:
var promise = $q.defer().promise;
return promise.reject( value ); // doesn't work
or
return $q.reject(); // also doesn't work
I can't seem to figure out how to return a rejected promise so I can save the server call, but I'm in a spot where it is either return a made-up rejected promise or make the server call. I'm in between both where I'm not in the original child directive that invoked the call, and the child wasn't able to make the comparison that was possible in the parent directive. Is there anyway to do this without a $timeout?
I think what you are looking for is
var app = angular.module('my-app', [], function() {
})
app.controller('AppController', ['$scope', '$q',
function($scope, $q) {
$scope.message = 'This is for testing';
function test() {
//create a deferred object
var deferred = $q.defer();
//reject the promise
deferred.reject(2);
//then return the promise
return deferred.promise;
}
test().then(function() {
$scope.message = 'Resolved';
}, function() {
$scope.message = 'Rejected';
})
}
])
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="my-app" ng-controller="AppController">
{{message}}
</div>
The deffered api has the reject/resolve method, where as the promise api has methods used to register the callback methods

How can I get a service to access server data via an $http call?

I make an $http call inside a service that is supposed to get data from my server. For some reason I can't get my service to work - nothing happens. I know the server code works because if I place the $http call inside a function within my controller, then it gets the server data as expected. Here is the code I have so far:
app.service('myService', function($q,$compile,$http) {
this.getData = function() {
var deferred = $q.defer();
var promise = $http.get('myfile.php').success(function (data) {
var response = $compile(data)($scope);
deferred.resolve(response);
});
return deferred.promise;
};
});
Also, I know the code that uses this service works because if I do something like the following,
app.service('myService', function() {
this.getData = function() {
return 'TEST';
};
});
then I will see the word "TEST" show up in the div that utilizes this service. I feel like I'm very close, but there is something I am missing. Any ideas on what I'm doing wrong?
UPDATE:
controller: function($scope, $http, $rootScope, myService){
var scope = $rootScope;
scope.viewMyData = function() {
var element = myService.getData();
$('#myDiv').html(element);
}
}
HTML:
<div ng-click="viewMyData()">Click Here</div>
<div id="myDiv"></div>
If I strip the code in myService and simply return TEST (as above), then I will see "TEST" show up in id="myDiv". But for some reason the $http call isn't being triggered.
#tymeJV is right, but here's my attempt to spell out the example better. $http returns a promise interface that allows you to chain callbacks to be executed when the $http response returns. So, in this case, calling myService.getData() can't return the result immediately (it's off getting the data from the server), so you need to give it a function to execute when the server finally responds. So, with promises, you simply attach your callback using the thePromise.then(myCallbackFunc).
Service
app.service('myService', function($q,$compile,$http) {
this.getData = function() {
var promise = $http.get('myfile.php');
promise = promise.then(function (response) {
return response.data;
});
return promise;
};
});
Controller
controller: function($scope, $rootScope, myService){
var scope = $rootScope;
scope.viewMyData = function() {
myService.getData().then(function(data) {
$('#myDiv').html(element);
});
}
}
Use .then in the controller to continue the promise pattern:
myService.getData().then(function(data) {
$('#myDiv').html(data);
});

Resources