How to process data in controller once received in angularjs? - angularjs

Assume I have a directive that contains a form where a user can enter in the name of a fruit.
I have a FruitFindController. User enters fruit name, "Apple", clicks a button which submits to controller.
Controller calls a service "GetFruitInfo(fruit)" and passes in "Apple" as parameter.
Once the information is received, it should call a method "addToListAndDoStuff()" in order to add the fruitinfo to the list.
My issue is, in my FruitFindController (assume fruitFinder is the service)...
$scope.GetFruitInfo = function() {
$scope.foundFruit = fruitFinder.GetFruitInfo($scope.fruitField);
// should alert "Found Fruit" and call addToListAndDoStuff() method to add the foundFruit information to the list managed by another directive, "FruitList".
}
What is the best way to "wait for the information is stored into $scope.foundFruit before doing any code below and popping up the alert box?

The best way is to use a promise. In your fruitFinder service, the GetFruitInfo method would look something like this..
function GetFruitInfo(fruit) {
var delay = $q.defer();
$http({method: 'GET', url: 'http://myapi.com/getFruitInfo?fruit=' + fruit}).
success(function(data, status, headers, config) {
delay.resolve(data);
}).
error(function(data, status, headers, config) {
delay.reject(data);
});
return delay.promise;
}
This method returns a promise object that you can wait for it to resolve in your controller using the .then() method, like this..
$scope.GetFruitInfo = function() {
$scope.foundFruit = fruitFinder.GetFruitInfo($scope.fruitField).then(function(response) {
alert('Found Fruit');
addToListAndDoStuff(response);
});
}

Related

Sending array to server in AngularJS

