Return Statement not Waiting on Promise - javascript

I have a service. Lets say that this returns the string "B".
I have the following controller:
$scope.output;
var someVariable = 'A';
$scope.setUpConnection = function (someVariable) {
$scope.output = createConnection(someVariable);
console.log($scope.output);
}
createConnection = function (someVariable) {
var result;
service.connect(someVariable).then(function success(response) {
result = response.data;
}, function error(response) {
result = 'Error' + response;
});
return result;
}
The createConnection() function jumps to the end of the function, not waiting for the .then, returning nothing and as such returning undefined. Can someone explain why it isn't waiting for the promise to finish?
The service isn't the problem, if I replace the return with a direct
$scope.output = response.data;
it works fine. The problem and the reason it's set up like this is that the createConnection() function will eventually take place in a seperate JS file once I get around to moving it, so the solution above won't work. As such I figured I'd need the return statement.

This will not work because at the time you return the result promise is not resolved. you have to unwrap the promise inside the setUpConnection
$scope.setUpConnection = function (someVariable) {
service.connect(someVariable).then(function success(response) {
$scope.output = response.data;
}, function error(response) {
$scope.output = 'Error' + response;
});
}

Related

AngularJS: returning data from a function and assigning it to a variable

I am new to angularjs, and I am trying to return the data from a function to another function, and store it in a variable.
$scope.myNameValidate = function(name){
$scope.friendsList = $scope.getAllFriends(name);
console.log("data", $scope.friendsList);
}
$scope.getAllFriends = function(name){
friendService.getAllfriends(name)
.then(function(data){
//success
console.log(data);
}, function(err){
//error
})
}
I want to store all the objects in a variable but I get undefined as result.
output in console
data undefined
[Object, Object, Object, Object, Object, Object]
You need to know the Angular promise.
This issue related to Asynchronous operation.
You can fix it with proper thenable chaining.
You can do it in this way.
$scope.myNameValidate = function(name) {
$scope.getAllFriends(name)
.then(function(data) {
$scope.friendsList = data;
console.log(data);
}, function(err) {
//error
});
}
$scope.getAllFriends = function(name) {
return friendService.getAllfriends(name)
}
Why its' undefined?
Your function $scope.getAllFriends() is not returning anything witch can set data to $scope.friendsList.
function myFunc(){
var i = 5;
}
var myVar = myFunc();
myVar will not have value 5.
function myFunc(){
var i = 5;
return i;
}
var myVar = myFunc();
In angular even if it's asynchronous data when you set to $scope as
soon data has arrived angular will update your view and scope.
You cannot use async callbacks this way. In your particular case you should set $scope.friendsList inside the success callback.
$scope.myNameValidate = function(name) {
$scope.getAllFriends(name);
}
$scope.getAllFriends = function(name) {
friendService.getAllfriends(name)
.then(function(data) {
$scope.friendsList = data;
console.log("data", $scope.friendsList);
}, function(err){
//error
})
}
$scope.myNameValidate = function(name){
$scope.friendsList = $scope.getAllFriends(name)
.then(function(data){
//here is your data
})
.catch(error){
//Error
}
console.log("data", $scope.friendsList);
}
$scope.getAllFriends = function(name){
var promise = friendService.getAllfriends(name)
.then(function(data){
return data;
}, function(err){
//error
})
return promise;
}
This is asynchronus call thats why you got undefined

Javascript Promises on Angular Controller

