Hi all I am new to angular js,here I want to fetch the json from server to the controller so that I can handle the data,but whats happening here is the first alert -11 is called then alert 2 is called and in the end alert 1 is being called ,I read about promise so I tried it but still not working,I want it to happen one after another please help me .Thanks in advance
sampleApp.controller('firstpage', function ($scope, $q, $http, $templateCache, onlinedata, offlinedata) {
$scope.message = 'This is Add new order screen';
var defer = $q.defer();
defer.promise.then(function () {
$scope.method = 'POST';
$scope.url = 'http://ncrts.com/ncrtssales_compadmin/webservices/user_login';
$scope.fetch = function () {
$scope.code = null;
$scope.response = null;
alert($scope.response + 11) //alert11
$http({
method: $scope.method,
url: $scope.url,
cache: $templateCache
}).
success(function (data, status) {
$scope.status = status;
$scope.message = data;
alert($scope.message + 1) //alert1
}).
error(function (data, status) {
$scope.data = data || "Request failed";
$scope.status = status;
});
};
$scope.fetch();
})
.then(function () {
alert($scope.message + 2); //alert 2
})
defer.resolve();
//alert($scope.remember)
});
You have to use the resolve and reject functions to handle the response with the promise. You can find more information about promise in the AngularJS documentation. I made a little change in your code to show you how you can achieve what you want.
sampleApp.controller('firstpage', function ($scope, $q, $http, $templateCache, onlinedata, offlinedata) {
$scope.message = 'This is Add new order screen';
var defer = $q.defer();
$scope.method = 'POST';
$scope.url = 'http://ncrts.com/ncrtssales_compadmin/webservices/user_login';
$scope.fetch = function () {
$scope.code = null;
$scope.response = null;
alert($scope.response + 11) //alert11
var defer = $q.defer();
$http({
method: $scope.method,
url: $scope.url,
cache: $templateCache
}).
success(function (data, status) {
//$scope.status = status;
$scope.message = data;
alert($scope.message + 1) //alert1
defer.resolve({
status: status,
message: data
});
}).
error(function (data, status) {
var data = data || "Request failed";
//$scope.status = status;
defer.reject({
status: status,
message: data
});
});
return defer.promise;
};
$scope.fetch().then(function (data) {
alert('Status: ' + data.status);
alert('Message: ' + data.message);
});
});
I am very confused by the formatting of your code. It may help you to write the asynchronous call in a service and then inject the service into your controller. Keeping that in mind, here is some general advice that I've learned regarding asynchronous calls and promises in AngularJS:
Your service should initially return a deferred promise. This promise
should then be resolved on success() of the asynchronous call.
After $http() returns, but before success() returns, you have an
unresolved promise. If you have code that you want to run after the
promise is resolved, you need to use then() to indicate that you
want to execute the code within the then() block once you've
received data (and resolved the promise).
Not using then() for this
situation will cause errors because you will be attempting to access
data that doesn't yet exist.
It seems from your code that you are aware of the necessary coding strategy for what you need, but it will always help to isolate asynchronous calls into services so that the framework can make your life easier. Good luck.
Related
To resolve my issue I have gone through many articles on different sites, but none resolved it.
I'm writing a simple AngularJS application. I'm quite new to Angular. I have written a factory method which call the $http service which gets the data from the web api. Web api is running fine and its returning the JSON object as expected.
Angular Code
var app = angular.module("app", [])
.controller("controller", function ($scope, WebFactory) {
$scope.data = "data";
$scope.error = "error";
$scope.data=WebFactory.getData();
})
.factory("WebFactory", function ($http) {
var obj = {};
obj.getData = function()
{
$http({
method: "GET",
url: "http://localhost:37103/api/employee",
}).then(function success(response) {
return response.data;
})
.then(function error(response) {
return response;
});
return 'No data';
}
return obj;
});
HTML code
<body ng-controller="controller">
data: {{data}}
<br/>
error: {{error}}
<br />
I have spent 2 days, but still dont know why its not working.
Try something like this instead:
var app = angular.module("app", [])
.controller("controller", function ($scope, WebFactory) {
$scope.data = "data";
$scope.error = "error";
$scope.data = {}
WebFactory.getData().then(function success(response) {
$scope.data = response.data;
});
})
.factory("WebFactory", function ($http) {
var obj = {};
obj.getData = function()
{
return $http({
method: "GET",
url: "http://localhost:37103/api/employee",
})
}
return obj;
});
First of all, you're missing an ng-app declaration
Secondly, you are misusing the then callback. It accepts three parameters: success callback, error callback, finally callback.
As the first then executes the success, then it executes the second callback that always returns the response, but I assume it is not intended to be that way and you could use the get function which is more easy to use.
It should be:
$http.get("http://localhost:37103/api/employee").then(function(response){
//Do something with successfull response
},
function(error){ //do something with the error});
See documentation about promises
Lastly, you are dealing with promises and async code, yet returning response or string instead of the promise with the result. So the getData() should look like this:
obj.getData = function(){
return $http.get("http://localhost:37103/api/employee");
}
And use the then(success,error,finally) callbacks in the controller or if you want to provide values on the error/finally callbacks in the service, you should use the $q service
obj.getData(){
var deferred = $q.defer();
$http.get(...).then(function(response){
deferred.resolve(response.data);
},
function(error){
deferred.reject("No Data");
});
return deferred.promise;
}
Of course you would have to provide $q service to the WebFactory
I'm trying to pass data to $scope.post by doing it this way, but it doesn't want to work like I imagine it to do. I get no errors in the console and the code is inside the PostController.
var PostController = function ($scope, $location, $routeParams, $http, Post, User) {
$scope.post = {};
$scope.getById = function (id) {
return $http.get('/api/Post/' + id).success(function (data) {
$scope.post = data;
});
}
$scope.getById($routeParams.id);
console.log($scope.post);
}
Here's the routing too:
when('/post/:id', { controller: PostController, templateUrl: 'post.html' }).
Edit, whole PostController added.
getById is an async call, it's not failing, you're just not waiting! Use .then to return a promise and do the assignment in the callback:
$scope.getById = function (id) {
return $http.get('/api/Post/' + id).then(function (result) {
return result.data
});
}
$scope.getById($routeParams.id).then(function(data) {
$scope.post = data;
});
console.log($scope.post); is called before callback, so there is no values.if you want to get the value in console, try this..
$scope.getById = function (id) {
return $http.get('/api/Post/' + id).success(function (data) {
$scope.post = data;
console.log($scope.post);
});
}
$http get returns promise.
That means, that function inside success, isn't invoked at once.
It's not intuitive, but that is how promises work.
To track resulting data, insert console.log inside success function
return $http.get('/api/Post/' + id).success(function (data) {
$scope.post = data;
console.log('$scope post: ',$scope.post);
});
You will see data returned from get call to debug ( you can also print this variable in your view ).
How it works:
$http.get returns a promise, and also adds addtional success and error function.
After $http.get, you chain promise to success function
$http.get('/api/Post/' + id).success
which is called after successful server response ( http codes from 200 to 299 ), and error function is called where there is failure ( 400 - 499 codes ).
The first two answers are probably the solution to your problem... since your console.log is executing before the callback to the HTTP request. However, it is good practice to also handle HTTP errors, which could always be a problem. Here is an example of how you would do that:
$http.get('/api/Post/' + id).
success(function(data, status, headers, config) {
//handle success
}).
error(function(data, status, headers, config) {
//handle error
});
Dear AngularJS savies,
How to set $scope.data in the controller having a promise returned from a factory. All I can do is work with the data returned in the scope of the method of the factory's object and I cannot "load" the data in a value existing in the controller's scope. How can I pass the data into controller's scope?
The code sequences as following
This is the factory:
var features = {};
// the method returns a promise tot he controller needed to be delt with .then()
features.getPromise = function(){
//make a promise
var promise = $http({method: 'GET', url: '../../LIBS/inc/getAllGeoFeatures.php'})
.success(function(data, status, headers, config){
return data;
})
.error(function(data, status, headers, config){
$log.warn(data, status, headers, config);
});
return promise;
};
This is the controller:
$scope.data = 'null';
factGetFeat.getPromise().then(function(promise){
$scope.data = promise;
$log.info($scope.data); //gets the object all right
// here I can work with the data but I cannot share it with the controller
// i.e. with the view
});
$log.info($scope.data); //$scope.data is still null and I need it loaded with the data
I need some counceling because I sense I go nowhere
I even tried to load $scope.data with the outcome of the method, but I only get the promsise object and not the data:
Object {then: function, catch: function, finally: function}
Please advise.
P.S. I use angular 1.2.x
Thank you very much for your time and patience.
It should be
factGetFeat.getPromise().then(function(promise){
$scope.data = promise;
$log.info($scope.data); //gets the object all right
}).then(function(){
// here you can see $scope.data updated with a new value
$log.info($scope.data);
});
as alternative:
var promise = factGetFeat.getPromise().then(function(promise){
$scope.data = promise;
$log.info($scope.data); //gets the object all right
});
promise.then(function(){
// here you can see $scope.data updated with a new value
$log.info($scope.data);
});
.then is evaluated when 1st promise resolved
You are doing it almost right. You only need to return the promise from your service.
If I understand you question you are concerned about $scope.data being null when you call $log.info($scope.data) on the very last page. And that is perfectly correct. $scope.data will be set later, when the HTTP call is finished successfully.
If you need to do any operations only when the data arrived, you must include it success callback.
Here is how it could look like:
var app = angular.module('app',[]);
app.factory('featuresService', ['$http', '$log', function($http, $log) {
var getPromise = function() {
//create the promise, this will be returned from this function
var promise = $http({method: 'GET', url: '../../LIBS/inc/getAllGeoFeatures.php'});
//on error do some logging here
promise.error(function(data, status, headers, config) {
$log.warn(data, status, headers, config);
});
return promise;
};
return {
getPromise: getPromise;
}
}]);
app.controller('testCtrl', 'featuresService', function($scope, featuresService) {
//set initial values
$scope.data = null;
$scope.vectorAllLibs = null;
var init = function() {
featuresService.getPromise().then(function(data) {
$scope.data = data;
$scope.vectorAllLibs = convertVectorAllLibs(data);
};
};
var convertVectorAllLibs = function(data) {
return ol.source.GeoJSON({ projection: 'EPSG:3857', object: data });
};
$scope.processVectorAllLibs = function() {
if (!$scope.vectorAllLibs) {
alert('sorry, no data yet!');
return;
}
//process here
};
init();
});
I'm trying to bind some data being returned from an API to my scope using promises with $q, I am able to pull the data from the server without any issue (I can see JSON being returned using fiddler) however the $scope variable remains empty, any help would be greatly appreciated! Thanks in advance.
Code:
toDoListService.js
app.factory("toDoListService", function ($http, $q) {
var deferred = $q.defer();
return {
get: function () {
$http({ method: 'GET', url: '/api/todo/' }).
success(function (data) {
deferred.resolve(data);
}).
error(function (data, status, headers, config) {
deferred.reject(status);
});
return deferred.promise;
}
});
toDoListController.js
app.controller("toDoListController", function($scope, toDoListService){
$scope.toDoList = toDoListService.get();
});
First of all you should put var deferred = $q.defer(); in your get function, so that every get has it's own deferred object.
Second what get actually returns is a promise. So you need to access you data in this way:
app.controller("toDoListController", function($scope, toDoListService){
toDoListService.get().then(function(data){
$scope.toDoList = data;
});
});
Right now, your $scope.toDoList is bound to a promise. This means of binding used to work, but was deprecated in, I think, 1.2.
As Michael suggests, you must do:
app.controller("toDoListController", function($scope, toDoListService){
toDoListService.get().then(function(data){
$scope.toDoList = data;
});
});
Also, using $q is not required here at all, as $http returns a promise anyway. Therefore, you could just do:
app.factory("toDoListService", function ($http){
return {
get: function () {
return $http({ method: 'GET', url: '/api/todo/' });
}
};
});
You can simplify your code by using this:
toDoListService.js
app.factory("toDoListService", function ($http, $q) {
return {
get: function () {
return $http({ method: 'GET', url: '/api/todo/' });
}
}
});
toDoListController.js
app.controller("toDoListController", function($scope, toDoListService) {
toDoListService.get().then(function(response){
$scope.toDoList = response.data;
return response;
});
});
Be sure to return response in your success callback, otherwise chained promises would not receive it.
I'm implementing just a thin wrapper around $http for our REST API, and I'm wanting it to return a promise in the same way as $http does (after I massage the data).
Here's my service:
Services.service('Item', ['$http', '$q', function($http, $q){
var deferred = $q.defer();
var getSuccess = function(data, status, headers, config){
var item = angular.copy(data);
item.primaryImage = 'https://my.cdn.com/' + item.meta.images[0].s3id;
if(item.meta.source_link !== null) {
item.sourceLink = item.meta.source_link.url;
}
deferred.resolve(item, data, status, headers, config);
};
var getError = function(data, status, headers, config) {
deferred.reject(data, status, headers, config);
};
this.get = function(userID, itemID) {
$http({
method: 'GET',
url: '/api/items/' + userID + '/' + itemID
}).success(getSuccess).error(getError);
return deferred.promise;
};
}]);
But from my understanding of the documentation, I have to use .then(success, error, always) rather than .success().error().always() like I can with $http.
Is it possible to implement promises in the same way that $http does? I would love to do this
var req = Item.get($routeParams.userID, $routeParams.itemID);
req.success(function(item){
window.console.log('Got an item!', item);
});
.error(function(item){
window.console.log('Damn. It failed.')
})
This question made me search for a bit after understanding what you actually wanted.
I made a plnkr showing how I solved this: http://plnkr.co/edit/LoCuwk26MEZXsugL1Ki5
Now, the important part is:
var promise = defered.promise;
promise.success = function(fn) {
promise.then(function(res) {
fn(res);
});
return promise;
};
promise.error = function(fn) {
promise.then(null, function(err) {
fn(err);
});
return promise;
};
return promise
This code comes straight from the angular source code. So I believe it is the way to go if you want to replicate that style.
I did notice an error in your code though. All services are singletons. Which means you only create one deferred object. You should create one on each call and use that.