I have one function, I am required to print the lastlockerbalance outside the function.
var getlockerbalance = function() {
$http.get("php/selectLOCKERBALANCE.php").success(function(lockerbalance) {
$scope.lockerbalance1 = lockerbalance;
var lastlockerbalance = $scope.lockerbalance1[0].LOCKERBALANCE;
console.log(lastlockerbalance);
});
};
console.log(lastlockerbalance);
Showing error message as "lastlockerbalance is undefined".
You can't. The .success() callback won't even have been called by the time your second console.log() function is called, in fact the request $http.get() call won't even send the request until after the getlockerbalance() function returns.
What you need to do is move the code that uses the value inside the callback.
You could either return a promise and use then() or pass a callback to the function.
Promise
function getlockerbalance() {
return $http.get("php/selectLOCKERBALANCE.php").success(function(lockerbalance) {
$scope.lockerbalance1 = lockerbalance;
var lastlockerbalance = $scope.lockerbalance1[0].LOCKERBALANCE;
return lastlockerbalance;
});
};
getlockerbalance().then(function(result){
console.log(result);
});
Callback
var getlockerbalance = function(callback) {
$http.get("php/selectLOCKERBALANCE.php").success(function(lockerbalance) {
$scope.lockerbalance1 = lockerbalance;
var lastlockerbalance = $scope.lockerbalance1[0].LOCKERBALANCE;
callback(lastlockerbalance);
});
};
function printBalance(balance) {
console.log(balance);
}
getlockerbalance(printBalance);
Related
I have one Angular.js method from child controller, where it makes a call to twop parent controller methods one after another. But the second function should get the account data from from the first function and then will update call data like below:
filter.filterAccountsByProductMetrics1 = function(productWithSegmentations12) {
accountService.fetchAccountForRecordType([filter.selectedHcpHco.Name.display])
.then(function(resp) {
$scope.accountDataUpdate({
accounts: resp.data
});
var productId = null;
if(filter.selectedMySetupProduct.Product_vod__c) {
productId = filter.selectedMySetupProduct.Product_vod__c.value;
}
callService.getCallsForProductId(productId)
.then(function(calls) {
filter.filterRecords[filterType.product.value] = calls;
$scope.callDataUpdate({
calls: applyAllFilterOnCalls()
});
});
});
};
I've checked both the functions are getting called but the sequence is not maintained. How to make sure the two parent functions get called one after another.
EDIT: function accountDataUpdate:
call.accountDataUpdate = function(accounts) {
call.accounts = accounts;
getCallDetails(getCallIdsFromCallsForFilteredAccount())
.then(function() {
updateProductFrequencyTableData();
updateAccountDetailData(true);
});
updateDailyFrequencyChartData();
updateWeeklyFrequencyChartData();
updateCallFrequencyTableData();
updateAccountFrequencyData();
$timeout(function() {
$scope.$broadcast('updateDoughnutChart');
$scope.$broadcast('updateBarChart');
});
};
Modify accountDataUpdate to return a promise:
call.accountDataUpdate = function(accounts) {
call.accounts = accounts;
var promise = getCallDetails(getCallIdsFromCallsForFilteredAccount())
.then(function() {
updateProductFrequencyTableData();
updateAccountDetailData(true);
updateDailyFrequencyChartData();
updateWeeklyFrequencyChartData();
updateCallFrequencyTableData();
updateAccountFrequencyData();
return $timeout(function() {
$scope.$broadcast('updateDoughnutChart');
$scope.$broadcast('updateBarChart');
});
});
return promise;
};
Then use that promise for chaining:
filter.filterAccountsByProductMetrics1 = function(productWithSegmentations12) {
return accountService.fetchAccountForRecordType([filter.selectedHcpHco.Name.display])
.then(function(resp) {
return $scope.accountDataUpdate({
accounts: resp.data
});
}).then(function() {
var productId = null;
if(filter.selectedMySetupProduct.Product_vod__c) {
productId = filter.selectedMySetupProduct.Product_vod__c.value;
}
return callService.getCallsForProductId(productId)
}).then(function(calls) {
filter.filterRecords[filterType.product.value] = calls;
return $scope.callDataUpdate({
calls: applyAllFilterOnCalls()
});
});
};
Because calling the .then method of a promise returns a new derived promise, it is easily possible to create a chain of promises.
It is possible to create chains of any length and since a promise can be resolved with another promise (which will defer its resolution further), it is possible to pause/defer resolution of the promises at any point in the chain. This makes it possible to implement powerful APIs.
For more information, see AngularJS $q Service API Reference - Chaining promises.
I'm trying to wrap a third party library to return an object that resolves into an object that can be displayed in the view, similar to how $resource() works. I'm aware that I can manually do .then() on the promise and then set the value, but I wanted the result to seamlessly return similar to how I can do:
this.Value = $resource("/someresource").get();
How would I change the below SomeThirdPartyFunction() to return an object that resolves in the view.
Here's an example of what I'm trying to do:
angular.module('testApp', []).controller('TestController', function ($timeout, $q) {
var TestController = this;
var SomeThirdPartyFunction = function () {
var Deferred = $q.defer();
var Promise = Deferred.promise;
$timeout(function () {
Deferred.resolve("abcd");
}, 3000);
return Promise;
};
TestController.Value = SomeThirdPartyFunction();
/* I don't want to do this:
SomeThirdPartyFunction().then(function(Value) {
TestController.Value = Value;
});*/
});
And here's a plunker: https://plnkr.co/edit/HypQMkaqXmFZkvYZXFXf?p=preview
Every example I've seen using promises just wraps $http calls, but I haven't seen any examples of calling third party libraries that return promises that resolve into objects.
From the AngularJS document:
It is important to realize that invoking a $resource object method
immediately returns an empty reference (object or array depending on
isArray). Once the data is returned from the server the existing
reference is populated with the actual data.
So instead of return a promise, you can do something like this:
var SomeThirdPartyFunction = function() {
var getAComplextObject = function() {
return {
number: 42,
method: function() {
return this.number + 1;
}
};
};
var returnValue = {};
$timeout(function() {
console.log("Resolved!");
Object.assign(returnValue, getAComplextObject());
}, 1000);
return returnValue;
};
You can wrap it in a promise and make the promise part of the return value, doing that you can make it thenable (aka a Promise)
Under-the-hood, $resource uses angular.copy:
function myResourceGet(params) {
var emptyObj = {};
emptyObj.$resolved = false;
emptyObj.$promise = $http.get(url, {params:params})
.then(function(response) {
angular.copy(response.data, emptyObj);
}).finally(function() {
emptyObj.$resolved = true;
});
return emptyObj;
}
From the Docs:
angular.copy Overview
Creates a deep copy of source, which should be an object or an array.
If a destination is provided, all of its elements (for arrays) or properties (for objects) are deleted and then all elements/properties from the source are copied to it.
The $resource service only works when the data is an object or an array. It does not work with primitives such as a string or number.
Is there any way of adding a callback method to a function that calls service
in a function i am calling multiple service methods and i want to a set a callback method to that function.
I tried this but no luck
$scope.MyFunction() = function()
{
//Multiple Service calls
$scope.callService1 = service.CallService1() //returns true on success
$scope.callService2 = service.CallService2() //returns true on success
$scope.callService3= service.CallService3() //returns true on success
if($scope.callService1 && $scope.callService2 && $scope.callService3)
{
$scope.CallbackMethod ();
}
}
$scope.CallbackMethod = function()
{
alert('CallbackMethod')
}
I tried this one too but its not in sync as the service calls takes some time.
$scope.MyFunction() = function(CallbackMethod)
{
//Refer Above Code
}
CallService service Method is something simple like
$http.post('/InstStrategy/ReadAll').then(function (response) {
return true
});
Assuming that CallService1, CallService2 and CallService3 are async methods, they should return a deferred promise. For example:
this.CallService1 = function() {
// Once the result is available resolve the promise.
return $http.post('/InstStrategy/ReadAll').then(function(response) {
return true;
});
}
Now, it's time to define your function:
$scope.MyFunction = function(callback) {
var callService1 = service.CallService1(),
callService2 = service.CallService2(),
callService3 = service.CallService3();
// We want to wait for all these three methods to complete.
$q.all([callService1, callService2, callService3])
.then(function(results)) {
// Results is an array containing the results of each of your service calls.
var allTrue = true;
angular.forEach(results, function(result) {
if (!result) allTrue = false;
});
// If all the service calls where true, perform our callback.
if (allTrue) callback();
});
};
Note that the allTrue check is not really necessary, since the promises are systematically resolved with true.
I'm trying to create a service that will hold the shopping cart content of my website using AngularJS. I will then use this to make sure the reference to the cart in all controllers etc should be to the same object and synced.
The problem is that the cart content must be initialized via an ajax call. My code below does not work but it shows what I'm trying to accomplish. I would like to somehow get the list of items and return with getItems(), but if the list of items is not yet fetched then I will need to fetch for it first and promise a return. I'm trying to wrap my head around the "promise" concept but so far I have not fully got it yet.
factory('cartFactory', function ($rootScope, Restangular) {
var cart = $rootScope.cart = {};
return {
getItems: function () {
if (undefined == cart.items) {
return Restangular.oneUrl('my.api.cart.show', Routing.generate('en__RG__my.api.cart.show')).get().then(function($cart){
cart = $rootScope.cart = $cart;
angular.forEach(cart.items, function(value, key){
cart.items[key]['path'] = Routing.generate('en__RG__my.frontend.product.info', {'slug': value.variant.product.slug});
});
return cart.items;
});
} else {
return cart.items
}
},
setItems: function ($items) {
cart.items = $items;
},
removeItem: function ($item) {
cart.splice(cart.indexOf($item), 1);
},
addItem: function ($item) {
cart.items.push($item)
}
}
})
I will try to explain this in a very simplified way.
A promises is just an object that is "passed around" and we use this objects to attach functions that will be executed whenever we resolve, reject or notify the promise.
Because in Javascript objects are passed by reference we are able to refer to the same object in several places, in our case inside the service and the controller.
In our service we execute:
getItems: function () {
var deferred = $q.defer();
// do async stuff
return deferred.promise;
}
Lets say that the variable deferred above is an object more os less like this:
{
reject: function (reason) {
this.errorCallback(reason);
},
resolve: function (val) {
this.successCallback(val);
},
notify: function (value) {
this.notifyCallback(value);
},
promise: {
then: function (successCallback, errorCallback, notifyCallback) {
this. successCallback = successCallback;
this.errorCallback = errorCallback;
this.notifyCallback = notifyCallback;
}
}
}
So when we call getItems() a promise (deferred.promise) is returned and this allows the callee to set the callbacks to be executed whenever the promise changes its state (resolve, reject or notify).
So inside our controller I am setting only the resolve callback, if the promises is rejected it will happen silently because there is no errorCallback to be executed.
cartFactory.getItems().then(function (items) {
$scope.items = items;
});
Of course there is much more behind it, but I think this simplistic promise will help you get the basic idea. Be aware that cartFactory.getItems() must always return a promise, even when the items are already loaded, otherwise cartFactory.getItems().then() would break if , for example, you return an array.
Here a JSBin with your cartFactory service, I am using $timeout to simulate an async call.
Hope this helps.
I have a mocked resource that is simply an object of functions, in this case only one. This function returns another function. The code looks like this:
var mockRevivhalResource = {
tenantOptions: function tenantOptions() {
return {
post: function post() {
}
}
}
};
var RevivhalResource = mockRevivhalResource;
I am able to spy on tenantOptions() with spyOn(RevivhalResource, 'tenantOptions'); but I can't seem to spy on post() that tenantOptions() returns.
The only thing that doesn't throw an error is spyOn(RevivhalResource.tenantOptions(), 'post'); but I believe I am simply setting the spy on a new instance on the post function, but when the angular application calls RevivhalResource.tenantOptions().post(); it's calling a new instance of post because if I have console.log("test"); in the mocked post function the tests print out "test" even if I don't let the spy callThrough. But I could be wrong on that matter.
The controller code that is calling the resource is like this
$scope.fun = function fun() {
RevivhalResource.tenantOptions().post(
{...stuff...},
function success(data) {...success handler...},
function error(data) {...error handler...}
)
};
with RevivhalResource being a angularjs provider like this
angular.module('revivhal').provider('RevivhalResource', [function () {
...init stuff...
this.$get = function ($resource) {
...more init stuff...
return {
tenantOptions: function tenantOptions() {
return $resource(...path..., {...data...},
post: {method: "POST"});
}
}
}
}]);
And what I'm trying to do is using a spy to confirm that RevivhalResource.tenantOptions().post() has been called. I then need to make the spy call the success and error handlers to test that the handlers are correct.
You can refactor your mock so its build out of spies that return other spies:
var postSpy = jasmine.createSpy();
var tenantOptionsSpy = jasmine.createSpy()
var mockRevivhalResource = {
tenantOptions: tenantOptionsSpy.andReturn({post: postSpy})
};
mockRevivhalResource.tenantOptions().post()
expect(tenantOptionsSpy).toHaveBeenCalled();
expect(postSpy).toHaveBeenCalled();