Angular Service call after variable population - angularjs

I'm trying to create an angular service that holds a variable which value in turn will be set after result of another service call. Here is the code:
angular.module("someApp",[]).service("someServiceName", function() {
var myVar = undefined;
this.get = function() {
if (myVar) {
return myVar
} else {
console.error('Error text');
}
}
var init = function () {
anotherService.call().then(function (result) {
myVar = result;
});
};
init();
});
When I call someServiceName.get() first time after application load it returns nothing (because myVar is not filled yet). But on next service call it returns value if myVar variable.
So, my question is how to return myVar on someServiceName.get() call but after running init() first?

Maybe you are calling someServiceName.get() before the anotherService.call() is ended; this will give you undefined.
What about:
angular.module("someApp",[]).service("someServiceName", function($q) {
var deferred = $q.defer();
this.get = function() {
anotherService.call()
.then(function (result) {
if (result) {
deferred.resolve(result);
} else {
deferred.reject('Error text');
}
}, function (error) {
deferred.reject('AnotherService error');
});
return deferred.promise;
}
});
In this case you will recall the anotherService each time you want to get his value.

Related

Call a asynchronous method after another in AngularJS

I have a $watch attached to the appId variable. SO, when appId get changed it called the init function
$scope.$watch('appId', function() {
if ($scope.appId != '') {
console.log('Inside appId watch');
$scope.init();
}
});
init() calls two service methods
$scope.init = function() {
if ($scope.appId === undefined || $scope.appId == '') return false;
$scope.getPrincipals($scope.loadPrincipals);
$scope.getSignaturesByAppId($scope.loadSignatures);
};
The methods are
$scope.getSignaturesByAppId = function (callback) {
ApplicationDataSource.getSignaturesByAppId($scope.appId, function (result) {
callback(result);
$scope.$apply();
});
};
$scope.loadSignatures = function (result) {
var signatureResultSet = angular.fromJson(result[0]);
$scope.appSignatures = signatureResultSet;
if($scope.appSignatures.length===0){
$scope.setDefaultValue();
}
else{
$scope.setValueFromObject();
}
};
$scope.getPrincipals = function (callback) {
ApplicationDataSource.getApplicationPrincipalList($scope.appId, function (result) {
callback(result);
$scope.$apply();
});
};
$scope.loadPrincipals = function (result) {
var guarantorResultSet = angular.fromJson(result[0]);
$scope.principals = guarantorResultSet;
};
The problem occurs here. In loadSignatures(), I have called a method setDefaultValue() which needs the data retrieve from loadPrincipals. So, when, loadSignatures called, principal data is not updated.
How to call the $scope.getPrincipals($scope.loadPrincipals) after $scope.getSignaturesByAppId($scope.loadSignatures) finish to retrieve data.
You can use Promises, here is an example:
var promise = callThatRunsInBackground();
promise.then(
function(answer) {
// do something
},
function(error) {
// report something
},
function(progress) {
// report progress
});
So in your code it might look like (I will leave it to you to fix as I'm not going to compile or check for syntax errors):
var getPrincipals = $scope.getPrincipals($scope.loadPrincipals);
getPrincipals.then(
function(datapayload) {
//do something with datapayload perhaps
$scope.getSignaturesByAppId($scope.loadSignatures);
});
This will make it wait until getPrincipals is finished before running getSignaturesbyAppId
What solve my issue is, I called $scope.getSignaturesByAppId($scope.loadSignatures); in loadPrincipals callback function, not in init()
$scope.loadPrincipals = function (result) {
var guarantorResultSet = angular.fromJson(result[0]);
$scope.principals = guarantorResultSet;
$scope.getSignaturesByAppId($scope.loadSignatures);
};

Calling second http call after the first http call finish

This is the service where im saving the data and returning the result
nurseService.js
(function () {
'use strict';
angular.module('app.services')
.factory('NurseService', NurseService);
NurseService.$inject = ['$http', '$q','Constants'];
function NurseService($http, $q, Constants){
var service = {
saveSample:saveSample
};
return service;
function saveSample(data) {
var deferred = $q.defer();
$http({method:"POST", data:data, url:Constants.API_URL_SAVE_SAMPLE_COLLECATION}).then(function(result){
return deferred.resolve(result.data);
});
};
return deferred.promise;
}
})();
This is the controller where im using the return value and based on the value returned im calling another http get method and printing it.
vm.saveSamples = function() {
var data = {
visitId: visitId,
orders: vm.gridTestApi.selection.getSelectedRows()
};
var url = Constants.API_URL_SAVE_SAMPLE_COLLECATION;
var barCodeResponse = null;
var sampleId = "";
var myDataPromise = NurseService.saveSample(data);
myDataPromise.then(function(result) {
console.log("data.name"+ JSON.stringify(result));
vm.printBarCode(result.sampleId);
// if(sampleId != ""){
printElement("printThisElement");
// }
});
//Barcode method this should call after saving the data and returned the sampleId
vm.printBarCode = function(sampleId) {
$http.get("master/barcode/"+sampleId).then(function (response) {
vm.barCodeImage = angular.copy(response.data.result);
});
}
But here before the saving print is calling. How can I hadle so that the first call should finish before the second http call to barcode and print it
//Print code
function printElement(elem) {
var printSection = document.getElementById('printSection');
// if there is no printing section, create one
if (!printSection) {
printSection = document.createElement('div');
printSection.id = 'printSection';
document.body.appendChild(printSection);
}
var elemToPrint = document.getElementById(elem);
// clones the element you want to print
var domClone = elemToPrint.cloneNode(true);
printSection.innerHTML = '';
printSection.appendChild(domClone);
window.print();
window.onafterprint = function () {
printSection.innerHTML = '';
}
};
You have to return the $http call in printBarCode and use a .then like so:
//Barcode method this should call after saving the data and returned the sampleId
vm.printBarCode = function(sampleId) {
return $http.get("master/barcode/"+sampleId).then(function (response) {
vm.barCodeImage = response.data.result;
});
}
myDataPromise.then(function(result) {
console.log("data.name"+ JSON.stringify(result));
return vm.printBarCode(result.sampleId)
}).then(
function() {
printElement("printThisElement");
},
function(error) {
// error handler
}
);
printElement will now wait for the printBarCode promise and .then to fulfil before executing.
You also don't have to use a $q.defer when doing a $http call, $http is already a promise so you can just return that like so:
function saveSample(data) {
return $http({method:"POST", data:data, url:Constants.API_URL_SAVE_SAMPLE_COLLECATION})
.then(
function(result) {
return result.data;
},
function(error) {
// don't forget to handle errors
}
);
}
First of all, $http internally implements promises you you dont have to explicitly create them.
Secondly, you should put all your http requests in the service/factory
The modified code looks like
angular.module('app.services')
.factory('NurseService', function($http){
var service = {
saveSample : function(data){
//first http implementation here
return $http.post(....);
}
getBarcode : function(sampleId){
//http implementation here for barcode
return $http.get(....);
}
}
return service;
});
and your controller can use the service like
angular.module('app.services')
.controller('saveSampleCtrl',function($scope,NurseService){
var postData = {
//your post data here
}
NurseService.saveSample(postData)
.then(function(data){
//read sampleId here from data
var sampleId = data.sampleId;
NurseService.getBarcode(sampleId)
.then(function(){
//your print statement here
});
});
}
there might be typos in the code but this is just a basic idea on how you could do that. Hope it helps

Angular variable in factory?

In a Angular app i have a couple of calls to a WebAPI service.
The first call, lets call it call1, should determine a true/false value of a variable.
So i have this
vm.call1.$promise.then(function (data) {
$rootScope.variable1 = data.variable;
});
This variable is to be used inside a factory i have;
myApp.factory('myStore', function ($http, $q, $rootScope) {
var showAll = $rootScope.variable1;
var get = function () {
if (showAll) {
//do this
} else {
//do this
}
};
return {
get: get
};
});
My problem is, that the factory above is loaded on pageload, and before the promise, and therefore the value is undefined.
How can i get the value, over to my factory, after the promise is complete?
No rootscope example: You can set the showAll flag manually:
vm.call1.$promise.then(function (data) {
myStore.setShowAll(data.variable);
});
and in the Factory:
myApp.factory('myStore', function ($http, $q) {
var showAll = 'true or false to be a default';
var get = function () {
if (showAll) {
//do this
} else {
//do this
}
};
var setShowAll = function(value) {
showAll = value;
};
return {
get: get,
setShowAll: setShowAll
};
});
Rootscope example: If you for some reason really need to use $rootScope for this you can just check for $rootScope value when you get, you don't have to store the value in a varibale.
myApp.factory('myStore', function ($http, $q, $rootScope) {
var get = function () {
if ($rootScope.variable1) {
//do this
} else {
//do this
}
};
return {
get: get
};
});

How to wait for a promise resolution?

I need to wait for a promise resolution.
function myFunction(myService, projectId) {
var localdata;
var myDataPromise = myService.getData(projectId);
myDataPromise.then(function(result) {
localdata = result;
});
var someResult = someProcess(localdata); // I need to wait for promise resolution.
return someResult;
}
UPDATE
I try to clarify my question.
I have the myService service with function which return promise:
var getData = function (projectId) {
return projectResource.getProjectUser({ projectId: projectId }, function (result) {
return result;
}).$promise;
};
You don't need a local variable ...
function myFunction(myService) {
return myService.getData().then(function(result) {
return result;
});
}
and your caller would be:
myFunction(myService).then(function(result){
//you can be sure that result is fully computed here
console.log("Your result " + result);
})
You don't want to return data from a promise!
You do want to return a promise in order to "continue" the chain.
The wait you are looking for is the callbacks you attach to the promise.
function myFunction($scope, myService) {
var myDataPromise = myService.getData();
myDataPromise.then(function(result) {
// this is the "wait" your looking for..
$scope.data = result;
console.log("data.name"+$scope.data.name);
});
return myDataPromise; // return the promise
}

multiple method call same single service with cachefactory in angularjs

I have a service like below... which always get all types of buyers from server.
var buyersService = function ($http, $q,$cacheFactory) {
var serviceBase = '/api/OMData/';
var BuyersFactory = {};
buyersService.cache = $cacheFactory('cacheId');
BuyersFactory.GetBuyers = function (type) {
var buyersDiffer = $q.defer();
var dataList = buyersService.cache.get('BuyerData');
if (dataList != null && dataList.length > 0) {
buyersDiffer .resolve(_getBuyerByType(type,dataList));
}
else {
$http.get(serviceBase + 'GetBuyers').then(
function (results) {
buyersService.cache.put("BuyerData", results.data);
buyersDiffer .resolve(_getBuyerByType(type,results.data));
});
}
return buyersDiffer .promise;
}
app.factory('OMDataService', ['$http', '$q', '$cacheFactory', buyersService]);
});
function _getBuyerByType(Type,dataList) {
try {
var typedBuyer= Enumerable.From(dataList).Where(function (x) {
return x.Type== Type;
}).ToArray();
return typedBuyer;
} catch (e) {
throw e;
}
}
function getLocalBuyer(){
return BuyersFactory.GetBuyers(1);
}
function getForeignBuyer(){
return BuyersFactory.GetBuyers(2);
}
There are two types of buyer in my business. Such as localBuyer and foreignBuyer. In my controller I need to call two service at a time with Q.All. When two service hit in buyersService method then system call server two times. Hence current cash is empty. But I want that system call server one times for one service call and second service get data from cache.
EDIT: Controller code
function loadDefaultData() {
try {
$q.all([
OMDataService.getLocalBuyer(),
OMDataService.getForeignBuyer(),
]).then(function (data) {
$timeout(function () {
//set dropdown list
viewData.local= data[0];
viewData.foreign= data[1];
}, 0);
}).catch(function (e) {
showError(e);
});
} catch (e) {
showError(e);
}
}
I would suggest defining a variable to save the promise returned by $http. The first time the service is called, that variable is initially undefined. It is set to the promise returned by $http.
The logic of your service thus becomes:
if cache, return cache
if promise, return promise
else call server and save promise
I removed you deferred variable. It is no more needed. I did wrap the cache response in $q.when() (doc: https://docs.angularjs.org/api/ng/service/$q)
var buyersService = function ($http, $q, $cacheFactory) {
var serviceBase = '/api/OMData/';
var BuyersFactory = {};
buyersService.cache = $cacheFactory('cacheId');
var serverPromise; // Will be used to store the promise returned by $http on first server call
BuyersFactory.GetBuyers = function (type) {
var dataList = buyersService.cache.get('BuyerData');
function serverCall () { // stores promise receives by $http and return it
serverPromise = $http.get(serviceBase + 'GetBuyers').then(
function (results) {
buyersService.cache.put("BuyerData", results.data);
return _getBuyerByType(type, results.data);
});
return serverPromise;
}
if (dataList !== null && dataList.length > 0) {
return $q.when(_getBuyerByType(type,dataList)); // auto resolving promise
}
// If a first call to the server was already done, serverPromise will exist and no further call to the server will be made
return serverPromise || serverCall();
};
app.factory('OMDataService', ['$http', '$q', '$cacheFactory', buyersService]);
});
function _getBuyerByType(Type,dataList) {
try {
var typedBuyer= Enumerable.From(dataList).Where(function (x) {
return x.Type== Type;
}).ToArray();
return typedBuyer;
} catch (e) {
throw e;
}
}

Resources