I am starting to build a web application.
The user can select and add items to a list of fruit. The list of fruit objects is stored in an array in Javascript/AngularJS.
When the user presses the Submit button, I want the entire list of fruit to be sent to the server, where the list is then saved into a database.
I have only a basic understanding of HTTP. Would I want to POST the array? How would I do this?
I'd prefer you to go for $resource which includes in ngResource module.
While passing array inside your post call you need to mention isArray option to true inside $resource option
CODE
angular.module('app',[])
//factory will have resource object
.factory('myService',function($resource){
var postFruitData = function(){
return $resource('/savefruit', {}, {saveData: {method:'POST', isArray: true}});
}
return{
saveData: postFruitData
}
})
.controller('mainCtrl',function($scope,myService){
//this function needs to be call on post like form ng-submit
$scope.postFruitData = function(){
myService.saveData({}, $scope.data).$promise.then(function(data){
//you will get data here
});
}
});
For more info you can also take look at this SO Question
Hope this could help you. Thanks.
Here's a POST example that posts an array of fruit to the server. This code would be located inside your button click function.
$scope.fruit = [{name: 'Apple'}, {name: 'Grape'}];
// Simple POST request example (passing data) :
$http.post('/someUrl', {fruit: $scope.fruit}).
success(function(data, status, headers, config) {
// this callback will be called asynchronously
// when the response is available
}).
error(function(data, status, headers, config) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
Take a look at the angular documentation for $http. This should help you out.

How to Prime $http $cache with AngularJS

When a user logs into the main page of my site, I typically load quite a bit of data on the home page. much more than when they come to a specific url on the page. When they hit the ome page, that actually fullfills the data requests of much of the data that I grab individually when they hit a specific page.
I like how the $http module works with $cache and I'm wanting to use the knowledge of my home page hit to populate the cache of calls I know the individual page will make.
That is, as an example, my home page calls /rest/clients which returns all clients while individual pages call /rest/client/101. What I want to do is make it so that if /rest/clients is called first, then when /rest/client/101 is called an new fresh xhr call does not have to be made but the data can be gotten from the cache as if /rest/client/101 had already been called.
I've never done a decorator before but I'm thinking maybe a decorator on the $http service? I looked through the $http code and it seemed the cache is stored in closure to the actual http call and not exposed except on the next Get.
Has anyone done this or similar? I could not find it. Any specific pseudo coding suggestions would be very welcome.
In your data service you have 2 methods, getAll and getOne.
In the service define a reference to your getAll results promise.
Then in your getOne service check to see if that promise exists and if it does use it to filter out the one item that you need to satisfy your getOne need.
module.service('dataService', function($http){
var getAllPromise = null;
this.getAll = function(){
if (getAllPromise !== null){
getAllPromise;
}
getAllPromise = $http.get('clients');
return getAllPromise
};
this.getOne = function(id){
if (getAllPromise !== null){
return getAllPromise
.then(function(allData){
//logic here to find the one in the full result set
return theFoundItem;
};
}
return $http.get('clients/' + id);
};
});
I found the solution I asked for but implementing and making it testable is proving to be beyond my skills. I'm going to go with #brocco solution but for the permanent record I'm leaving the actual answer to what I was asking. I'm not marking this as the correct solution because #brocco solution is better for my real problem. So, thank you #brocco for the help.
You can see below what I'm basically doing is to create my own $cache with $cacheFactory. I then use the .put method of the new cache object to prime my cache. Then, subsequent calls to the client/1 url will get the cache'd record without ever having to call cache/1 in real live. The cache is loaded in the for loop from the first big call.
Thanks for everyones input on this.
var myApp = angular.module('myApp', []);
myApp.factory('speakersCache', function($cacheFactory) {
return $cacheFactory('speakersCacheData');
});
myApp.controller('personController', ['$scope','$http','speakersCache', function ($scope,$http,speakersCache) {
$scope.getAllSpeakers = function() {
$http.get('speakers.json',{cache: speakersCache}).
success(function (data, status, headers, config) {
debugger;
var i;
for(i=0;i<data.length;i++) {
var url = 'speaker/' + i;
speakersCache.put(url, data[i]);
}
}).
error(function (data, status, headers, config) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
};
$scope.getAllSessions = function() {
$http.get('sessions.json',{cache: speakersCache}).
success(function (data, status, headers, config) {
debugger;
}).
error(function (data, status, headers, config) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
};
$scope.getOneSpeaker = function() {
$http.get('speaker/1',{cache: speakersCache}).
success(function (data, status, headers, config) {
debugger;
}).
error(function (data, status, headers, config) {
debugger;
});
}
$scope.checkit = function() {
var x = speakersCache;
debugger;
};
}]);
If I understand you well, I have done something similar:
I have this code:
.factory('myOwnEntity', ['$filter',
function ($filter) {
var myOwnList = [];
return {
set : function (data) {
myOwnList = data;
},
get : function () {
return myOwnList;
},
find : function (id) {
return $filter('filter')(myOwnList, { itemId : id }).pop();
}
}
}
])
When I make the petition to the Web Service, I store the information like this:
$http.get(url, {
cache : true
})
.success(function (data) {
myOwnEntity.set(data);
defer.resolve(data);
});
return defer.promise;
Now, the next time I need some information, I just query my entity with the find method. Hope this is what you are looking for.

calling angularjs-service iteratively

I have an array of ids and would like to iterate over them and pass them to a service to fetch some data. But I would like to only move to the next id after the processing of the previous id has finished. After all the data has been fetched I need to call a specific function.
My code (without the iteration) wold be something like
MyService.fetch(id)
.success(function (data, status, headers, config) {
doSomething();
});
What I want to achieve is something like this but in a way which can handle an unknown number of items in my array of ids:
MyService.fetch(id).success(function (data, status, headers, config)
{
MyService.fetch(id2).success(function (data, status, headers, config)
{
doSomething();
});
});
Any ideas how to achieve this ?
thanks
Thomas
Angular comes with a lite promise library: $q.
It's actually quite simple to do.
Service
myApp.factory('theProcessor', function($q, $timeout) {
return {
fetch: function(queue, results, defer) {
defer = defer || $q.defer();
var self = this;
// Continue fetching if we still have ids left
if(queue.length) {
var id = queue.shift();
// Replace this with your http call
$timeout(function() {
// Don't forget to call d.resolve, if you add logic here
// that decides not to continue the process loop.
self.fetch(queue, results, defer);
results.push({ id: id, value: Math.floor((Math.random()*100)+1) });
}, 500);
} else {
// We're done -- inform our caller
defer.resolve(results);
}
// Return the promise which we will resolve when we're done
return defer.promise;
},
};
});
See it in action at this plunker.
Try to use following approuch:
var idsArray= [], result = [];
/// ...After filling array
function nextIteration(index) {
MyService.fetch(idsArray[index]).success(function (data, status, headers, config)
{
result.push(data);
if (++index < idsArray.length) {
nextIteration(index)
} else {
console.log('Task complete');
}
}
nextIteration(0);
You could use the $q's all() method to bundle all the promises that you define and then do something after all of them are resolved e.g:
$q.all([promise1, promise2, ...]).then(...)
You may want to consider implementing this feature in your controller or your service.
Take a look at HERE for a complete API reference and details.
UPDATE
Just thinking that your service could accept an array of ids and it could have a method which would recursively fetch the data in order that you want. Look and the following code, it's an idea so it may not work as is:
function(){
var result = [];
var fetch = function(idArr /*this is your ID array*/){
(a simple guess if what you want to do with that ID)
$http.get('yourURL?id=' + <first element of idArr>)
.success(function(data){
//some logic
result.push(data);
idArr.splice(1,0);
fetch(idArr);
});
}
}

How can set a script to run after all photos have loaded?

I have have spent hours trying all of the different methods given online but nothing works. I just simply want to load a script to run after all images have loaded. Is there something about Angular that won't allow me to do this? I'm using $routeProvider:
var photos = {
name: 'photos',
url: '/photos',
views: {
main: {
templateUrl: "views/photos/photos.html",
controller: function($scope,$http){
$http({
url: 'get/photos',
method: "POST"
})
.success(function (data, status, headers, config) {
$scope.data = data;
// this doesn't work
$(window).load(function() {
myScript();
});
})
.error(function (data, status, headers, config) { $scope.status = status; });
}
}
}
};
By the way, I'm not getting any errors in the console.
It seems to me that the http POST call retrieves the photos. And I am suppose that myScript is a function. So why not try this:
var photos = {
name: 'photos',
url: '/photos',
views: {
main: {
templateUrl: "views/photos/photos.html",
controller: function($scope,$http){
$http({
url: 'get/photos',
method: "POST"
})
.success(function (data, status, headers, config) {
$scope.data = data;
myScript();
})
.error(function (data, status, headers, config) {
$scope.status = status;
});
}
}
}
};
since the myScript function only runs after the POST succeeds. I am supposing that the data refers to the actual image data.
I don't know if I really understood what type of data you are trying to get, but I think you could try with promises
$http in Angular already return a promise wrapped in .success or .error, but you can also use the .then() callback like with every other promise
So if the problem is to wait for the success() callback to be finished you could do something this way, replacing it by several then() :
$http.post(...).then(
//function which will wait for the data to be downloaded
//here you can alter data, check some values etc...
).then(
//the script for what you want after
myScript();
);
I made a little fiddle to explain : http://jsfiddle.net/Kh2sa/2/
It simulates a long response time with $timeout, so you have to wait 3 secondes to see your modified data, which remains in its initial state until you call the myScript() function
AFAIK, Angular does not provide a way to inform us when images have finished loading.
You will need to write your own directive for this. The directive would wrap the necessary JavaScript/jQuery code that would detect the finished loading condition for one or more images.
jQuery callback on image load (even when the image is cached) and https://github.com/desandro/imagesloaded might help.

Angular.js - How to pass data from controller to view

This is the first time i am using Angular.js. So my workflow could be wrong.
How do i pass data from controller to the view
ng-view -> Displays html page using jade
When user clicks on submit button, i use $http on the controller and submit the request to the server.
The server returns me the necessary data back which i need to pass to another view.
My code snippet
function TrackController($scope,$http,$location,MessageFactory){
$scope.message = MessageFactory.contactMessage();
$scope.submit = function () {
var FormData = {
'track_applicationid': $scope.track_applicationid,
'track_email': $scope.track_email
}
$http({method: 'POST', url: '/track', data: FormData}).
success(function(data, status, headers, config) {
$scope.registeredDate = 'data.REGISTERED_DATE';
$scope.filedDate = data.FILED_DATE;
$location.path('trackMessage');
}).
error(function(data, status, headers, config) {
console.log('error');
});
}
}
In the above code, i want to pass registeredDate and filedDate to trackMessage view.
After going through the comments, i understood you are using one controller for two views.
If you want to set values to $scope.registeredDate and $scope.filedDate, You have to declare those objects globally using root-scope(Not recommended) or
use Angular values.
I recommended to use two different controllers.

Resources