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
});
Related
Stuck with a simple basic login problem here. My AuthService factory has following code inside of it (2 relevant functions and a local variable):
var username = '';
function login(uname, upwd, utype) {
// create a new instance of deferred
var deferred = $q.defer();
$http({
method: 'POST',
url: '/root',
headers: {
'Content-Type': 'application/json'
},
data: {
username: uname,
password: upwd,
type: utype
}
}).success(function(data, status, headers, config) {
if (status === 200) {
user = true;
username = data.username;
usertype = data.usertype;
deferred.resolve();
} else {
user = false;
deferred.reject();
}
})
.error(function(data, status, headers, config) {
user = false;
deferred.reject();
});
// return promise object
return deferred.promise;
}
function getusername() {
return username;
}
My controller looks like this:
angular.module('smApp').controller('rootloginController', ['$scope', '$location', 'notificationFactory', 'AuthService',
function($scope, $location, notificationFactory, AuthService) {
$scope.submit = function() {
AuthService.login($scope.rEmail, $scope.rootPassword, 'root')
if (AuthService.isLoggedIn()) {
$location.url('/dashboard');
notificationFactory.success('Logged in as ' + rootEmail);
} else {
//ngNotifier.notifyError($scope.rEmail);
notificationFactory.error('Invalid username & password combination');
}
};
};
}]);
I am calling my getusername() in the if statementright after login() and since login has $http post it's asynchronous and I think im hitting a wall here.
So my main problem here is the first click always gives me error message and the second clicks logs me in. I am assuming this has to do with the promise not being fulfilled right away and taking some time to execute. I was wondering if there was anyway around this? I really dont have any other code to execute beside wait since this is a login page and using a timeout doesnt seem like the proper way to do it.
In this case you need to use the Promise API. Calls to the server made via the $http service return a promise, which allow binding of .success and .error methods.
The .then method may be used as a shorthand for both .success and .error. It accepts two functions that it executes in success and error scenarios respectively. Returning a promise in those functions allows chaining calls to the server.
In most cases, this should suffice:
// In service
login: function () {
return $http.post('your:url').then( // `then` here is optional, but possible
function () {}, // update service values without having to involve the controller (and/or transform the response object)
function () {} // throw error log mesages
)
}
// In controller
$scope.submit = function () {
AuthService.login().then(
function () {
// success logic: redirect, assign scope variables, etc
},
function () {
// error logic: allow retry
}
);
}
You have to call AuthService.isLoggedIn() after the login request has been completed. For this, first return the promise of the deferred object you created.
function login(uname, upwd, utype) {
// create a new instance of deferred
var deferred = $q.defer();
$http({
method: 'POST',
...
return deferred.promise;
}
Now, you can wait for the request to complete.
AuthService.login($scope.rEmail, $scope.rootPassword, 'root').finally(function() {
if (AuthService.isLoggedIn()) {
$location.url('/dashboard');
notificationFactory.success('Logged in as ' + rootEmail);
} else {
//ngNotifier.notifyError($scope.rEmail);
notificationFactory.error('Invalid username & password combination');
}
});
I have the following function named getvalue. It is inside an AngularJS module together with a controller. I am trying to call this function on click event invoking another function in a controller.(I hope I am clear)
function:
function getvalue(Data, $http) {
var value=undefined;
$http({
url: /myurl,
method: "GET",
params: {
tmp: Data.tmp,
pressure: Data.pressure
}
}).success(function (data, status, headers, config) {
value=parseFloat( console.log(data));//console working here
return value;
});
return value;
}
Code inside Controller
value= getvalue(formData, $http );
alert(value);//undefined here. Seems like value is never changed.
I have not getting the value on alert but console is printing the value. I need help if possible for two issues.
How can I change the value from inside success and return to controller?
Is there any way that I don't have to inject $Http from controller to function?
-----It would be nice if I can do that for unit testing.
you would ideally want to pull the $http service out of the controller and make a factory to do those calls.
in the factory have a function that accepts the data you are wanting to send and have it return the promise back to the controller
something like this
Repo
app.factory("fooRepo", ["$http", function($http){
return {
getValue: function(data){
return $http({
method: "POST",
url: "/myUrl"
});
}
};
}]);
Serivce
app.factory("foo", ["$q", "fooRepo", function($q, fooRepo){
return {
getValue: function(data){
var deferred = $q.defer();
fooRepo.getValue(data)
.success(function(results){
//do some work
deferred.resolve(results);
})
.error(function(error){
// do some work
deferred.reject(error);
});
return deferred.promise;
}
}
}]);
here is the controller
app.controller("fooCtrl", ["foo", function(foo){
foo.getValue(dataHere)
.then(function(results){
// do something here
});
}]);
Added Plunkr
As you are calling a method which is doing async call, you must return promise from there as you don't know when data will get back from the ajax. On success of that ajax you should update your variable. Outside of ajax function you will get undefined value because value is returned in async manner.
Function
function getvalue(Data) {
var value=undefined;
return $http({
url: /myurl,
method: "GET",
params: {
tmp: Data.tmp,
pressure: Data.pressure
}
})
}
Controller
getvalue(formData).success(function (data, status, headers, config) {
console.log(data);//you will get data here
});
A $http-Request is async. That means that alert will be called before the .success(..) callback is executed.
You can see a result on the console because it reflects changes made after the call of console.log().
Calling alert(value); in the .success()-Callback will shield the desired result.
Replace:
}).success(function (data, status, headers, config) {
value=parseFloat( console.log(data));//console working here
return value;
});
with:
}).success(function (data, status, headers, config) {
alert(parseFloat(data));
});
I have a factory returning an object calling an internal resource containing JSON as so:
.factory('cardFactory', function ($q, $http) {
return {
getOtherStuff: function () {
var deferred = $q.defer(),
httpPromise = $http.get('/static/cards.json');
httpPromise.then(function (response) {
deferred.resolve(response);
}, function (error) {
console.error(error);
});
return deferred.promise;
}
};
});
In my controller I call it like this:
var cardSuccess = function(data, status, headers, config) {
$scope.cards = data.data;
};
cardFactory.getOtherStuff()
.then(cardSuccess, cardError);
In the browser $scope.cards in populated but on the device it doesn't populate.
Any ideas why?
Hmm.., not sure.
I have it in a different way in my Ionic app, working great.
.factory('cardFactory', function ( $http ) {
var promise;
var cards = {
getOtherStuff: function() {
if ( !promise ) {
// $http returns a promise, which has a then function, which also returns a promise
promise = $http.get( '/static/cards.json' ).then(function (response) {
// The then function here is an opportunity to modify the response
// The return value gets picked up by the then in the controller.
return response.data;
});
}
return promise; // Return the promise to the controller
}
};
return cards;
})
Then, on the controller, calling it by:
$scope.getData = function() {
// Call the async method and then do stuff with what is returned inside our own then function
cardFactory.getOtherStuff().then(function(d) {
$scope.cards= d;
});
}
$scope.getData();
Hope it helps.
[EDIT:] Could it be the $http.get url, being relative? Have you tried with an absolute url?
Replace $scope.cards=data.data with "$scope.cards=data"
var cardSuccess = function(data, status, headers, config) {
$scope.cards = data;
};
try removing the leading slash in your url for $http. Try using 'static/cards.json' instead of '/static/cards.json'
I actually had the same problem and this fixed it for me. Hope it helps!
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.
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.