How to access the updated below $scope value? - angularjs

$scope.widgettype = ' ';
$scope.getwidgettype().then(function (data) {
$scope.widgettype = data;
$scope.showdimaxis = data === 'bubble';
});
console.log($scope.widgettype);
As new to angularjs, I am just stucked over here.
Console.log is returning blank value (not the updated one).
How to access the value of $scope.widgettype (updated value) in some other function? Is there any other method to achieve this?
Your help realy appreciated!

Code on angularjs are asynchronous. So
$scope.getwidgettype().then(function (data) {
$scope.widgettype = data;
$scope.showdimaxis = data === 'bubble';
});
take some milliseconds to be performed.
Try to shift console.log inside the then clause.
$scope.widgettype = ' ';
$scope.getwidgettype().then(function (data) {
$scope.widgettype = data;
$scope.showdimaxis = data === 'bubble';
console.log($scope.widgettype);
});

To use widgettype outside of your current function, you need to return a Promise (which $http already does) and resolve it every time you need to retrieve the value.
For example:
$scope.widgettype = ' ';
var promise = $scope.getwidgettype().then(function (data) {
$scope.widgettype = data.data; // `.then` wraps it in an object, so you need `.data`
$scope.showdimaxis = data.data === 'bubble';
return data.data; // return the value within a Promise
});
And use it elsewhere as:
promise.then(function(data){ // resolving it every time we need `data`
console.log(data); // we returned `data.data`, so this time `.data` is not needed
})
It's best to write a Service/Factory for this, which might return it like this:
return this.getwidgettype().then(function(response) { // return a promise
return response.data; // and return your data
});

Related

Always return data from service

