In Angular.js do some operations after the download has finished - angularjs

I have this factory that downloads some JSON data and adds it to the $scope.
myApp.factory('loadDataService', function ($rootScope, $http) {
var loadDataService = {};
loadDataService.data = {};
loadDataService.getData = function () {
$http.get('/static/data.json')
.success(function (data) {
console.log("download finish");
loadDataService.data = data;
});
return loadDataService.data;
};
return loadDataService;
});
I call the download service from my main controller like this:
$scope.data = loadDataService.getData();
// if I access the $scope.data here I get and exception because
// the data is not yet downloaded.
Once the data is download and added to the scope I need to do a bunch of operations. What is the proper way of doing a bunch of operations in your controller after your data is downloaded.

Give a callback function in getData like this:
your Factory
loadDataService.getData = function (callback) {
$http.get('/static/data.json')
.success(function (data) {
console.log("download finish");
loadDataService.data = data;
callback();
});
return loadDataService.data;
};
your Controller
$scope.someOperations = function() {
// Your operations
};
$scope.data = loadDataService.getData($scope.someOperations);
You can also use loaded event with $rootScope like this:
$rootScope.$on('data:loaded', function(e, data) {
deferred.resolve(data);
});

Related

Angularjs - Editing arrays returned from http get url

I have this array I am getting through the following method:
var url= *url defined here*;
$scope.ViewProfile = function () {
$http.get(url)
.success(function (response) {
$scope.ProfileList = response;
$scope.FavNumbers = $scope.ProfileList[0].FavNumbers;
})
.error(function () {
});
}
I am required to edit the Fav Numbers list on the UI. and post it back to another url through http post url method. What I am stuck is with the concept of asynchronous calls, due to which I am unable to retrieve the favorite numbers list to be available for editing. Please help!
I have tried a method of using promises as follows:
app.factory('myService', function($http) {
var myService = {
async: function(url) {
var promise = $http.get(url).then(function (response) {
console.log(response);
return response.data;
});
// Return the promise to the controller
return promise;
}
};
return myService;
});
In my controller I am doing:
angular.module('JuryApp').controller('mycontroller', ['myService', function (myService) {
myService.async(url).then(function(d) {
$scope.data = d;
});
app.controller('MainCtrl', function( myService,$scope) {
// Call the async method and then do stuff with what is returned inside our own then function
myService.async().then(function(d) {
$scope.data = d;
});
});
But I keep getting the error 'd is not defined'. It keeps giving an error of some sort, where the debugger goes into an infinite loop or something.
You are overcomplicating it, I think. Async calls are actually pretty simple:
You're service:
app.factory("myService", ["$http", function($http) {
var MyService = {
getData: function(url) {
return $http.get(url); //$http returns a promise by default
}
};
return MyService;
})];
Your controller:
angular.module('JuryApp').controller('mycontroller', ['myService', function (myService) {
$scope.FavNumbers = [];
var url = "http://my.api.com/";
myService.getData(url).then(function(response) {
$scope.FavNumbers = response.data[0].FavNumbers;
});
}]);
That's all that you need to do.

Store AJAX result in factory and retrieve in controller

I am currently trying to store a $http JSON request to a variable in a factory and then retrieve the value of that variable in a controller.
Currently all I receive back is undefined. I imagine the AJAX request isn't finished running before the function gets called. I am new to Angular so trying to grab any basic concepts I can and helpful knowledge.
app.factory('typiCode', function($http) {
var jsonService = {
async: function() {
var promise = $http.get('https://jsonplaceholder.typicode.com/posts/1')
.then(function(response) {
console.log(response);
return response.data;
})
return promise;
}
};
return jsonService;
});
app.controller("getJson", function($scope, typiCode) {
$scope.returnedData = typiCode.jsonService;
$scope.logResults = function() {
var theData = $scope.returnedData;
console.log(theData);
}
});
<button ng-click="logResults()">Launch data</button>
Thank you in advance!
Your typiCode factory returns your jsonService object. So you should be calling typiCode.async() somewhere in your code.
You could do, for example, like this in your controller:
app.controller("getJson", function($scope, typiCode) {
typiCode.async()
.then(function(data) {
$scope.returnedData = data;
})
$scope.logResults = function() {
var theData = $scope.returnedData;
console.log(theData);
}
});

$http.post in angularJS goes in error in without debugging mode only.in debugging mode its works fine.why?

here is my javascript code
$scope.addUser = function () {
debugger;
url = baseURL + "AddUser";
$scope.objUser = [];
$scope.objUser.push( {
"ID": '0',
"UserName": $scope.txtUserName,
"Password": $scope.txtPassword,
"Role":"Non-Admin"
});
$http.post(url,$scope.objUser[0])
.success(function (data) {
debugger;
alert("S");
window.location = "../View/Login.html";
}).error(function () {
debugger;
alert("e");
});
}
here is my server method code
[HttpPost]
public int AddUser(UserModel user)
{
//_entity.Configuration.ProxyCreationEnabled = false;
tblUser objUser = new tblUser();
objUser.UserName = user.UserName;
objUser.Password = user.Password;
objUser.Role = user.Role;
_entity.tblUsers.Add(objUser);
_entity.SaveChanges();
return objUser.ID;
}
You can use promises to get the response. this can be inside into a service and call it whenever you want to use it.
this.addUser = function (obj) {
var datosRecu = null;
var deferred = $q.defer();
var uri = baseUrl + 'addUser';
$http({
url: uri,
method: 'post',
data: angular.toJson(obj)
}).then(function successCallback(response) {
datosRecu = response;
deferred.resolve(datosRecu);
}, function errorCallback(response) {
datosRecu = response;
deferred.resolve(datosRecu);
});
return deferred.promise;
};
Also .error and .success are deprecated.
PD: the parameter data: inside the $http correspond to the body. if you want to send parameters you should use params:{}
EDIT:
Here i leave you a link how promises work. Angular promises
Basically this helps to process data asynchronously
the example above can be used inside a service like this
myApp.service('myService', function($q, $http){
// here your services....
});
the service can be injected inside to any controller to provide the data that what you want, inside of your functions
myApp.controller('myController', function($scope, myService){
$scope.list = function(){
$promise = myService.getAll(); // this will be the name of your function inside your servive
$promise.then(function(data){
console.log(data); //here you can se your promise with data like status and messages from the server.
});
};
});
Hope it helps.

Use $http once from Angular Service

I need to grab some data from my db through an API and make it accessible throughout my Angular app. I understand that Services are good for storing data to be accessed from multiple controllers. However, in the following code I end up with a new $hhtp.get() each time just to get the same data.
Service:
.factory('Playlist', ['$http', function($http) {
var playlist = {};
playlist.getPlaylist = function() {
return $http.get('api/playlist.php')
.then(function (response) {
var data = response.data;
return data;
})
}
return playlist;
}])
Controllers:
.controller('ScheduleCtrl', ['$http', 'Playlist', function($http, Playlist) {
var self = this;
Playlist.getPlaylist()
.success(function(playlist) {
self.playlist_id = playlist.id;
fetchItems();
})
var fetchScheduleItems = function() {
return $http.get('api/schedule.php/'+self.playlist_id).then(
function(response) {
if (response.data === "null") {
console.log("No items");
} else {
self.items = response.data;
}
}, function(errResponse) {
console.error('Error while fetching schedule');
});
};
}])
.controller('PlaylistItemCtrl', ['$http', 'Playlist', function($http, Playlist) {
var self = this;
Playlist.getPlaylist()
.success(function(playlist) {
self.playlist_id = playlist.id;
fetchItems();
})
var fetchPlaylistItems = function() {
return $http.get('api/schedule.php/'+self.playlist_id).then(
function(response) {
if (response.data === "null") {
console.log("No items");
} else {
self.items = response.data;
}
}, function(errResponse) {
console.error('Error while fetching schedule');
});
};
}])
Is there a way to store the Playlist ID without pinging 'api/playlist.php' from every controller?
Update
Here's a Plunkr based on Abhi's answer: http://plnkr.co/edit/or9kc4MDC2x3GzG2dNeK?p=preview
As you can see in the console, it's still hitting the server several times. I've tried nesting CachedData.save() differently, but it doesn't seem to apply.
I would say store your data locally (CachedData factory - rename it to something that makes sense) and inside your getPlaylist method, before doing http call, check CachedData to see if your data is present and if not, then do the http call.
The code will be something like the below. I have just written it free-hand, so there may be some errors, but you get the picture.
.factory('Playlist', ['$http', 'CachedData', function($http, CachedData) {
var playlist = {};
playlist.getPlaylist = function() {
if (CachedData.data) {
// return cached data as a resolved promise
} else
return $http.get('api/playlist.php')
.then(function (response) {
var data = response.data;
cachedData.save(data);
return data;
})
}
return playlist;
}])
// CachedData factory
.factory('CachedData', function() {
var _data;
var cachedData = {
data: _data,
save: function(newData) {
_data = newData;
}
};
return cachedData;
})
EDIT: Also Remove fetchPlaylistItems from the controller and put it in a factory. The controller is just a glue between your viewmodel and view. Put all your business logic, http calls in a service.
EDIT: I have setup a plunk for you here. I hope it helps.
EDIT: John, the reason you are seeing two server calls is because they are from different controllers ManiCtrl1 and MainCtrl2. By the time, the getPlaylist method from MainCtrl2 is called, the first http request didn't get the chance to finish and save the data. If you add a timeout to MainCtrl2 before calling your service method, you will see that the data is retrieved from cache. See this updated plunk for a demo.
This will be more useful in an app with multiple views, where you don't want to reload data when navigating back to a view. (Ideally, depending on the type of data you are caching, you will have some expiry time after which you would want to reload your data).
You could do some pre validation when calling that method.
var playlist = {};
playlist.playlist = [];
playlist.getPlaylist = function () {
if (playlist.playlist.length <= 0) { //or some lodash _.isEmpty()
$http.get('api/playlist.php')
.then(function (response) {
playlist.playlist = response.data;
})
}
return playlist.playlist;
};
Hope it helps!

Accessing returned scope method variables in another method in AngularJS

I have an Angular app with a service and a controller:
service.js
.factory('MyService', function ($http, $q) {
var api_url = 'http://localhost/api/';
var MyService = {
list: function (items_url) {
var defer = $q.defer();
$http({method: 'GET',
url: api_url + items_url}).
success(function (data, status, headers, config) {
defer.resolve(data);
}).error(function (data, status, headers, config) {
defer.reject(status);
});
return defer.promise;
},
...
}
});
controller.js
.controller("ItemsCtrl", function ($scope, MyService) {
$scope.getItems = function () {
MyService.list('items/').then(function(data) {
$scope.items = data;
});
};
$scope.addItems = function () {
$scope.getItems();
// why is this undefined ??!!!
console.log($scope.items);
};
The issue is that I want to call the $scope.getItems method inside the $scope.addItems method. Do I perhaps need to use $scope.apply(), as the returned value is a promise?
I think what I am displaying here is a general lack of understanding.
Change your controller like this:
.controller("ItemsCtrl", function ($scope, MyService) {
$scope.getItems = function () {
return MyService.list('items/').then(function(data) {
$scope.items = data;
});
};
$scope.addItems = function () {
$scope.getItems().then(function() {
// should be what you want this time
console.log($scope.items);
});
};
Your problem is when you call $scope.getItems(), http response is not returned yet, so $scope.items is not populated. You have to wait for all the promises are resolve to access items.
$scope.items is undefined because $http is an asynchronous communication. That is, when you call $scope.addItems(), it creates and sends the request to retrieve your list of items, then immediately moves on to the next line of code, which is to log $scope.items to the console. Since there's nothing in $scope.items yet, you get an undefined value.
If you want to operate on the data returned by the http call, you must guarantee that the data will be populated. In other words, any operations you want to perform on $scope.items should be called within your .then() block.
$scope.$apply() is used when you are not executing within an AngularJS context, to force the AngularJS framework to evaluate the expression. It will not help you here - you'll get an "$digest already in progress" error, or something along those lines.
Try this:
.controller("ItemsCtrl", function ($scope, MyService) {
$scope.getItems = function () {
MyService.list('items/').then(function(data) {
$scope.items = data;
console.log($scope.items);
});
};
$scope.addItems = function () {
$scope.getItems();
};
});
That is because $scope.getItems is asynchronous. Your callback (that added via then) is called after $scope.addItems executed.

Resources