Updating scope on form submit - angularjs

I have a form that upon submit will POST a message to our REST API.
If successful, the REST API will return the updated value in the same JSON format as the GET call makes.
For some reason, even after the POST call has finished, the {{escalation.policy}} is still not updated in the scope.
var escalation = Escalation.save({
policy: $scope.policy,
}).$promise.then(function (data) {
$scope.escalation.push(data);
alert(data);
},

Is your REST request coming in then function? Try to put error function next to then() and make sure your request is successfully executed and responded back.

You need to call $scope.$apply() after $scope.escalation.push(data);. That will cause a new $digest to occur forcing the view to update, my guess is that $promise.then is ocurring outside the usual digest loop.

This is the current full segment of code for the submit()
$scope.submit = function () {
var Escalation = $resource('/api/escalation');
var escalation = Escalation.save({
policy: $scope.policy,
}).$promise.then(function (data) {
$scope.escalation.push(data);
}, function (error) {
alert('This request could not be processed. Please try again later.');
console.log(error);
});
};
The API will always return in the following format for a GET or POST:
{"policy":"Whatever the current/new policy is."}
Alas, i can still not seam to figure out why the view will not update.

Related

Use of AngularJS Factory for Authentication

New to AngularJS.. I want to build a simple Logon screen using a logon page, utilising a controller (I call it 'AccessCtrl') and service.
I want the controller to make use of a service (I called it 'AuthService'), which will perform the REST call that verifies the username/password, and, will also contain information about the success or failure of that logon attempt.
I want to receive information about the last login attempt (as returned in by the REST call). For now - just a string which I want to show on the logon screen, (eg 'password invalid' or 'account expired', or 'welcome'). I'm making this a property of the AuthService service which I hope to display.
My view, has a form with username, password and a submit button that calls the controller's login() method. I'm not including it here for brevity. I don't think thats where the problem lies.
To start with, I want to capture when the server is down/unavailable, etc, and also report this, using the same service. To start with - all calls will fail,(because I have an invalid url).
The controller is defined like this:
angular.module('loginApp')
.controller('AccessCtrl', ['$scope','$http','AuthService',
function ($scope,$http,AuthService,Config) {
this.login =function() {
var user={user:this.username,password:this.password,otherCredentials:this.otherCredentials} ;
AuthService.login(user);
this.message=AuthService.message;
};
}]);
My factory service is defined as follows:
.factory('AuthService', ['$http', function ($http) {
var authService = {};
var apiRootUrl="http://somesite.com/urany";
authService.login = function (credentials) {
authService.message="";
$http.post(apiRootUrl+'/login', credentials)
.then(
function (response) {
// populate OK message
authService.message="Welcome !";
},
function (response) {
// Currently - all calls fail, as the URI is invalid
// I want to trap this.
authService.message = "Server unavailable with response status = " + response.status ;
return authService;
},
function(response) {
// this is the notify callback function.
//
});
};
authService.isAuthenticated = function () {
// rerurn true or false if previously authenticated
return true;
};
return authService;
}])
;
The problem is that my invalid message ('Server unavailable with response status...') does not appear in my view.
In stepping through the code, the correct authService function is called, but, this does not seem to be populated into the controller/view.
I have a feeling this is a timing issue, where the controller that is executing
this.message=AuthService.message;
before the call actually comes back from the post - but I'm not sure that is the case or how to fix that.
any help/clues welcome.
thanks.
S
Have you tried something like this?
Angular Service Code:
//call the service
AuthService.login(user).then(function(response){//begin call back
//store the response data message object property returned from the service
$scope.message = response.message;
}//end call back

AngularJS ngResource delete event not calling callback

I have this code:
dogsResource.delete({id: $stateParams.dogId}, angular.noop,
function(value, responseHeaders){
//Success
console.log(value);
console.log(responseHeaders);
},
function(httpResponse){
//Error
console.log(httpResponse);
}
);
The delete is done, the problem is that neither success nor error is being called. I've also tried using an instance (that means, to use $delete), but it didnt work either.
I tried testing the callbacks with other methods, such as get
$scope.dog = dogsResource.get({id: $stateParams.dogId}, function(value, res){
console.log(value);
});
And it works. I don't know why that happen, since the dog is being deleted from database.
Thanks
UPDATE
dogResource code
// Return the dogs resource
.factory('dogsResource', ['$resource', function($resource){
return $resource("http://localhost:5000/dogs/:id",{id: "#id"},{update: {method: "PUT"}});
}])
UPDATE 2
I Found the error. It was in the RESTful API (Node js). The method was not sending anything to Angular, so no callback was triggered:
//DELETE - Delete a dog with specified ID
exports.deleteDog = function(req, res) {
console.log('DELETE' + req.params.id);
Dog.findById(req.params.id, function(err, dog) {
dog.remove(function(err) {
if(err) return res.status(500).send(err.message);
console.log('Succesfully deleted.');
res.status(200);
})
});
};
Replacing res.status(200) with res.status(200).end() got the callback triggered.
Thanks you all for your time.
I suggest to you to not use
res.status(200).end()
In fact usually when you delete an object with a REST service in expressJS, the common case is to send the deleted object as response, because it could be useful for the frontend to get this object (and to make sure that it's the good object).
So instead of use
res.status(200).end()
use
res.send(dog)
Or if you want to send an empty response, the status code for a delete operation should be :
res.status(204).end()
204 NO CONTENT
Note that you don't need to set the status code by default it will be 200. So set status code to 200 is just useless.
And to finish an http response needs to be sent to close the request. The end method or the send method make that. Set a status code to a response http will never send anything to the frontend. That's why your angular callback was never fired.
So i suggest to you to add the tag expressjs to your question, because it's not an AngularJS problem but a real expressJS mistake.
In your code, the second argument is angular.noop:
dogsResource.delete({id: $stateParams.dogId}, angular.noop,
function(value, responseHeaders){
//Success
console.log(value);
console.log(responseHeaders);
},
function(httpResponse){
//Error
console.log(httpResponse);
}
);
According to the ngResource Source Code, if you set the second argument to a function (angular.noop is a function) then it will use the second argument as the success callback. Since the second argument is a no-operation, nothing will happen when it is called.
Try setting the second argument to function (r) { console.log (r) } and see what you get.
I'm recently working with ngResource. In my case, I've have used three parameters in that api call. Therefore, you could use
dogsResource.delete({id: $stateParams.dogId}, function(value, responseHeaders){
//Success
console.log(value);
console.log(responseHeaders);
},
function(httpResponse){
//Error
console.log(httpResponse);
}
);
I hope that helps.
Use promise return by the $resource object. As $resource object by default return a promise object, and that promise object is available .$promise variable over that $resource API method.
Code
dogsResource.delete({id: $stateParams.dogId}).$promise.then(function(data)//Success
console.log(value);
},
function(httpResponse){ //Error
console.log(httpResponse);
});

Angularjs analogue of jQuery .always()

I want to make a HTTP request to my server and can't find the answer on my question how to make .always() like in jQuery style.
According Angular's documentation of $http, there is only this construction:
// Simple GET request example :
$http.get('/someUrl').
then(function(response) {
// this callback will be called asynchronously
// when the response is available
}, function(response) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
There's the finally():
$http.get('/someUrl').
then(function(response) {
// this callback will be called asynchronously
// when the response is available
}.catch(error) {
// called asynchronously if an error occurs
// or server returns response with an error status.
}).finally() {
//Always do something
});
Which will always be called no matter what the outcome is.
You can read about this in the documentation for $q here.

How to handle a single 404 in AngularJS's $q

I have a couple chained $http combined with a single $http using $q.all([prmiseA, promiseB]). Everything is working fine, I get the data back and errors are handled no problem.
Except that on occasion data won't be found on a particular http call and it is not an error.
I am using a service to separate the logic from the UI. And my call looks like this
$scope.Loading = true;
var p = Service.Call(Param1, Param2);
p.then(function () {
$scope.Loading = false;
}, function (reason) {
$scope.Loading = false;
$scope.alerts.push({ msg: "Error loading information " + Param1, type: "danger" });
})
What I would like to be able to do is handling the 404 on that one URL inside the 'Service.Call' function. So that the UI code above remains untouched.
My problem is that if I add an error handler to the specific call that may return a 404. Then all errors are "handled" and so I loose errors for that one call.
Is there a way to "reraise" in $q?
Is there a way to "reraise" in $q?
Yes, you can rethrow by returning a rejected promise from the handler:
return $q.reject(new Error("Re Thrown")); // this is an actual `throw` in most
// promise implemenentations
In case an $http call 404 is not an error, you can recover from it. One of the cool features of promises is that we get to recover from errors:
var makeCallAndRecover(url){
return $http.get(...).catch(function(err){
// recover here if err is 404
if(err.status === 404) return null; //returning recovery
// otherwise return a $q.reject
return $q.reject(err);
});
}

JSONP request issue

Recently I have replaced xmlHTTPRequest with a JSONP request for my web service calls, but I found that I'm getting errors due to it. I could see that JSONP is a little slower.
initialize:function(){
this.callParent();
var jsonObject = Ext.create('MyProj.library.webservice').makeJSONPRequest('top_categories_json');
Ext.getCmp('categoryList').setData(jsonObject.info);
console.log(jsonObject.info);
}
makeJSONPRequest: function(urlx, postparams) {
Ext.data.JsonP.request({
params:{
params: Ext.JSON.encode(postparams)
},
success: function(result) {
console.log('JSON RES');
console.log(result.info);
if (result) {
//return JSON.parse(result);
return result;
} else {
Ext.Msg.alert('Error', 'There was an error retrieving the weather.');
}
}
});
}
I could see that after executing the makeJSONPRequest call, it executes the next stateemnt without waiting for the JSONP request to finish, so jsonObject becomes undefined. After that error the JSONP request finishes and prints the value. Anyway to suspend the main thread until the JSONP request finishes.
No. Calls to your service are async. You really need to put all logic in the callback handler. Or generates an event after you receive a response and handle that event.

Resources