Get resolved data from service within a service - angularjs

How do I resolve the $promise generated by apiResource inside getDB() before it's actually returned back to my controller? Right now I get undefined.
people.factory('uniqueContacts', ['apiResource', function(apiResource) {
return{
getDB: function () {
apiResource.query({api_resource:'people'}).$promise.then(function(response){
return response.data
});
}
}
}]);
$resolvedData = uniqueContacts.getDB();
console.log($resolvedData);

There are 2 things:
first your function needs to actually return something
second here you have an async process so you'll need a callback, you cannot simply store the return in a variable like that
Check that code instead:
people.factory('uniqueContacts', ['apiResource', function(apiResource) {
return {
getDB: function () {
return apiResource.query({api_resource:'people'}).$promise.then(function(response){
return response.data
});
}
};
}]);
uniqueContacts.getDB().then(function (data) {
console.log(data);
});

Probably something like that. I made async the function getDB.
people.factory('uniqueContacts', ['apiResource','$q', function(apiResource,$q) {
return{
getDB: function () {
var d = $q.defer
apiResource.query({api_resource:'people'}).then(function(response){
d.resolve(response);
},function(err){
d.reject(err);
});
}
}
}]);
uniqueContacts.getDB().then(function(response){
$resolvedData = response;
console.log($resolvedData);
});
If you want to wait for the async call to be finished, add a promise table and wait for $q.all like that.
var promises = [];
promise.push(uniqueContacts.getDB().then(function(response){
$resolvedData = response;
}));
$q.all(promises).then(function(){
console.log($resolvedData);
});

Related

can't get the value in my controller after calling a promise in the service

i have a controller that calls a function in a service. this, in turn, calls a promise function inside the same service.
the problem is that i can't get the returned value in my controller.
the controller:
function mainFunctionInControlelr() {
some code here...
vm.evtHTTPFactory.getData() // calling the service
.then(function(response) {
console.log("the returned value is " + response.myReturned );
});
}
the service:
factory.getData = function(parm) {
return factory.getABC(parm); // calling another method in the same service
};
factory.getABC = function(parm) {
return $q(function(resolve, reject) {
$http.get(PltConfig.APIPath + '/v1/............', {
params: { inputParm: parm }
})
.success(function (response) {
resolve(response.data.myReturned);
return;
} )
});
};
the issue is that getData, inside the service, is calling getABC, also inside the service. something is lost in the process. I need to have "myReturned" in the controller.
what do i need to put in getData (in the service) to make things work?
thanks a lot.
I would use async await... like this:
in your function getData:
factory.getData = async function(parm) {
var data = await factory.getABC(parm);
return data;
};
in your function controller:
async vm.evtHTTPFactory.getData() {
var myResp = await vm.evtHTTPFactory.getData()
console.log(myResp)}
An example here: https://jsfiddle.net/hernangiraldo89/frv4L2jh/4/
I hope it helps you!

How to get .notify() in chaining promises from $q.all?

I am using chained promises in angular js with $q service and it's working fine except the information of progressCallback ? let me draw what I have done so far?
calling function from my controller in below chainable promise way
fun1()
.then(resp1){
return fun2(resp1.id);
})
.then(resp2){
return $q.all([fun3(resp2.id),fun4(resp2.name)]);
})
.then(function(resp34){
return fun5();
})
.then(success)
.catch(errorhandler)
.finally(final);
and here is my all functions signature in service
var funX = function(param) {
var d = $q.defer();
d.notify('start with funX'); // Note: it was not working so placed inside else
doSomethingASync(param, function(err,data) {
if(err) { d.reject(err);}
else { d.notify('done with funX'); d.resolve(data); }
});
return d.promise;
});
Now my question is where do I receive this d.notify() message in my controller?
trial 1
.then(resp1, info1){
return fun2(resp1.id);
});
but it's undefined
trial 2
.then(resp1, err1, info1) {
return fun2(resp1.id);
}
but still undefined?
UPDATE
I have find a way by adding second parameter in finally()
.then().catch().finally(final, notify);
and here is my function definitions.
var errorHandler = function(err) {
console.error('Error returned from function:', err);
};
var final = function() {
console.log('Called Finally');
};
var notify = function(notification) {
console.log('Notify', notification);
};
var success = function(data) {
console.log('Success data');
console.log(data);
};
Can we get each promise function notification or this is not feasible?
But Now my query changed to
How do we add a .notify for the $q.all() ?
as I understand that $q.all returns a single promise which contains all promise resolve data;

