I need to execute a function which is defined in controller in load-time, in order to gain json data from another place right after page is loaded.
I've tried to call the func immediately within controller, now i feel it was bad idea.
When something bad is happen and exception is raised - the controller stops working.
Well, not big surprise, but at the moment i don't have idea how work it out.
Ofcourse, i can wrap possible dangerous code in try-catch, but that's definetely not best solution imho.Here's the sample code:
app.controller("ServerStatusCtrl",
function($scope) {
$scope.reloadFunc = function()
{
throw "dat bad exception";
}
$scope.reloadFunc(); // Let's pretend that it's needed 2 call this function in load-time.
});
And example on jsfiddle
I advice you to use $q's way of notifying that something happen: return promise and reject it after something wrong happen.
This is the way how exception handling is done in async/promise way.
General idea is:
Instead of returning result, function should return promise
When you have your data ready (loaded from server) you resolve promise
If something bad happen you reject it.
function someFunc() {
var d = $q.defer();
do.somethingAsync(function(result) {
if (somethingWrong) d.reject(result);
else d.resolve(result);
});
return d.promise;
}
And in controller:
$scope.myData = someFunc().then(function ok(result) { return ok.data; }, function faled() { handle...});
This gives a good control on error handling/recovery.
Found easier solution for this.
Just discovered a ngInit directive which solved the whole problem.
Also, i think that module.run(fn) would be also applicable for this kind of tasks.
Related
Take a look at this method returned in a factory:
fetchEmployeeList: function() {
var q = $q.defer();
$http.get('/Employee/')
.success(q.resolve)
.error(ajaxErrorHandler.handleError);
return q.promise;
}
The author of this code says that this is the model we should use for returning data from HTTP endpoints. Basically, any time we need data from a service, we should use this pattern. The author is under the impression that this is preferred over returning $http.get()'s return value instead.
I don't understand the point of this code, though. I thought $http.get() does return a promise.
Can someone explain what this example snippet is doing or what they think the author might be trying to do?
That's the deferred anti-pattern, which practically warps a promise when not needed.
in your case returning a q.promise seems like an abuse since the HTTP object can return a promise itself.
I'd refactor the code to the following:
fetchEmployeeList: function() {
return $http.get('/Employee/');
}
you can take a look to this blog post for more reference as well,
don't be afraid to open a discussion with whoever is suggesting that approach.
I'm new in AngularJS so if the question is not 'intelligent' for you, please don't rate it in negative. If someone ask a question, for he isn't stupid.
So..
I would like to use data from an ajax request, like this:
encryptApp.factory('getData', function($http, $rootScope) {
var getData = {};
getData.tot_of = function() {
return $http.get('/path/to').then(function(result) {
return result.data;
});
}
getData.get_info = function() {
return $http.get('/path/to').then(function(result) {
return result.data;
});
}
return getData;
});
In controller I use this:
getData.get_info().then(function(get_info) {
$scope.get_info = get_info;
});
// HERE THE $scope.get_info is UNDEFINED
I'm new in AngularJS and I don't know why does this. So, is there a method that I can use the json data outside the " then function ".
Thanks and please don't rate this question negative. Sorry if my english is not good.
$http.get returns a promise.
By essence, a promise is as Javascript saying:
"Hey ! I let you make the request, but please, I don't want to wait for you, so when you finished, please execute the callback I'm just passing you, since now, I will forget you since I have more code to execute while you're doing your job".
In other words, a promise's callback isn't executed immediately, since the goal is to not block the Javascript "thread" (Javascript is like single-threaded).
So your current code is acting like this:
getData.get_info().then(function(get_info) { //the function inside this "then" IS the callback
$scope.get_info = get_info;
});
// Hey !! The request might not finish ! So don't expect $scope to have the value you expect here !
So the simple example to illustrate would be to imagine that your ajax request takes 100ms to execute.
Within those 100ms, your next Javascript scope is very very very likely to be already reached, having $scope.get_info not initialized yet.
Without promise, your next code, outside of the callback, that should not depend of $scope.get_info, would have to wait 100ms to start, wasting time.
So, is there a method that I can use the json data outside the " then
function ".
There is a way, using broadcasting/emit ($rootScope.$broadcast/$rootScope.$emit) to trigger a corresponding event, but it's often more "anti-KISS" for a simple case.
I advise you to put all your depending code in the promise callback.
To clean your code, merely call a private function that you define outside the callback.
I have a function in my controller that calls an api to retrieve some values:
$scope.Refresh= function(){
$http.get('/get/value')
.success(function(data) {
//some actions
})
.error(function(data) {
//some actions
});
} ;
I want to refresh the values occasionally, so I've done:
setInterval($scope.Refresh, 100000);
I will do in a better way, but now I want to solve this.
but there is a problem:
If, in the controller, I say: $scope.Refresh (to execute the function first time), the controller does nothing.
If I write the same function + setInterval (to test and run it) it works first time (outside the function), but never refresh next times (code function inside), to explain, that execute the function but neither .success nor .error is called.
I have seen the headers with a 304 status (not modified) but the values are modified!!
I tried to disable cache but that did not fix the problem.
I tried to give a random value to the route like: /get/value/(randomNuber) but I get nothing
Where is the problem?
Just running:
$scope.Refresh();
should definitely run the function at least once. If it doesn't something is wrong with your code or with your server route. But you should be getting a console error if that's the case.
For setInterval, you should be using the $interval service that ensures your code is run within the angular loop.
Also, per the documentation, you should explicitly cancel this interval when your controller is destroyed.
var httpInterval = $interval($scope.Refresh, 100000);
$scope.$on('$destroy', function() {
$interval.cancel(httpInterval);
});
I've only had intermittent luck with .success and .error, and I'd like to think that part of it was caching the request. I have very consistent, successful results using .then, as shown:
$scope.Refresh= function(){
var myGet = $http.get('/get/value');
myGet.then(function(data){
//do success things here
}, function(data){
//do error things here
});
};
Other than that, follow the advice that #theJoeBiz gave regarding $interval and you should be fine.
i'm using angularJS and SLIM PHP restful server, the PHP service is working and actually i have already used $http.get() with no problems in this application ...
But now a strange thing is happening, i created a new function in the same way that the others, and it get .success(function(data)) with no problems, i actually can console.log(data) and it shows the right results, but when .success() finish and return, i recieve a undefined result.
ps: there is no error in browser console.
var markerOptions = [];
loadMarkers();
console.log(markerOptions);
function loadMarkers() {
$http.get('http://localhost/rest/getMarkers').success(function(response){
console.log(response);
markerOptions = response;
});
}
Console.log() inside success() return the right data
Console.log() after loadMarkers() return undefined
#MarcKline's comments are correct. Anyways, following what I think you're trying to achive by this piece of code of yours, you can assign the returned data from the ajax response to a scope variable (assuming you're using $scope), e.g $scope.markerOptions = response. You can declare markOptions as a scope variable by var $scope.markOptions = [] (...and, of course, log it by console.log($scope.markOptions) accordingly). Also, define $scope.loadMarkers = function() {...} and call it by $scope.loadMarkers()
The scope will be updated as soon as the client-side gets its ajax response.
Hope it helps your current needs in addition to a better understanding of javasciprt's async approach that some of its principles were explained to you by the comments.
I found this snippet of code that does what I want it to:
var promise = this.model.save();
$.when(promise).then(function() {
console.log(promise.responseText);
});
I want to get back the responseText from my Backbone call to this.model.save(). This code was documented here. But it's not logging anything, even if I pull a raw text string in the console.log() call.
Could someone please explain in layman's terms what a jQuery promise is? I've read about them, but I don't think I quite got what they were. That might help me understand why this code isn't working for me. If I console.log(promise) in between the first and second lines of code, then I get the responseText. So something is happening in either the $.when or the then that is causing this to go wrong.
EDIT:
After reading the article, I discovered I could do this:
var promise = this.model.save();
$.when(promise).then(null, function(obj) {
console.log(obj.responseText);
});
But I don't understand what the null represents. then seems to take two parameters, a success function and a failure function. But wouldn't the success function be first? I get a 200 response from the server.
So first off, I'm pretty sure you don't need the when part; from the jQuery docs:
The jqXHR objects returned by $.ajax() as of jQuery 1.5 implement the
Promise interface, giving them all the properties, methods, and
behavior of a Promise (see Deferred object for more information).
Since Promise has a then method already, you can just do:
this.model.save().then(null, function(obj) {
console.log(obj.responseText);
});
(The fact that the above code almost reads like an English sentence is a major advantage of using Deferreds, for me at least.)
As for your null argument, the docs are again pretty clear. There are three signatures for then (and that's just to cover the different jQuery versions; any given version has less):
deferred.then( doneFilter [, failFilter ] [, progressFilter ] )
deferred.then( doneCallbacks, failCallbacks )
deferred.then( doneCallbacks, failCallbacks [, progressCallbacks ] )
As you can see, all three take the "done" function first, and the failure function second. This does seem to imply that you're getting a failure, which is confusing. One way to avoid the problem is to not use then at all. Instead, try the following:
this.model.save().always(function(obj) {
console.log(obj.responseText);
});
That will make your function get called no matter what happens. However, you probably should figure out what's going on, so you might want to instead add a success and failure callback to do some debugging:
this.model.save().done(function() {
// Success case
}).fail(function() {
// Failure case
});
Because this.model.save returns a promise, you can do the following instead:
this.model.save()
.done(function(response) {
console.log("Success!");
})
.fail(function(response) {
console.log("Error!");
});
(That's easier than the whole $.when bit.)
My guess is that although your response is returning a 200 code, it is still "failing" because the response data type doesn't match up with what you're expecting (what's set in the dataType attribute in the $.ajax call).
I am a big fan of using promise, and I think the promise means very similar things in different packages.
To answer your question, which previous answers didn't, the "then" function is a function of a promise, the "when" function is a fail-save, incase the object is not a promise, a "when(obj)" will make sure it is a promise, so that you can use the elegant xxx.then(success(){},error(){}).
btw, the "deferred" that machineghost said is the package that let you use promise.
For starting to know promise and how to use it. check out this tutorial. It explains every thing very clearly, it is the article that made me so into promises.
http://strongloop.com/strongblog/promises-in-node-js-with-q-an-alternative-to-callbacks/
Now, as machineghost said, it seems your sync call is getting an error, according to a REST API documentation,https://parse.com/docs/rest# (don't know if it is the same as backbone), the server will response a JSON object for a "create" request in this format:
{"createdAt": "2011-08-20T02:06:57.931Z","objectId": "Ed1nuqPvcm"}
My guess is, maybe your server did not respond the request with the correct JSON, so the save() think the operation failed because there was no "createAt" field, event thought your sever did created the item.