This question already has answers here:
How can I access a variable outside a promise `.then` method?
(2 answers)
Closed 5 years ago.
I have a factory named readingService the factory method GetLastSyncTimestamp return a DateTime from a web service, after calling the factory I have assign return DateTime in $scope.lastSyncTimestamp variable, but problem is inside the promise I can get the DateTime correctly
readingService.GetLastSyncTimestamp($scope.id).then(function(d) {
$scope.lastSyncTimestamp = d.data;
console.log($scope.lastSyncTimestamp);
});
but outside the promise I don't get any data
readingService.GetLastSyncTimestamp($scope.id).then(function(d) {
$scope.lastSyncTimestamp = d.data;
});
console.log($scope.lastSyncTimestamp);
is there any way to get data outside the promise ?
Create a service
.service('DataService', function () {
var service = {};
service.defaultvalue= "1";
return service;
})
and inject it in the controller.
Then you can use it in the promise like:
dataservice.lastSyncTimestamp = d.data;
and also outside will be working.
example:
https://github.com/leader80/angularjs-dataservice/blob/master/js/dataService.js
In this example:
readingService.GetLastSyncTimestamp($scope.id).then(function(d) {
$scope.lastSyncTimestamp = d.data;
});
console.log($scope.lastSyncTimestamp);
The promise is not returning before the console.log($scope.lastSyncTimestap); line is executed. You can either handle the data within the promise or encapsulate the functionality you wish to do with the data in a function and call that function from within the promise.
Related
This question already has answers here:
Is it bad practice to have a constructor function return a Promise?
(5 answers)
Closed 6 years ago.
I am new to javascript, I need some help understanding how promises(using bluebird) should be used. Below is my code and I want the constructor to initialize a property after property is resolved.
var getCookie = function(object, someParams) {
return connect(someParams)
.then(function(response){
self.cookie = response.cookie;//this should be done as part of object initialization.
done();
});
}
var app = function(){
var self = this;
getCookie(self);
//how to make sure that return happens after promise is resolved?
return self;
}
how to make sure that return happens after promise is resolved?
You can't. The app function will return before the promise is resolved. That is even guaranteed by JavaScript.
How to call promise object in constructor to set a property
You don't.
Instead you have something like a factory method that creates a new instance of the class, and returns a promise that resolves to the instance.
Example:
function getCookie(someParams) {
return connect(someParams)
.then(function(response){
return response.cookie;
});
}
function App() {}
function getApp() {
var app = new App();
return getCookie(params)
.then(function (cookie) {
app.cookie = cookie;
return app;
});
}
// Usage
getApp().then(function(app) {
// use app
});
One uses promises for asynchronous processes. Constructor functions are synchronous. While you can use promises in constructors, the returned instance won't be fully initialized until the promise is resolved. But your code would never know when that is.
That's why having a factory method that returns a promise that resolves to the class instance if the more reliable way.
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 3 years ago.
The community reviewed whether to reopen this question 11 months ago and left it closed:
Original close reason(s) were not resolved
I need to get the response.data out of the promise so it can be returned by the enclosing function. I know, I probably can't do it the way I've coded it because of normal JavaScript scope. Is there any way, it can be done?
The console.log at #1 produces the correct data. console.log #2 always produces 'a';
function addSiteParentId(nodeId) {
var theParentId = 'a';
var parentId = relationsManagerResource.GetParentId(nodeId)
.then(function(response){
theParentId = response.data;
console.log(theParentId); // #1
});
console.log(theParentId); // #2
return theParentId;
}
Any pointers would be appreciated.
One of the fundamental principles behind a promise is that it's handled asynchronously. This means that you cannot create a promise and then immediately use its result synchronously in your code (e.g. it's not possible to return the result of a promise from within the function that initiated the promise).
What you likely want to do instead is to return the entire promise itself. Then whatever function needs its result can call .then() on the promise, and the result will be there when the promise has been resolved.
Here is a resource from HTML5Rocks that goes over the lifecycle of a promise, and how its output is resolved asynchronously:
https://web.dev/promises/
I also don't like using a function to handle a property which has been resolved again and again in every controller and service. Seem I'm not alone :D
Don't tried to get result with a promise as a variable, of course no way. But I found and use a solution below to access to the result as a property.
Firstly, write result to a property of your service:
app.factory('your_factory',function(){
var theParentIdResult = null;
var factoryReturn = {
theParentId: theParentIdResult,
addSiteParentId : addSiteParentId
};
return factoryReturn;
function addSiteParentId(nodeId) {
var theParentId = 'a';
var parentId = relationsManagerResource.GetParentId(nodeId)
.then(function(response){
factoryReturn.theParentIdResult = response.data;
console.log(theParentId); // #1
});
}
})
Now, we just need to ensure that method addSiteParentId always be resolved before we accessed to property theParentId. We can achieve this by using some ways.
Use resolve in router method:
resolve: {
parentId: function (your_factory) {
your_factory.addSiteParentId();
}
}
then in controller and other services used in your router, just call your_factory.theParentId to get your property.
Referce here for more information:
http://odetocode.com/blogs/scott/archive/2014/05/20/using-resolve-in-angularjs-routes.aspx
Use run method of app to resolve your service.
app.run(function (your_factory) { your_factory.addSiteParentId(); })
Inject it in the first controller or services of the controller. In the controller we can call all required init services. Then all remain controllers as children of main controller can be accessed to this property normally as you want.
Chose your ways depend on your context depend on scope of your variable and reading frequency of your variable.
You have to return a promise instead of a variable.
So in your function just return:
return relationsManagerResource.GetParentId(nodeId)
And later resolve the returned promise.
Or you can make another deferred and resolve theParentId with it.
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 7 years ago.
So I am going to preface this by saying that my understanding of callback functions is limited so there is a chance I am making a beginner mistake with either callbacks or RequireJS.
Essentially, what I am looking for is the ability to access the values of the method from an API and create a variable by looping through what is contained inside the callback function. I then want to take that variable and return its value in the return portion of my RequireJS define statement. Below is a simplified example of what I am trying to do.
//call an api library then loop through to get all values for your object
define(['apiLibrary'], function (api) {
//create var that contains api method of current object
var apiMethod = api.someMethod();
//declare value var to be used inside callback
var value ='';
//call otherMethod, specifying an arguement and use callback to access contents of method
apiMethod.otherMethod('arg',function (reply) {
//loop through each value inside callback
$.each(reply.item, function (key, value) {
//add values to variable for each instance of method
value += 'the key is '+key+' and the value is'+value;
});
});
//return some values as well as the value set above for the overall define method
return {
valueFromElsewhere: 'hardcoded for example',
valueFromLibrary: value //value is '' since it is set insde a callback function
}
});
I appreciate any help I get in advance! Thanks!
EDIT:
The information on promises is extremely helpful and definitely helps me wrap my head around asynchronous functions in general but I need to return my variable data in a RequireJS return statement. There is a downstream program, that I have no control over, expecting data to be returned in a specific format that is provided by the return value of my define function.
You'll need to access the value asynchronously. A great way of handling that is a Promise:
var getValue = new Promise(function(resolve, reject) {
apiMethod.otherMethod('arg',function (reply) {
$.each(reply.item, function (key, value) {
value += 'the key is '+key+' and the value is'+value;
});
resolve(value);
});
});
return {
valueFromElsewhere: 'hardcoded for example',
getValueFromLibrary: getValue
};
You can then access it using the .then api:
foo.getValueFromLibrary.then(function(value) {
console.log('Value:', value);
});
This question already has answers here:
Any way to know if a variable is an angularjs promise?
(4 answers)
Closed 8 years ago.
There are cases when I need to check if an object is a promise or not, e.g. to show a loading indicator when getting initial data from an API which might take a couple of seconds.
So far I'm using this code snippet:
if ($scope.data.$resolved === false){
// data is a promise as it is not resolved yet
}
else{
// data is not a promise as it either never was or has been resolved
}
This seems to work well but since I'm not an Angular expert (yet) I was wondering if there's a better / recommended way to check if an object is a promise. Thanks!
You don't need to know, if the promise is already resolved. If you pass your callback into the .then, this code will be executed, even if the promise is already resolved.
And it seems like a bad practice make your method return 2 different types.
A promise or the data directly.
Just always return a promise, even if the data is fetched from the cache.
Pass it into the .resolve, where ever the data did come from.
Something like this:
function getData(){
var data = getFromCache();
if( data ) {
var deferred = $q.defer(); //Make your own promise
deferred.resolve(data);
return deferred.promise;
}else{
return $http.get("someData.json") //Return the promise from the `$http.get`
.then(function(data){
return data;
});
}
}
//inside a service PService
this.getPTypes = function(){
var types = PTypesFactory.get({});
return types.$promise.then(function(result)
{
console.log(result.groups);
return result.groups;
});
}
//inside a controller
$scope.groups = PService.getPTypes();
console log shows correct fetched REST data, but when I do
console.log($scope.groups);
I get
Object {then: function, catch: function, finally: function}
which is promise API instead of the correct resolved data.
The problem is that you trying to use a asynchronous function like it was a synchronous one.
then is a method which returns a promise.
when invoking it with a callback that callback would not be invoked immediately, only when the response get back from the server.
You can write it like so:
Service
this.getPTypes = function(callback){
PTypesFactory.get({}).then(callback);
}
Controller
PService.getPTypes(function(res){
$scope.groups = res.data;
});
Promises are used to handle asynchronous operations. The function you pass to the then method is called at some indeterminable point in time. You can't return a value from within it to some other point in execution.
Instead of calling then in your service, just return the promise:
this.getPTypes = function(){
return PTypesFactory.get({}).$promise;
}
and handle its resolution in the controller:
$scope.groups = PService.getPTypes().then(function(result) {
console.log(result.groups);
});