I am getting the error Cannot read property of '$promise' of undefined.
Here is the code that is throwing it:
var myPromise = sharedDataService.getData($scope.entityId).$promise;
resolvePromise(myPromise, 'entityData');
the resolvePromise method:
function resolvePromise(promise, resultObject){
promise.then(function(response){
$scope[resultObject] = result;
});
promise['catch'](function(error){
//error callback
});
promise['finally'](function(){
//finally callback
});
sharedDataService looks like this:
var publicInterface = {
getData: getData
};
var storedData;
function getData(entityId) {
if(storedData.entityId === entityId){
return storedData;
}else{
var entityDataPromise = dataAccessService.getEntityData(entityId).$promise;
entityDataPromise.then(function (response) {
storedData = response;
return storedData ;
});
entityDataPromise['catch'](function(error) {
//throw error;
});
entityDataPromise['finally'](function(done) {
//do finally
});
}
}
return publicInterface;
finally, the dataAccessService:
var publicInterface = {
getEntityData: getEntityData
}
var entityData = $resource(apiUrl + 'Entity', {}, {
'getEntityData': {
method: 'GET',
url: apiUrl + 'Entity/getEntityDataById'
}
}
function getEntityData(entityId){
return entityData.getEntityData({entityId: entityId})
}
return publicInterface;
the original promise is throwing an error. When I put breakpoints various places, I can see my data is being returned sometimes. The functionality of sharedDataService is almost one of a chaching service.
Why is my original promise returning undefined?
Your getData() method doesn't have a return when if is false. So you would need to return entitiyDataPromise.
But, that would mean one condition returns a promise and the other returns an object
So both conditions need to return a promise and we can use $q for the first condition
function getData(entityId) {
if(storedData.entityId === entityId){
// return to getData()
return $q.resolve(storedData);
}else{
var entityDataPromise = dataAccessService.getEntityData(entityId).$promise;
// return to getData()
return entityDataPromise.then(function (response) {
storedData = response;
return storedData ;
});
entityDataPromise['catch'](function(error) {
//throw error;
});
entityDataPromise['finally'](function(done) {
//do finally
});
}
}
Be sure to inject $q in service.
In controller would be:
var myPromise = sharedDataService.getData($scope.entityId);
resolvePromise(myPromise, 'entityData');
Related
Promise in ForEach
I'm having a problem, I need to call a service N times and I've tried this:
This is my function that calls the service, I send a parameter that is "code" and returns a promise.
var get222 = function(codigo) {
var defer = $q.defer();
var cbOk = function(response) {
//console.log(response);
defer.resolve(response);
}
var cbError = function(error) {
//console.log(error);
defer.reject(error);
}
VentafijaAccessService.getProductOfferingPrice(codigo, cbOk, cbError);
return defer.promise;
}
After this function, I get the codes and I need to make a call N times and when they finish returning the promise to get the answer for each code I send.
var getProductOfferingPrice = function(_aCodigoOfertas) {
var deferred = $q.defer();
var results = [];
var promises = [];
angular.forEach(_aCodigoOfertas, function(codigo) {
promises.push(get222(codigo));
});
$q.all(promises)
.then(function(results) {
// here you should have all your Individual Object list in `results`
deferred.resolve({
objects: results
});
});
return deferred.promise;
};
The calls to the services IF THEY ARE EXECUTED, but never returns the promise, I can not get the response of each one.
EDIT
VentaDataService.js
var get222 = function(codigo) {
return $q(function(resolve, reject) {
VentafijaAccessService.getProductOfferingPrice(codigo, resolve, reject);
});
}
var getProductOfferingPrice = function(_aCodigoOfertas) {
return $q.all(_aCodigoOfertas.map(function(codigo) {
return get222(codigo);
}));
};
VentaFijaController.js
var cbOk2 = function(response) {
console.log(response);
}
var cbError2 = function(error) {
console.log(error);
}
VentafijaDataService.getProductOfferingPrice(codigoOfertas)
.then(cbOk2, cbError2)
There's no need to wrap a new promise around this. Just return the $q.all() promise:
VentafijaAccessService.getProductOfferingPriceAllPromise = function(_aCodigoOfertas) {
var promises = [];
angular.forEach(_aCodigoOfertas, function(codigo) {
promises.push(get222(codigo));
});
return $q.all(promises);
};
The resolved value of the returned promise will be an array of results.
VentafijaAccessService.getProductOfferingPriceAllPromise(...).then(results => {
console.log(results);
}).catch(err => {
console.log(err);
});
If _aCodigoOfertas is an array, you can further simply getProductOfferingPrice to this:
VentafijaAccessService.getProductOfferingPriceAllPromise = function(_aCodigoOfertas) {
return $q.all(_aCodigoOfertas.map(function(codigo) {
return get222(codigo);
}));
};
You can also vastly simplify get222() to this:
var get222 = function(codigo) {
return $q(function(resolve, reject)) {
// call original (non-promise) implementation
VentafijaAccessService.getProductOfferingPrice(codigo, resolve, reject);
});
}
Then, in the controller, you could do this:
VentafijaDataService.getProductOfferingPriceAllPromise(codigoOfertas).then(function(result) {
console.log(result);
}).catch(function(e) {
console.log('Error: ', e);
});
I have the problem that my function doesn't wait for the response of http request and go further. I know that I can use promise to wait but I don't understand the concept.
I have a data service that have all http request :
function GetGroupIdFromBakery(bakeryId, successCallback, errorCallback) {
$http.get(service.baseUrl + "BakeriesGroup/Bakeries/" + bakeryId)
.then(function (result) { successCallback(result.data); }, errorCallback);
}
From another service, I call the data service :
var hasPermission = function (permission, params) {
permissionRoute = permission;
setIdEntity(params);
for (var i = 0; i < permissions.length; i++) {
if (permissionRoute.Name === permissions[i].Name) {
if (permissions[i].Scope == "System")
return true;
else if (permissions[i].Scope == permissionRoute.Scope && permissions[i].IdEntity == permissionRoute.IdEntity)
return true;
}
}
return false;
}
var setIdEntity = function (params) {
if (permissionRoute.Scope == "Bakery")
permissionRoute.IdEntity = parseInt(params.bakeryId);
else if (permissionRoute.Scope == "Group") {
if (params.bakeriesGroupId)
permissionRoute.IdEntity = parseInt(params.bakeriesGroupId);
else {
getGroupOfBakery(parseInt(params.bakeryId));
}
console.log(permissionRoute.IdEntity);
}
}
var getGroupOfBakery = function (bakeryId) {
DataService.GetGroupIdFromBakery(bakeryId, function (groupId) {
permissionRoute.IdEntity = groupId;
}, function (error) {
console.error("something went wrong while getting bakery");
alert("Une erreur s'est produite lors de la récupération de la boulangerie");
});
}
I must wait for the response of DataService.GetGroupIdFromBakery(). With this code, permission.EntityId is undefined when I call getGroupByBakery().
Can somebody help me, please?
You can add a watcher to your response data. I think it is EntityId in your case.
It get executed as soon as your EntityId changes. After getting the response data you can call the function, this time EntityId will not be undefined.
$scope.$watch(function () {
return EntityId
}, function (newEntityId) {
if(newEntityId != undefined {
// now you can call your function
}
}
}, true);
Exactly, you have to use promises, because $http module is asynchronus. I built a service for that:
.service('RequestService', function($q, $http){
return {
call: function(htmlOptions){
var d = $q.defer();
var promise = d.promise;
$http(htmlOptions)
.then(function(response){
d.resolve(response.data);
}, function(response){
d.reject(response.data);
});
promise.success = function(fn) {
promise.then(fn);
return promise;
};
promise.error = function(fn) {
promise.then(null, fn);
return promise;
};
return promise;
}
}
})
And then:
RequestService.call({
method: 'POST' //GET, DELETE ...
data: data,
url: 'http://someurl.com/'
});
you should use defer.
create a new defer object in GetGroupIdFromBakery method,in success part resolve the defer and in failed part reject it, and return the promise of defer at the end.
function GetGroupIdFromBakery(bakeryId, successCallback, errorCallback, $q) {
var defer = $q.defer();
$http.get(service.baseUrl + "BakeriesGroup/Bakeries/" + bakeryId)
.then(function (result) {
successCallback(result.data);
defer.resolve(result.data);
}, function(){
defer.reject();
});
return defer.promise;
}
This successfully return you a promise that you can call with .then() and receive as a value in the service where you need to have the data of GetGroupIdFromBakery.
getGroupOfBakery(parseInt(params.bakeryId), $q).then(function(data){
// here you have data
})
Be aware you should inject $q, here I supposed that we have $q in service and I passed it to method.
i have this function:
charCtrl.loadDataFromToMonth= function (from,to,year) {
var url = servername+'admin/dashboard/getIncidentDepartByMonthFromTo/'+from+'/'+to+'/'+year;
//alert(url);
function onSuccess(response) {
console.log("+++++getIncidentDepartByMonthFromTo SUCCESS++++++");
if (response.data.success != false) {
$scope.payloadgetIncidentDepartByMonthFromTo = response.data.data;
var getIncidentDepartByMonthFromTo= $scope.payloadgetIncidentDepartByMonthFromTo;
// alert('dddd'+JSON.stringify(loadedDataByMission));
$scope.labelsf = [];
$scope.qsd = [];
$scope.dataf = [];
getIncidentDepartByMonthFromTo.forEach(function(data) {
var monthNumber=$filter('date')(data.la_date, "MM");
$scope.labelsf.push($filter('monthName')(monthNumber));
$scope.dataf.push(data.number);
$scope.qsd.push('ff','ff','ff');
//alert($scope.labelsf );
});
//alert( $scope.dataf );
charCtrl.loadDataFromToMonthArrivee(from,to,year);
} else {
alert("failure");
}
// $scope.stopSpin('spinner-0');
};
function onError(response) {
console.log("-------getIncidentDepartByMonthFromTo FAILED-------");
//$scope.stopSpin('spinner-0');
console.log(response.data);
console.log("Inside getIncidentDepartByMonthFromTo error condition...");
};
//----MAKE AJAX REQUEST CALL to GET DATA----
ajaxServicess.getData(url,username,password, 'GET', '').then(onSuccess, onError);
};
this function return for exemple: $scope.dataf = ['45','48','255'];
I have a second function, by the way its the same function but it gets data from other Rest service:
charCtrl.loadDataFromToMonthArrivee= function (from,to,year) {
var url = servername+'admin/dashboard/getIncidentArriveeByMonthFromTo/'+from+'/'+to+'/'+year;
//alert(url);
function onSuccess(response) {
console.log("+++++getIncidentDepartByMonthFromTo SUCCESS++++++");
if (response.data.success != false) {
$scope.payloadgetIncidentArriveeByMonthFromTo = response.data.data;
var getIncidentArriveeByMonthFromTo= $scope.payloadgetIncidentArriveeByMonthFromTo;
// alert('dddd'+JSON.stringify(loadedDataByMission));
$scope.labelsf = [];
$scope.qsd = [];
$scope.dataf = [];
getIncidentArriveeByMonthFromTo.forEach(function(data) {
var monthNumber=$filter('date')(data.la_date, "MM");
$scope.labelsf.push($filter('monthName')(monthNumber));
$scope.dataf.push(data.number);
//$scope.qsd.push('ff','ff','ff');
//alert($scope.labelsf );
});
alert('aqsz'+$scope.dataf );
} else {
alert("failure");
}
// $scope.stopSpin('spinner-0');
};
function onError(response) {
console.log("-------getIncidentDepartByMonthFromTo FAILED-------");
//$scope.stopSpin('spinner-0');
console.log(response.data);
console.log("Inside getIncidentDepartByMonthFromTo error condition...");
};
//----MAKE AJAX REQUEST CALL to GET DATA----
ajaxServicess.getData(url,username,password, 'GET', '').then(onSuccess, onError);
};
this function return for exemple: $scope.dataf = ['69','50','96'];
my question is: is there a way to declare the second function in the first fuction and get a result like this:
this function return for exemple: $scope.dataf = [['45','48','255'],['69','50','96']];
I would use promises to wait for the second call to respond and update a variable in the function scope (sibling to the function). Something like this:
var aggregate = [];
charCtrl.loadDataFromToMonth()
.then(function(resp){
return new Promise(resolve, reject){
aggregate.push(resp.data); // push the response from the first call
charCtrl.loadDataFromToMonthArrivee()
.then(function(resp) {
aggregate.push(resp.data); // push the result from the second call
resolve(resp)
})
}
})
.then(function(resp){
console.log(aggregate); // should have both results
})
Or better yet, you can use Promise.all (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all)
Am trying to call a Post method and then depending on the result I am going to call same Post method multiple times and return the result, using $q.all.
My Post method is :
getData: function (params, callback) {
$http.post('service/myService', params)
.success(function (data) {
callback(null, data);
}).error(function (error) {
callback(error);
});
}
I am calling it in below function, this function is recursive so if it contains nextUrl I am doing same thing until there is no object for paging:
var result = [];
var promises = [];
var checkForPaging = function (nextUrl, service, $q) {
var deferred = $q.defer();
var criteria = {
url: url
}
var promise = service.getData(criteria, function (error, data) {
if (data.statusCode == 200) {
for (var i = 0; i < data.body.items.length; i++) {
result.push(data.body.items[i]);
}
if (data.body.paging != null && data.body.paging.next != null) {
checkForPaging(data.body.paging.next.url, service, $q);
} else{
deferred.resolve(result);
}
}
});
promises.push(promise);
$q.all(promises)
return deferred.promise;
}
Then am calling this function from below and want to get the result back once all calls are complete:
checkForPaging(data.body.paging.next.url, myService, $q).then(function (data) {
console.log(data)
});
The issue I am having is that it never hits the callback function above : console.log(data). But I can see it calling the Post method several times.
If I resolve it like below then I can see after first Post it is hitting the callback above:
$q.all(promises).then(function (results) {
deferred.resolve(result);
}, function (errors) {
deferred.reject(errors);
});
Am I doing it right? How can I get the result back and call the Post method several times?
Let me know if it is not clear or have any questions!
Try something like this with proper promise chaining:
var result = [];
var checkForPaging = function(nextUrl, service) {
var criteria = {
url: url
}
return service.getData(criteria, function(error, data) {
if (data.statusCode == 200) {
for (var i = 0; i < data.body.items.length; i++) {
result.push(data.body.items[i]);
}
if (data.body.paging != null && data.body.paging.next != null) {
return checkForPaging(data.body.paging.next.url, service);
} else {
return result;
}
}
});
}
checkForPaging(data.body.paging.next.url, myService).then(function(data) {
console.log(data)
});
And getData:
getData: function(params) {
return $http.post('service/myService', params)
.then(function(response) {
return response.data;
});
}
Here is solution: https://plnkr.co/edit/HqkFNo?p=preview I rewrited logic a bit.
You can catch the main idea.
UPDATE added promiseless solution
1) Your service should return only promise:
this.getData = function(url, params){
return $http.post(url, params); //You're just returning promise
}
2) You don't need $q.all, you can use single promise:
var result = [];
var deferred;
var checkForPaging = function (url) {
if(!deferred){
deferred = $q.defer();
}
//resolvind service promise
newService.getData(url).then(
//if ok - 200
function(response){
for (var i = 0; i < data.body.items.length; i++) {
result.push(data.body.items[i]);
}
if (data.body.paging != null && data.body.paging.next != null){
{
return checkForPaging(data.body.paging.next.url);
} else{
deferred.resolve(result);
}
},
//handle errors here
function(error) {
}
);
return deferred.promise;
}
3) You should call it like this:
checkForPaging('url').then(function(data){
//here will be resolved promise
console.log(data);
});
I have the following in my controller:
ApiRequest.get('locations').then(function(locations) {
$scope.locations = locations.locations;
});
ApiRequest.get('sublocations').then(function(sublocations) {
$scope.sublocations = sublocations.sublocations;
});
ApiRequest.get('varieties').then(function (varieties) {
$scope.varieties = varieties.varieties;
});
ApiRequest.get('tasks').then(function(tasks) {
$scope.tasks = tasks.tasks;
});
ApiRequest.get('customers').then(function(customers) {
$scope.customers = customers.customers;
});
ApiRequest.get('batches').then(function(batches) {
$scope.batches = batches.batches;
$ionicLoading.hide();
});
The data from each of these requests goes on to poplate select boxes in a form.
Here is my APIRequest service:
return {
get: function(entity) {
if($rootScope.online == false) {
var data = {};
data = JSON.parse(localStorage.getItem('data-' + entity));
console.log(data);
deferred.resolve(data);
} else {
$http.get($rootScope.baseUrl + entity).success(function(data) {
deferred.resolve(data);
})
}
return deferred.promise;
},
}
It would appear that for some reason the results aren't getting back from the service on time to display them in the view.
Is this something to do with the way I am handling the promise?
At first look, you declared the promise with $q outside your function as global (because I don't see inside). Try this one:
get: function(entity) {
var deferred = $q.defer();
if($rootScope.online == false) {
var data = {};
data = JSON.parse(localStorage.getItem('data-' + entity));
console.log(data);
deferred.resolve(data);
} else {
$http.get($rootScope.baseUrl + entity).success(function(data) {
deferred.resolve(data);
})
}
return deferred.promise;
},
your current implementation has little to no error handling and is executing multiple API requests in parallel; I would recommend chaining the promises.
ApiRequest.get('locations').then(function(locations) {
$scope.locations = locations.locations;
return ApiRequest.get('sublocations');
}).then(function(sublocations) {
$scope.sublocations = sublocations.sublocations;
return ApiRequest.get('varieties')
}).then(function (varieties) {
$scope.varieties = varieties.varieties;
return ApiRequest.get('tasks')
}).then(function(tasks) {
$scope.tasks = tasks.tasks;
return ApiRequest.get('customers')
}).then(function(customers) {
$scope.customers = customers.customers;
return ApiRequest.get('batches')
}).then(function(batches) {
$scope.batches = batches.batches;
$ionicLoading.hide();
}, function(_error) {
$ionicLoading.hide();
console.log(_error);
});
and then your service can be simplified; the $http client returns a promise and using $q.when can return a promise also
get: function(entity) {
if($rootScope.online == false) {
var data = {};
data = JSON.parse(localStorage.getItem('data-' + entity));
console.log(data);
$q.when(data);
} else {
return $http.get($rootScope.baseUrl + entity)
}
},