How do I get response data to be used outside function?
var myVar;
uploadService.getUploadFolderId(folderId).then(function(response){
console.log("Show docs id", response.data); // I get output :)
myVar = response;
return myVar;
}).$promise;
console.log("show", myVar) // output: undefined
I did some reading and practices about global function and function hoisting but I still could not get it to work. Please help and thanks in advance.
You can utilize the Promise API in javascript. Essentially you:
Create your local variable (value below)
Create your Promise
Perform some long running task in your promise, and call resolve when you have what you want
Pass an object into the resolve handler that you want to preserve (expose outside of the `Promise)
Utilize the then(...) handler on the Promise and extract the object you resolved earlier
Example:
var value = 'Foo';
var promise = new Promise(
function(resolve, reject) {
setTimeout(function() {
resolve('Bar')
}, 1000);
});
promise.then(function(val) {
value = val;
console.log(value); // Bar
});
Related
This is my JS:
self.obj = {}
self.obj.accessErrors = function(data) {
var cerrorMessages = [];
for (prop in data) {
if (data.hasOwnProperty(prop)){
if (data[prop] != null && data[prop].constructor == Object) {
self.obj.fetch[accessErrors](data[prop]);
}
else {
cerrorMessages.push(data[prop]);
}
}
}
return cerrorMessages;
};
self.obj.fetch = {
X: function() {
// do stuff.
},
Y: function(callback) {
$http.get('/yposts/').then(
function(response) {
self.posts = response.data;
callback(self.posts);
},
function(response) {
self.posts = {};
self.obj.accessErrors(response.data).then(function(cerrrorMessages) {
callback(posts, cerrorMessages);
});
}
);
}
};
And I am getting an error pointing to this line:
self.obj.accessErrors(response.data).then(function(cerrrorMessages) {
The error says:
TypeError: self.obj.accessErrors(...).then is not a function
Any idea how to solve this?
self.obj.accessErrors(response.data) does not return a promise so therefore, you can't use promise methods on it.
If you want it to return a promise and you want that promise to reflect when all the fetch() operations are done and those operations are actually async, then you will have to make all your async code into using promises and you will have to combine them all using Promise.all() or the angular equivalent and convert from using callbacks in fetch to just using a promise. Right now, you have a mix which is difficult to program with.
The .then() construction is only needed when using Promise objects - essentially, instead of returning a value, the function returns an object that resolves to a value at some point in the future (which is then passed into the function that you pass to .then().
But you are right in that you need an asynchronous pattern to do this correctly, since fetch.Y is an asynchronous method. A good thing to do would be to create an array of promises at the beginning of your accessErrors function, like so:
var fetchPromises = [];
and then replace self.obj.fetch[accessErrors](data[prop]); with something that calls push on that array to add the promise that fetch returns to it.
Then, instead of returning accessErrors, return Promise.all(fetchPromises).
This will require some fairly significant modification to your code, however - namely, you will need to rewrite it so that it uses the Promise API instead of this callback by itself (which shouldn't be too difficult to do).
I'm writing a test using Selenium and JavaScript. I'm new to both, and also new to functional programming and promises. I'm trying to create a function that needs to do 3 things:
Click on an input
Clear the input
SendKeys to input
My current function does not work:
var clearAndSendKeys = function(driver, elementIdentifier, sendKeys) {
var returnValue;
driver.findElement(elementIdentifier).then(function(inputField){
inputField.click().then(function() {
inputField.clear().then(function() {
returnValue = inputField.sendKeys(sendKeys);
});
});
});
return returnValue;
}
The function would then be called as for example:
clearAndSendKeys(driver, webdriver.By.id('date_field'), '14.09.2015').then(function(){
//Do stuff
});
I expected the variable returnValue to contain the promise from sendKeys. However the function clearAndSendKeys returns the undefined variable before sendKeys is ran. I assume this is because returnValue was never defined as a promise, and so the program does not know that it needs to wait for sendKeys.
How can I make my function clearAndSendKeys return the promise from sendKeys? I'd rather avoid having to add a callback to the clearAndSendKeys function.
Edit: Removed .then({return data}) from the code as this was a typo.
You have to return each promise from the .then callback:
var clearAndSendKeys = function(driver, elementIdentifier, sendKeys) {
return driver.findElement(elementIdentifier).then(function(inputField){
return inputField.click().then(function() {
return inputField.clear().then(function() {
return inputField.sendKeys(sendKeys);
});
});
});
}
The promise returned by .then will resolve to the same value as the value returned from the callback.
See Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference for why your current code does not work. Promises are asynchronous.
First of all its probably not the best idea to nest promises, completely defeating their main purpose of eliminating callback hell. then callback can return Thenable object that allows to create nice chains of async operations.
In this case you just need to store reference to input field available as a result of the first async operation in the scope of the main function and then create chain of async operations that can be returned from this function.
var clearAndSendKeys = function(driver, elementIdentifier, sendKeys) {
var inputFieldRef;
return driver.findElement(elementIdentifier)
.then(function(inputField){
inputFieldRef = inputField;
return inputField.click();
}).then(function() {
return inputFieldRef.clear();
}).then(function() {
return inputFieldRef.sendKeys(sendKeys);
});
}
I have a function, getGames(), in my Angular controller which can be called by both my init() function and an update() function. I need to know whether init() or update() called this function because I treat each situation differently.
I tried to access arguments.callee.caller.toString(), but this is not allowed while in strict mode, which is a requirement for this project.
How could I access the caller of getGames() while in strict mode?
My current structure below. Obviously loadingGames.promise within updateSchedule() does not work because that promise was already resolved when init() ran. I'm struggling to refactor this so that init() and updateSchedule() each depend on a different promise resolution with regard to the same function, getGames().
var loadingGames = $q.defer();
var getGames = function() {
playersService.getGames({
playerId: playerId
}).$promise.then(function(data) {
vm.games = data;
loadingGames.resolve();
});
};
var init = function() {
getGames();
}
init();
var updateSchedule = function() {
getGames();
loadingGames.promise.then(function() {
populateOptions(vm.games);
vm.tableParams.reload();
});
};
My thought was to determine the caller at the end of getGames() then resolve a different promise based on who the caller was.
Your getGames()-function could return a promise that is resolved as soon as the games have been fetched from the server(to make my example code shorter I left out the parameter to the service and assumed that it returns a promise):
var games; //This is vm.games in your case
(function fetchGames() {
games = playersService.getGames()
.then(function(data){
games = data;
return data;
});
})();
function getGames() {
return $q.when(games);
}
function updateSchedule() {
getGames()
.then(function(theGames){
populateOptions(theGames);
tableParams.reload();
});
}
$q.when(x) returns a promise that is immediately resolved with x if x is not a promise. If x is a promise, it returns x directly.
Just a note: Your populateOptions and tableParam.reload functions look a lot like you do manual DOM-stuff. This is almost always wrong in angular - let data binding do that job for you.
I have the following function defined in a service, in which I use $http to get some data and set some of the fields of an object:
function getComplexObject () {
var complexObject = {
'A': null,
'B': null
}
$http.get('someURI').then(function(data) {
complexObject.A = data;
//Do some processing and set B
return complexObject;
})
};
So until now I've used a promise with the $http service but I don't know how to wrap the function with $q so that I can ultimately use it in the following manner:
//Using my function as a promise
myService.getComplexObject().then(function (data) {
this.complexObject = data;
})
I've searched for tutorials on angular promises but most of them simply explain what a promise is or do something similar to what I already did, I'm guessing what I want to do is possible but I can't find the right syntax or the right tutorial.
Just put return in front of the $http.get(...).then(...) chain, i.e.
return $http.get(...).then(...);
This will ensure that the result of getComplexObject is a promise that will (when its resolved) contain the value of complexObject.
That is exactly what .then is designed for - it takes the promise from $http.get() and returns a new promise that will ultimately be resolved with its own return value instead of the original one.
FWIW, I'd put the declaration of complexObject inside the .then call - there's no need for it to be in the outer scope and it'll inadvertently cause a closure over that variable.
NB: Also, be careful about using this in your final callback - it may not be what you think it is!
You could return a promise and resolve if later (see: https://docs.angularjs.org/api/ng/service/$q).
function getComplexObject () {
var deferred = $q.defer();
var complexObject = {
'A': null,
'B': null
}
$http.get('someURI').then(function(data) {
complexObject.A = data;
//Do some processing and set B
deferred.resolve(complexObject);
});
return deferred.promise;
};
I have just started using promises in attempt to cleanup some 'callback hell'.
I've decided on trying bluebird and I am running it in the browser but immediately ran into scoping problems.
Is there a way of setting the thisArg in a new Promise? The below example shows that the 'this' value inside the promise resolver is set to the browser window, but I'd like it set to the surrounding scope so I can easily access member variables.
I noticed there is a .bind() method but it only scopes the 'then()' method, not the promise. I also realize I can have 'var me = this' just before the promise and use closure, but I wanted to avoid it if possible.
function MyObject() {
this.value = 7;
}
MyObject.prototype.getValue = function () {
return new Promise(function (resolve) {
// some request/processing that takes a long time
var result = Ajax.request(...);
resolve({
value: this.value,
result: result
});
// 'this' is set to window instead of the instance,
// resulting in this.value as undefined
});
}
var obj = new MyObject();
obj.getValue().then(function (value) {
console.log(value); // preferably outputs 7
})
No, there is not. You can of course use the default approaches, but you shouldn't need to.
When doing heavy processing and getting back the value asynchronously, you want to get a promise for the value. You don't need to set the result value as a property of the original instance.
MyObject.prototype.getValue = function () {
return new Promise(function(resolve) {
// lots of processing to make a `value`
resolve(value); // no `this` at all!
});
};
In case you want to synchronously get the .value that you had set on the instance, you don't need the Promise constructor. Just use Promise.resolve to make a promise for an existing value:
MyObject.prototype.getValue = function () {
// TODO: lots of processing
return Promise.resolve(this.value);
};
Or, in your case, even Promise.method:
// TODO: lots of processing
MyObject.prototype.getValue = Promise.method(function () {
return this.value;
});
This is more a comment then an answer, as it is primary opinion based.
In the rar situations where I need this it would look like this in my code:
Ajax.requestAsync in this case would be a promisifyed version of Ajax.request.
I know this might just move your problem to another place.
MyObject.prototype.getValue = function () {
return Ajax.requestAsync(...)
.bind(this)
.then(function(result) {
return {
value: this.value,
result: result
}
});
}
Or something like this:
MyObject.prototype.getValue = function () {
var returnValue = {
value: this.value
};
return Ajax.requestAsync(...)
.then(function(result) {
returnValue.result = result;
return returnValue;
});
}
A rarely use such constructs:
MyObject.prototype.getValue = function () {
return Promise.all([this, Ajax.requestAsync(...)])
.spread(function(object, result) {
return {
value: object.value,
result: result
};
});
}