I don't familiar with JavaScript Promises function.
Currently I have this code on my Angular Controller
$http.get('pages/about.html').then(function(response) {
var raw_html = response.data;
$scope.aboutHTML = raw_html.replace(/</g,"<");
});
I want to re-write the code so I could do something like this
$scope.indexHTML = getHTML('pages/index.html');
$scope.aboutHTML = getHTML('pages/about.html');
...
with function like this
function getHTML(url){
$http.get(url).then(function(response) {
var raw_html = response.data;
return = raw_html.replace(/</g,"<");
});
}
How to write the the code properly for the function above?
[Update #1]
Temporary Solution by #charlietfl
function getHTML(url){
// return the promise
return $http.get(url).then(function(response) {
var raw_html = response.data.replace(/</g,"<");
return raw_html;
});
}
getHTML('pages/index.html').then(function(raw_html){
$scope.indexHTML = raw_html;
});
I wanna to write this function to reduce the manual work, with this way I still need to write down $scope.{page} for each page, so anyone know better way?
[Update #2]
Solution by #joeytwiddle
function getHTML(url){
// return the promise
return $http.get(url).then(function(response) {
var raw_html = response.data.replace(/</g,"<");
return raw_html;
});
}
getHTML('pages/index.html').then(function(raw_html){
$scope.indexHTML = raw_html;
});
There is no way to just return the result, because the result will not be available until some time in the future. #asynchronous
You can only handle the result using a callback function.
If you want to minimize the work from outside, I would suggest something like this:
getHTMLAndStore('pages/index.html', $scope, 'indexHTML');
getHTMLAndStore('pages/about.html', $scope, 'aboutHTML');
function getHTMLAndStore(url, object, property) {
$http.get(url).then(function(response) {
var raw_html = response.data;
var weird_html = raw_html.replace(/</g,"<");
object[property] = weird_html;
}).catch(console.error.apply(console));
}
This is pure JS and not really related to Angular.
Note that these two requests will fire in parallel, not in sequence.
$http returns a promise so you need to return that promise from the function and use another then() to assign the scope variable:
function getHTML(url){
// return the promise
return $http.get(url).then(function(response) {
var raw_html = response.data.replace(/</g,"<");
return raw_html;
});
}
getHTML('pages/index.html').then(function(raw_html){
$scope.indexHTML = raw_html;
});
Currently your function doesn't return anything

Returning new Object from Service that uses $resource

I am working on making my existing code a bit better and I would like to have two objects for interacting with a RESTful API.
Previously, I used $http to get get the data and return the promise. I would then .then some actions to it. Then I would requery to get additional data and repeat it. So there were several nested $http queries. I would like to avoid that if possible.
I would like to have a service (or a factory) that I can use to configure various query parameters and another object for massaging and outputting the response.
Here is what I have so far:
var solr1 = angular.module('solr', ['ngResource']);
solr1.run(function(){
console.log("Module Loaded");
});
solr1.service('solrser', function($resource,solrresult) {
console.log("In Solrser")
this.serverurl = 'url';
this.res = $resource(this.serverurl);
this.query = function (p) {
this.res.get(p).$promise.then(function(d) {
return solrresult(d);
});
}
});
solr1.factory('solrresult',function() {
return function(a) {
this.data = a;
this.ready = 0;
console.log("In Factory")
this.getdocs = function() {
console.log("Getting Data")
console.log(this.data);
return this.data.docs; //this is line 9
}
return this;
}});
Controller looks like this:
app.controller('app1cont', ['$scope', 'solrser', 'solrresult', function($scope,solrser,solrresult){
console.log("Start");
var res = solrser.query({'q':'potato'});
console.log(res)
console.log(res.getdocs())
}]);
The output looks like this:
Module Loaded solr_module.js:5
In Solrser solr_module.js:9
Start main_controller.js:6
undefined main_controller.js:9
TypeError: Cannot read property 'getdocs' of undefined
at new <anonymous> (.........../main_controller.js:10:21)
at Object.e [as invoke] (https://code.angularjs.org/1.3.1/angular.min.js:36:365)
at F.instance (https://code.angularjs.org/1.3.1/angular.min.js:75:91)
at https://code.angularjs.org/1.3.1/angular.min.js:58:287
at s (https://code.angularjs.org/1.3.1/angular.min.js:7:408)
at G (https://code.angularjs.org/1.3.1/angular.min.js:58:270)
at g (https://code.angularjs.org/1.3.1/angular.min.js:51:172)
at g (https://code.angularjs.org/1.3.1/angular.min.js:51:189)
at https://code.angularjs.org/1.3.1/angular.min.js:50:280
at https://code.angularjs.org/1.3.1/angular.min.js:18:8 angular.js:11339
In Factory solr_module.js:25
So the factory gets created after the controller resumes execution. What am I doing wrong here?
You have a timing issue.
app.controller('app1cont', ['$scope', 'solrser', 'solrresult', function($scope,solrser,solrresult){
console.log("Start");
var res = solrser.query({'q':'potato'});
console.log(res)
console.log(res.getdocs())
}]);
When you call solrser.query() it runs async to get the data. So the res is not populated with any real value until after the promise returns inside the "solrser" service. You would need to do something more like:
solrser.query({'q':'potato'},function(res) {
console.log(res);
console.log(res.getdocs());
}); // could be done as a promise as well....
Separately, you also are doing something really strange when the response is called inside the solrser service.
this.query = function (p) {
this.res.get(p).$promise.then(function(d) {
return solrresult(d);
});
}
Calling return from within the promise handler is not going to do you very much. You need to either call a callback or resolve a deferred. Something like this would work better:
this.query = function (p,callback) {
this.res.get(p).$promise.then(function(d) {
callback(solrresult(d));
});
}
Or as a promise
this.query = function (p) {
var defer = $q.defer();
this.res.get(p).$promise.then(function(d) {
defer.resolve(solrresult(d));
});
return defer.promise;
}
Or you could just pass the get(p).$promise through, etc.
UPDATE:
Since this is an async action, there will always be a promise or callback. You have to do one of:
app.controller('app1cont', ['$scope', 'solrser', 'solrresult', function($scope,solrser,solrresult){
var res = solrser.query({'q':'potato'},function() {
res.getDocs();
});
}]);
Or just straight callback
app.controller('app1cont', ['$scope', 'solrser', 'solrresult', function($scope,solrser,solrresult){
solrser.query({'q':'potato'},function(res) {
res.getDocs();
});
}]);
I see missing semicolon
console.log("In Solrser")
shouldbe
console.log("In Solrser");
also missing semicolon here
console.log("Getting Data")
console.log("In Factory")
in controller you have missing semicolons too.
I think this is a reason why your code don't work.
To avoid bug like missing semicolon you can use JSHint plugin in your IDE

How to return data in a factory method within Angular?

I'm an ionic/Angular n00b and I having trouble wrapping my head around how to do this.
I have a factory defined as such:
angular.module('starter.services', [])
.factory('Calendars', function () {
var calendars;
var success = function(message) {
calendars = message;
return calendars;
};
var error = function(message) {alert("Error: " + message)};
window.plugins.calendar.listCalendars(success,error);
return {
all: function() {
return calendars;
},
get: function(calendarId) {
return calendars[calendarId];
}
}
});
And I'm trying to retrieve the calendars within my controller like this:
.controller('CalendarsCtrl', function($scope,Calendars) {
$scope.calendars = Calendars.all();
})
The factory method is being called but the results are not available until the 'success' callback is invoked so the CalendarsCtrl is always undefined.
How to solve this?
Edit - I've corrected the call within the controller. The same issue remains though, that the function does not return results until the success callback.
You will have to use a promise.
First add the dependency $q
.factory('Calendars', function ($q) {
then in all() you do this
all: function() {
var deferred = $q.defer();
window.plugins.calendar.listCalendars(function(data) {
deferred.resolve(data);
}
,function(error) {
deferred.reject(error); // something went wrong here
});
return deferred.promise;
now this will make the return after the data has been resolved (no more undefined).
One last thing, now when you get the data back at your controller you do this
var promise = Calendars.all();
promise.then(function(data) {
console.log('Success: you can use your calendar data now');
}, function(error) {
console.log('Failed for some reason:' + error);
});
You can read some more about promises here: https://docs.angularjs.org/api/ng/service/$q
I know it's hard to grasp the first time.
Angular factories are returning an object, in order to call their methods you must call them with Calendar.all() which will invoke the inner function.

To whom return is returning the value (javascript)?

I saw following code in the HotTowel project. In the following code, callback method for then returns value return vm.messabeCount = data;
(function () {
'use strict';
function dashboard(common, datacontext) {
vm.messageCount = 0;
function getMessageCount() {
return datacontext.getMessageCount().then(function (data) {
/******* Here ********/
return vm.messageCount = data;
});
}
}
})();
Am wondering why & to whom it's returning value. Is it some standard practice? Can't the code be just.
return datacontext.getMessageCount().then(function (data) {
vm.messageCount = data;
});
Or
return datacontext.getMessageCount().then(function (data) {
vm.messageCount = data;
return;
});
getMessageCount is a function returning a promise object. then method of this promise returns another promise again. It makes possible to chain multiple then parts. Each then(function() { ... }) has an ability to modify a data to be passed to the next then invocation. So this construction:
return datacontext.getMessageCount().then(function(data) {
return vm.messageCount = data;
});
means to modify a data passed to resolve callbacks. Without this return success functions would be resolved with undefined value, while we need it to be resolved with data.

Categories

Resources