Pass parameters from $get promise response to $scope

I do a ajax (get) request and obtain a promise with json data in a angular "jobList" service.
Then I update the scope with the obtained data. But my problem is that to update a scope variable 'X' I need to create a function per variable "readX" (see bellow).
Is there a way to add parameters, like in the last function in the following code?
app.controller("JobListController", ['$scope', '$timeout', 'jobList',
function ($scope, $timeout, jobList) {
var readList = function (response) {
if (response) {
$timeout(function () {
$scope.list = response;
$scope.$apply();
});
}
};
var readFamilies = function (response) {
if (response) {
$timeout(function () {
$scope.allFamilies = response;
$scope.$apply();
});
}
};
var readRegions = function (response) {
if (response) {
$timeout(function () {
$scope.allRegions = response;
$scope.$apply();
});
}
};
// !!! ----- HERE ------------- !!!
var readSomething = function (response, something) {
if (response) {
$timeout(function () {
$scope[something] = response;
$scope.$apply();
});
}
};
jobList.get().then(readList);
jobList.getAll("allFamilies").then(readFamilies);
jobList.getAll("allRegions").then(readRegions);
}]);
For a start you could simplify those callback functions: provided the callback happens inside angular (and it you're using $http it will) you don't need the $timeout call nor the $scope.$apply() call. Also you should write your service to only succeed if it returns data, reject the promise if it fail;s and that way you don't need the if So each callback could just be the assignment.
If you are making multiple calls that return promises, can you collapse the calls together?
$q.all([jobList.get(), jobList.getAll("allFamilies"), jobList.getAll("allRegions")])
.then(([list, families, regions]) => {
$scope.list = list;
$scope.allFamilies = families;
$scope.allRegions = regions;
});
I used es6 syntax here: it's well worth setting up your build chain to use something like babeljs so you can use the shorthand notation for simple callbacks.
If you really want to make the calls separately (they still evaluate in parallel) you can write a factory to generate the callbacks:
function assignToScope(name) {
return success;
function success(data) {
$scope[name] = data;
}
}
jobList.get().then(assignToScope('list'));
jobList.getAll("allFamilies").then(assignToScope('allFamilies'));
jobList.getAll("allRegions").then(assignToScope('allRegions'));
you could save the required property in a scope variable, before getting the data.
Something like this:
$scope.property = "list";
jobList.get().then(readSomething);
and your function would now become:
var readSomething = function (response) {
if (response) {
$timeout(function () {
$scope[$scope.property] = response;
$scope.$apply();
});
}
};
P.S:
I guess you can also use closures to do something like this:
var readSomething = function (something) {
return function(response){
if (response) {
$timeout(function () {
$scope[something] = response;
$scope.$apply();
});
}
}
};
Try this:
jobList.get().then(function (response) {
readSomething(response);
});
And function readSomething can have response only as in input.

Catching errors at the end of a chain of promises

I am using a factory to query data from Parse.com, this occurs many times in my ionic app and would like to apply a little more DRY to my code.
To call data I am using:
ParseFactory.provider('Clients', query).getAll().success(function(data) {
$localStorage.Clients = data.results;
}).error(function(response) {
errorFactory.checkError(response);
});
And often run many of these back to back to get data from different classes on the loading of a page.
Is it possible to use one error block at the end of all of these? like this:
ParseFactory.provider('Favourites', query).getAll().success(function(data) {
$localStorage.Favourites = data.results;
})
ParseFactory.provider('Somethings/', query).getAll().success(function(data) {
$localStorage.Programmes = data.results;
})
ParseFactory.provider('UserItems', query).getAll().success(function(data) {
$localStorage.UserExercises = data.results;
})
ParseFactory.provider('Customers', query).getAll().success(function(data) {
$localStorage.Clients = data.results;
}).error(function(response) {
errorFactory.checkError(response);
});
You could create helper method:
function query(resource, query) {
function querySucceeded(data) {
$localStorage[resource] = data.results;
}
function queryFailed() {}
ParseFactory.provider(resource, query)
.getAll()
.success(querySucceeded)
.error(queryFailed);
}
and, then just call:
query('Favourites', query);
query('Customers', query);
and so on.
Alternatively, you could factor queryFailed out, as such:
function query(resource, query) {
function querySucceeded(data) {
$localStorage[resource] = data.results;
}
return ParseFactory.provider(resource, query)
.getAll()
.success(querySucceeded);
}
function queryFailed() {
}
$q.all([
query('Favourites', query1),
query('UserItems', query2)])
.error(queryFailed);
$q.all takes an array (or object) of promises, and returns a single one.
The returned promise is resolved when all the original promises are resolved. It's rejected as soon as one of the original promises is rejected.
So, what you can simply do is something like
var request = function(path) {
return ParseFactory.provider(path, query).getAll();
};
var promises = {
favourites: request('Favourites'),
programmes: request('Somethings/'),
exercises: request('UserItems'),
customers: request('Customers')
};
$q.all(promises).then(function(results) {
$localStorage.Favourites = results.favourites.data.results;
// ...
}).catch(function() {
// ...
});

AngularJS : chaining http promises $q in a service

i have problems when it comes to $http promises in angularjs. i am doing this in my service: (the getSomething function should chain two promises)
the second function uses a external callback function!
app.service('blubb', function($http, $q) {
var self = this;
this.getSomething = function(uri, data) {
return self.getData(uri).then(function(data2) {
return self.compactData(uri, data2);
});
};
this.getData = function(uri) {
var deferred = $q.defer();
$http.get(uri).success(function(data) {
deferred.resolve(data);
}).error(function() {
deferred.reject();
});
return deferred.promise;
};
this.compactData = function(uri, data) {
var deferred = $q.defer();
/* callback function */
if(!err) {
console.log(compacted);
deferred.resolve(compacted);
} else {
console.log(err);
deferred.reject(err);
}
/* end of function */
return deferred.promise;
};
});
when i use the service in my controller it doesn't output the console.log:
blubb.getSomething(uri, input).then(function(data) {
console.log(data)
});
edit:
if i define the callback function by myself in 'compactData' it works, but i am using "jsonld.compact" from https://raw.github.com/digitalbazaar/jsonld.js/master/js/jsonld.js and THIS doesn't work!
jsonld.compact(input, context, function(err, compacted) {
if(!err) {
console.log(compacted);
deferred.resolve(compacted);
} else {
deferred.reject('JSON-LD compacting');
}
});
i am getting the console.log output in jsonld.compact but the resolve doesn't work and i don't know why..
it only works with $rootScope.$apply(deferred.resolve(compacted));
I'm using chaining promises like this:
$http.get('urlToGo')
.then(function(result1) {
console.log(result1.data);
return $http.get('urlToGo');
}).then(function(result2) {
console.log(result2.data);
return $http.get('urlToGo');
}).then(function(result3) {
console.log(result3.data);
});
Chaining promises works here : jsfiddle
In your implementation, if $http.get or compactData goes wrong your console.log(data) will not be call.
You should maybe catch errors :
blubb.getSomething(uri, input).then(function(data) {
console.log(data);
}, function(err) {
console.log("err: " + err);
});
Whenever you use an external (external to AngularJS) callback that runs in a new turn/tick, you have to call $apply() on the appropriate scope after it has been invoked. This lets AngularJS know it has to update. You'll probably want to make sure you're only calling it once -- after all of the promises have been resolved. As an aside, jsonld.js provides a promises/future API, so if you're already using promises, you don't have to do that wrapper code above. Instead you can do:
var promisesApi = jsonld.promises();
var promise = promisesApi.compact(input, context);
// do something with the promise
I would suggest you to use a Factory instead of a service.
Just return the function from the factory and use it in your controller

Resources