I have a series of services that either fetch data from an API server, or return data if it exists in local storage.
.factory('LogEntryResource', function(config, $resource) {
return $resource(config.apiUrl + 'logentries/:id/');
})
.factory('LogEntry', function(localStorageService, LogEntryResource) {
var localLogEntries = localStorageService.get("logEntries");
return {
all: function() {
if(localLogEntries){
return localStorageService.get("logEntries");
} else {
return LogEntry.query(function(data){
localStorageService.set("logEntries", data);
return data;
});
}
},
get: function(logEntryId){
...
},
delete: function(logEntryId){
...
},
update: function(logEntryId){
...
}
}
})
The problem is that in the app controllers sometimes a promise is returned, and sometimes the data is returned, so I need to handle the return value of LogEntry.all() to either wait for the promise to resolve or to use the data.
I'm not really sure how to go about it because I can either use a .then() which works for the promise, but is undefined if it has data, or vice-versa. I know I'm doing something wrong and looking for advice how to handle this situation of dealing with either data or a promise being returned.
.controller('LogEntryCtrl', function($scope, LogEntry) {
// var data = LogEntry.all();
// var promise = LogEntry.all();
$scope.logEntry = ???
}
I'm hoping there's a nice reusable solution instead of having to do a check to see what it is every time I use this code in my controllers/routes
// trying to avoid doing this
var logEntry = LogEntry.all();
if(logEntry.isPromise){
// do promise stuff here
} else if(logEntry.isData {
// do data stuff here
}
My suggestion would be always return a promise. You can use $q.resolve() to create a shortcut for a resolved promise
.factory('LogEntry', function(localStorageService, LogEntry, $q) {
var localLogEntries = localStorageService.get("logEntries");
return {
all: function() {
if(localLogEntries){
return $q.resolve(localLogEntries);
} else {
return LogEntry.query(function(data){
localStorageService.set("logEntries", data);
// update variable also
localLogEntries = data;
return localLogEntries ;
});
}
},
In controller you always use then() this way
LogEntry.all().then(function(data){
$scope.data = data;
});

Promise array for Q.all

I have an array of links, which I get in first request. My goal is to go to every link to gather data. So I want to make a promise for every request, push them all into an array and then pass to Q.all to resolve all the promises. The problem is I can't return promise and go to the next link
Here is the function, where I tried to make multiple requests and gather data
function arrayPromise(linksArr){
function collectingData(elem){
var deferredNew = Q.defer();
var url = elem;
request(url, function(error,response,html){
if(error){
deferredNew.reject(error);
}
var $ = cheerio.load(html);
var title, content;
$('.entry-title').filter(function(){
var data = $(this);
var title = data.text();
items.text.push(
{ titleof: title }
)
})
$('.entry-content ').filter(function(){
var data = $(this);
var content = data.html();
items.text.push(
{ contentof: content})
})
deferredNew.resolve(items);
})
console.log("Returning the promise");
return defferedNew.promise;
}
var promiseArr;
console.log("LENGTH:");
console.log(linksArr.length);
for (var i = 0; i < linksArr.length; i++) {
console.log(linksArr[i]);
var tempPromise = collectingData(linksArr[i]);
console.log(tempPromise);
promiseArr.push(tempPromise);
};
return promiseArr;
}
And how I try to use it
var linksPromise = fetchLinks();
linksPromise.then(function(arr){
console.log("LINKS PROMISE RESOLVED");
Q.all(arrayPromise(arr)).then(function(data){
console.log("SUCCESS RESOLVING ALL PROMISES")
console.log(data);
},function(err){
console.log("ERROR RESOLVING ALL PROMISES", err);
});
},function(err){
console.log(err);
})
promiseArr should be declared as an array:
var promiseArr = [];
If that doesn't fix it, please provide the error that you might be seeing.
There are MULTIPLE problems
First is in
deferredNew.resolve(items);
items is defined in a local scopes not defined anywhere in scope where deferredNew.resolve(items); evaluated.
Another: Assigning empty array to promiseArr would help too.
One more: request(url, function(error,response,html) is not assigning result anywhere and your function has no return statement where you think you return promice deferredNew.resolve(items);
PS
There are more erros, check that all your function return value, for example $('..').filter(...) does not reurn values

How to assign promise to scope

How to assign $promise to $scope.advertiserName? In the below example, Console.log($scope.title) returns "undefined".
Restangular.all('advertiser').one("?id=" + 1).getList().then(function(data) {
$scope.advertiserName = data.name;
$scope.advertiserId = data.id;
});
$scope.title = $scope.advertiserName;
$scope.id = $scope.advertiserId;
We can use callback function to execute lines of code after getting response of ajax call.You can visit this blog for awesome explanation of call back function http://javascriptissexy.com/understand-javascript-callback-functions-and-use-them/. Lets understand it through code.
$scope.setNameId = function (title,id,callBackFunction) {
Restangular.all('advertiser').one("?id=" + 1).getList().then(function(data) {
// $scope.advertiserName = data.name;
$scope.title= data.name;
// $scope.advertiserId = data.id;
$scope.id=data.id;
callBackFunction();
});
}
$scope.setNameId($scope.title,$scope.id,executeAfterResponse);
var executeAfterResponse=function(){
//code that you want to execute when value of $scope.title and $scope.id has changed
};
We can also do it by this approach
$scope.setNameId(executeAfterResponse);
Without passing $scope.title and $scope.id variable in argument of $scope.setNameId function as $scope variables can be accessed directly inside same file.
Commented lines of code are not required as we are assigning value to $scope.name and $scope.id directly.
If I am getting you correct, this is happening because of asynchronous call.
Asynchronous means sending the request (or rather receiving the response) is taken out of the normal execution flow. In your example,
$.ajax returns immediately and the next statement, return result;, is
executed before the function you passed as success callback was even
called.
You should do it like
$scope.someFunction = function () {
Restangular.all('advertiser').one("?id=" + 1).getList().then(function(data) {
return $scope.advertiserName = data.name;
});
}
$scope.title = $scope.someFunction(); //It will give you output
Edit 1:
I read many articles for the same and what I noticed that the response of asynchronous call will be taken out from normal execution flow. Either you use restangule or $http call, both are asynchronous call. So compiler will not wait for your response. You need to tell the compiler to wait for the ajax response. What I did in one of my projects. Here is a simple example which may illustrate more.
First I declared a controller function. Like below
$scope.asynchronousCallee = function (){
$http.get('/url').
success(function(data, status, headers, config) {
$scope.myAjaData = data;
});
}
$scope.asynchronousCallee(); //Call above function just after the declaration
Simply this function will receive data from server with a get call and assign response in variable but please note this success function will be called asynchronously. So what I did, I called asynchronousCallee function just after the declaration of it. Now compiler will wait for the response of this function and after executing the function, compiler will proceed further. I hope it may help you brother :-)
In your example below you are expecting the memory reference of advertiserName and title and advertiserId and id to be maintained. However, when pulling properties off of the scope it is retrieved by value not by reference. If you wanted to make your code work you would have to do one of two things:
Restangular.all('advertiser').one("?id=" + 1).getList().then(function(data) {
$scope.advertiserName = data.name;
$scope.advertiserId = data.id;
});
$scope.title = $scope.advertiserName;
$scope.id = $scope.advertiserId;
Initialize the correct property on the scope:
Restangular.all('advertiser').one("?id=" + 1).getList().then(function(data) {
$scope.title = data.name;
$scope.id = data.id;
});
Make it a by reference update instead:
var advertiser = {
id: $scope.advertiser,
title: $scope.advertiser
}
$scope.advertiser = advertiser;
Restangular.all('advertiser').one("?id=" + 1).getList().then(function(data) {
advertiser.title = data.name;
advertiser.id = data.id;
});
Since promises through the use of angular already trigger a digest cycle the view will then be updated
Restangular.all('advertiser').one("?id=" + 1).getList().then(function(data) {
$scope.advertiserName = data.name;
$scope.advertiserId = data.id;
return { name : data.name, id : data.id };
}, function(er){
//Handle error
})
.then(function(response){
$scope.title = response.name;
$scope.id = response.id;
}, function(er){
//Handle error
});

Update AngularJS scope variables in the view

I have the following AngularJS controller function which makes a JSONP request to a webservice, gets the data as a JSON file and assigns the values to scope variables which I show in the UI by AngularJS directives such as {{variableName}}. This function works fine when I run it on page load, however it does not update the view values when I call this as a function:
$scope.getData = function(id) {
$http.jsonp( webServices.getData+'?callback=JSON_CALLBACK', config ).then( function ( response ) {
$scope.data = response.data;
if($scope.data.status == "ok") {
$scope.data.receivedData = campaign.receivedData;
}
})
}
Can anybody give me a hint on how can I make this update the values in the view (form input controls) dynamically when the JSONP call returns the values? I read about $apply() but not sure where and how to use it.
Thanks.
Does the following solution help?
$http.jsonp( webServices.getData+'?callback=JSON_CALLBACK', config ).then( function ( response ) {
$scope.data = response.data;
if($scope.data.status == "ok") {
$scope.data.receivedData = campaign.receivedData;
$scope.$apply();
}
})
Scratch what I had earlier....
In your then promise handler you have:
$scope.data.receivedData = campaign.receivedData;
but you have not defined what campaign is, I assume that you want to set something on your $scope (what you're view will bind to) that is related to campaign that resides within the data coming back from the call to webServices.getData.
do not bind to a function... bind to a value.
and: return the promise
$scope.getData = function(id) {
// return the promise....
return $http.jsonp( webServices.getData+'?callback=JSON_CALLBACK', config ).then( function ( response ) {
$scope.data = response.data;
if($scope.data.status == "ok") {
$scope.data.receivedData = campaign.receivedData;
}
})
}
// fetch that data into a variable, that you bind to.
$scope.myActualData = $scope.getData();
if you later want to call the getData again, dont just call it, asign it again to the bound variable.
$scope.myActualData = $scope.getData();

Proper way of dealing with forEach Ajax calls in Angular

I need to update the data for each object in an array using a for loop and once all the data is captured, run a function. I don't want to mix jQuery in this and do it the proper Angular way of doing
Here is what I am doing,
$scope.units = ['u1', 'u2', 'u3'];
$scope.data = null;
//get individual unit data
$scope.getUnitData = function(unit){
service.getUnitData(unit).success(function(response){
$scope.data.push({'id' : response.id , 'value' : response.value});
});
};
$scope.updateAllUnits = function(){
$scope.data = null ; //remove existing data
angular.forEach($scope.units,function(val,key){
$scope.getUnitData(val);
};
console.log($scope.data); // Need to show all the data but currently it does not as the for each loop didn't complete
};
The service is defined as.
app.factory('service',function($http){
return {
getUnitData : function(unit){
return $http({
url : myURL,
method : 'GET',
params : {'unit' : unit}
});
}
}
});
How do I receive a callback when all the pulling has been done in the for loop ?
The result of your $http(...) call is a promise. This means you can use $q.all to wait for an array of them to complete.
$scope.updateAllUnits = function(){
$scope.data = null ; //remove existing data
var promises = [];
angular.forEach($scope.units,function(val,key){
promises.push($scope.getUnitData(val));
});
$q.all(promises).then(function success(data){
console.log($scope.data); // Should all be here
}, function failure(err){
// Can handle this is we want
});
};

Resources