AngularJS: Set private service variable in callback - javascript

I'm trying to do this:
app.service('productsService', ['$http', productsService]);
function productsService($http){
return {
getProducts: getProducts
}
var _products = [];
function getProducts(){
$http.get('http://localhost:4000')
.then(function(data){
_products = data;
});
}
}
But at the then callback _products is an undefined variable.
What is the correct way to set _products value from the then callback?

You need to set the variable before the return statement.
app.service('productsService', ['$http', productsService]);
function productsService($http){
var _products = [];
return {
getProducts: getProducts
}
//var _products = []; this will never run
function getProducts(){
$http.get('http://localhost:4000')
.then(function(data){
_products = data;
});
}
}

Related

Defer return of factory until loop is completely finished angularjs

I'm trying to make a method that returns an array of objects after getting the objects from an API. The problem is that the return from the factory happens before all the calls are finished. I've tried to use $q.defer but it still sends the return before it's ready to ship.
This is what I've come up with so far.
angular.module('watchList').factory('storageService', ['$http', '$q', function ($http, $q) {
storage = {};
storage.getMovies = function () {
var movies = localStorage.getItem('movies');
var movieArray = angular.fromJson(movies);
var newArray = [];
var defer = $q.defer();
angular.forEach(movieArray, function (id) {
newArray.push($http.get(api + id));
});
$q.all(newArray).then(function (response) {
defer.resolve(response);
});
return defer.promise;
}
This is the controller that I'm trying to make the call from
angular.module('watchList').controller('watchListController', ['$scope', 'storageService', function ($scope, storageService) {
$scope.movies = storageService.getMovies();
I want the loop to finish everything before it returns the array.
You don't need to create a promise, you can just return the promise returned by the $q.all(newArray) call.
The thing is that you cannot expect to get a result synchronously when it only becomes available asynchronously. So you need to keep with using then:
storage.getMovies = function () {
var movies = localStorage.getItem('movies');
var movieArray = angular.fromJson(movies);
var newArray = movieArray.map(function (id) {
return $http.get(api + id);
});
return $q.all(newArray);
}
storageService.getMovies().then(function(movies) {
$scope.movies = movies;
// ... other code working with $scope.movies
});
Side note: the map method does what you do with forEach, but immediately returns the array, which is quite practical.
getMovies will return immediately with a promise. You need to use "then" to wait on that promise.
$scope.movies = storageService.getMovies().then((response) => ...)

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

Cannot use .then() inside ng-click function

My controller looks like this
function menuController($scope, dataService) {
$scope.getMenuItem = '';
$scope.submenu = new Array();
var setMenuItems = function (w) {
$scope.submenu = new Array();
$.each(w, function (i, val) {
if ($scope.getMenuItem == 'year') {
$scope.submenu.push( {
name: val[0].year, link: year
});
}
});
}
$scope.UpdateSubmenu = function (a) {
$scope.getMenuItem = a;
loadData();
};
var loadData = function () {
dataService.getAlbums().then(setMenuItems);
}
loadData();
}
when loadData() is called during initialization it works fine. However when it is called from UpdateSubmenu it fails with TypeError: dataService.getAlbums(...).then is not a function
The UpdateSubmenu funtion is activated from an ng-click event.
The dataService looks like this
(function () {
"use strict";
var dataService = function ($http) {
var albums;
var getAlbums = function () {
if (albums)
return albums;
return $http.get("./api/Album").then(function (response) { albums = response.data; return albums; });
}
return { getAlbums: getAlbums };
}
angular.module("Main").factory("dataService", dataService);
}());
Why cant I use then() not accepted?
The issue is because you are caching the albums and returning that if it exists. The first time getAlbums() is called it returns the $http promise, the second time it returns an array of albums, which does not have a then() method.
I usually handle this by creating a promise using $q and instantly resolving it:
(function () {
"use strict";
var dataService = function ($http, $q) {
var albums;
var getAlbums = function () {
if (albums) {
var deferred = $q.defer();
deferred.resolve(albums);
return deferred.promise;
// ... or more simply ...
//return $q.when(albums);
}
else {
return $http.get("./api/Album")
.then(function (response) { albums = response.data; return albums; });
}
}
return { getAlbums: getAlbums };
}
angular.module("Main").factory("dataService", dataService);
}());
Instead of returning albums... return $q.resolve(albums) In short... to chain a promise (using .then() ) you must return always return a promise.

Pass a variable between two functions in a same controller [duplicate]

This question already has answers here:
Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference
(7 answers)
How do I return the response from an asynchronous call?
(41 answers)
Closed 7 years ago.
I define a variable by the name tst in controller, and i give some value in a function by the name GetOrders, but when i get tst in another function GetTotalValueOfProducts it is undefined and does not have value,this is what i do:
<script>
app.controller('OrderController', function ($scope, $http) {
$scope.quantity = 1;
$scope.Orders = {};
var tst ;
GetOrders = function () {
$http.get('/Order/GetAllOrders').success(function (response) {
$scope.Orders = response;
//here i set tst, and tst has value, i checked it has value and it's not undefined
tst = response;
});
}
GetOrders();
GetTotalValueOfProducts = function () {
//but here 'tst' is undefined!!!
var p = tst;
}
GetTotalValueOfProducts();
});
</script>
What is the problem?
This is happening because js is asynchronous.
You are executing GetOrders() as it is making http request, which will take time but before that http request finishes you are calling GetTotalValueOfProducts which makes it undefined.
<script>
app.controller('OrderController', function ($scope, $http) {
$scope.quantity = 1;
$scope.Orders = {};
var tst ;
GetTotalValueOfProducts = function () {
//but here 'tst' is undefined!!!
var p = tst;
}
GetOrders = function () {
$http.get('/Order/GetAllOrders').success(function (response) {
$scope.Orders = response;
//here i set tst, and tst has value, i checked it has value and it's not undefined
tst = response;
GetTotalValueOfProducts();
});
}
GetOrders();
});
</script>
The above should give you expected result. Not sure when you want to call the function.
Hi There AngularJS is all async so GetTotalValueOfProducts(); is getting called before success callback return any value from http. You have to call your function once the callback is completed.
You can use $q of AngularJS to accomplish it. Here is the link $q
This is a classic JavaScript async problem. Your second function is executed before the promise in the first function is resolved.
You should call
GetTotalValueOfProducts();
in success callback of $http service. Change the code like this
<script>
app.controller('OrderController', function ($scope, $http) {
$scope.quantity = 1;
$scope.Orders = {};
GetOrders = function () {
$http.get('/Order/GetAllOrders').success(function (response) {
$scope.Orders = response;
GetTotalValueOfProducts(response)
});
}
GetOrders();
GetTotalValueOfProducts = function (tst) {
var p = tst;
}
});
</script>
Try attaching tst variable into your inner $scope object.
EDIT
It was sloppy not seeing that these function are async. You should fetch your results as:
Try attaching tst variable into your inner $scope object.
EDIT
It was sloppy not seeing that these function are async. You should fetch your results as.
app.controller('OrderController', function ($scope, $http) {
$scope.quantity = 1;
$scope.Orders = {};
$scope.tst;
GetOrders = function () {
$http.get('/Order/GetAllOrders').success(function (response) {
$scope.Orders = response;
$scope.tst = response;
GetTotalValueOfProducts();
});
}
GetOrders();
GetTotalValueOfProducts = function () {
//but here 'tst' is undefined!!!
var p = $scope.tst;
}
});
Or even try to use $q

How to create my own promise?

I have two questions about promises in AngularJS:
How do I create my own promise?
See the code below:
function controller($http) {
var dataCache;
function getData(){
if( dataCache != null ){
// should return my own promise here
// to pass the value of 'dataCache' to 'then' immediately
} else {
return $http.get('...some url ...');
}
}
}
How do I return the last promise?
Code:
function controller($http) {
var urlArr = ['url1', 'url2', 'url3'];
function getDataOneByOne() {
// should call $http.get() for the url in the 'urlArr' one after another in a chain
// and return the last promise
}
}
For the second question, do Array.prototype.reduce on urlArr and build promise chain:
function controller($http, $q) {
var urlArr = ['url1', 'url2', 'url3'];
function getDataOneByOne() {
return urlArr.reduce(function (chain, url) {
return chain.then(function () {
return $http.get(url);
});
}, $q.when());
}
}
Don't forget to handle $http errors, though.
For the first question, I believe you're looking for $q.when(). It wraps a normal value in a promise and resolves it.
function getData(){
if( dataCache !== null ) {
$q.when(dataCache);
} else {
return $http.get('...some url ...');
}
}
getData.then(function() {
});
See Klaster's answer for your second question.

Categories

Resources