AngularJS Trigger callback after ForEach - angularjs

I'm currently developing an AngularJS form which on submit pushes single or multiple participant data to an SQL database.
I'm able to push data to the SQL database, but I'm wanting to trigger a callback that redirects the user once all participant data has been successfully submitted.
At the moment on success it redirects the user but, misses the next foreach submit for the next participant.
Any and all advice would be appreciated.
AngularJS
/* Submit */
$scope.submit = function() {
var array = $scope.form.participants;
//console.log(array);
angular.forEach(array, function(value, key){
var request = $http({
method: "post",
url: 'http://xxx.co.uk/submit.php',
data: {
coachName: $scope.form.program.coachName,
contactArea: $scope.form.program.contractArea,
postcode: $scope.form.program.postcode,
programmeStart: $scope.form.program.programmeDate,
sessionDate: $scope.form.program.sessionDate,
sessionNumber: $scope.form.program.sessionNumber,
weekNumber: $scope.form.program.weekNumber,
id: value.participant.id,
attendance: value.participant.attendance,
weight: value.participant.weight,
goldBehaviours: value.participant.goldBehaviours,
stepCount: value.participant.stepCount,
creditData: value.participant.creditData,
weekOne: value.participant.weekOne,
stepOne: value.participant.stepOne,
weekTwo: value.participant.weekTwo,
stepTwo: value.participant.stepTwo,
weekThree: value.participant.weekThree,
stepThree: value.participant.stepThree,
weekFour: value.participant.weekFour,
stepFour: value.participant.stepFour,
weekFive: value.participant.weekFive,
stepFive: value.participant.stepFive
},
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
}).success(function(data) {
//console.log(data);
$location.path("/thankyou");
});
});
};
Data
{
"program":{
"coachName":"AD",
"contractArea":"Berkshire",
"postcode":"NN1",
"programmeDate":"2016-08-15T23:00:00.000Z",
"sessionDate":"2016-08-16T23:00:00.000Z",
"sessionNumber":"1",
"weekNumber":"2"
},"participants":[
{"participant":{"id":"AW01","attendance":"Did Not Attend","weight":"1","goldBehaviours":"2","stepCount":"3","creditData":"","weekOne":"4","stepOne":"4","weekTwo":"5","stepTwo":"5","weekThree":"6","stepThree":"6","weekFour":"7","stepFour":"7","weekFive":"8","stepFive":"8"}},
{"participant":{"id":"AW02","attendance":"Attended","weight":"2","goldBehaviours":"3","stepCount":"4","creditData":"","weekOne":"5","stepOne":"5","weekTwo":"6","stepTwo":"6","weekThree":"7","stepThree":"7","weekFour":"8","stepFour":"8","weekFive":"9","stepFive":"9"}}
]
}

You can inject $q to your controller/service and use $q.all method (you can also use native Javascript Promise if you're not worried about old browsers support).
The all method takes an array of promises and resolve when all promises in the array resolve (it will reject if any of the promises reject).
$scope.submit = function() {
var array = $scope.form.participants;
var promises = [];
//console.log(array);
angular.forEach(array, function(value, key){
promises.push($http({
method: "post",
url: 'http://xxx.co.uk/submit.php',
data: {
coachName: $scope.form.program.coachName,
...
...
...
stepFive: value.participant.stepFive
},
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
}));
});
$q.all(promises).then(function() {
$location.path("/thankyou");
});
};

You are telling it to redirect with each iteration, not after all iterations have been completed. Try moving your redirect like so:
angular.forEach(array, function(value, key){
var request = $http({
method: "post",
url: 'http://xxx.co.uk/submit.php',
data: {
coachName: $scope.form.program.coachName,
contactArea: $scope.form.program.contractArea,
postcode: $scope.form.program.postcode,
programmeStart: $scope.form.program.programmeDate,
sessionDate: $scope.form.program.sessionDate,
sessionNumber: $scope.form.program.sessionNumber,
weekNumber: $scope.form.program.weekNumber,
id: value.participant.id,
attendance: value.participant.attendance,
weight: value.participant.weight,
goldBehaviours: value.participant.goldBehaviours,
stepCount: value.participant.stepCount,
creditData: value.participant.creditData,
weekOne: value.participant.weekOne,
stepOne: value.participant.stepOne,
weekTwo: value.participant.weekTwo,
stepTwo: value.participant.stepTwo,
weekThree: value.participant.weekThree,
stepThree: value.participant.stepThree,
weekFour: value.participant.weekFour,
stepFour: value.participant.stepFour,
weekFive: value.participant.weekFive,
stepFive: value.participant.stepFive
},
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
}).success(function(data) {
//console.log(data);
});
$location.path("/thankyou");
});
Your redirect needs to be outside of your forEach.

Related

Angular-js $scope variable is not updated in view

I am new to angular-js and building a simple to-do application. I am creating a task and displaying the created task in a html table using ng-repeat. But the problem is that after posting the data, $scope.tasks variable is updated on controller side, but not in view. The view updates after refreshing the web page only and the task is added to html table. How can I make the view update after creating the task. Thanks in advance. Here is my code:
In my controller:
var app = angular.module('MyApp', ['ngMaterial', 'ngMessages']);
app.controller('DemoCtrl', function($scope,$mdSidenav,$mdDialog,$interval,$http,$mdToast) {
$scope.tasks = [];
_refreshTaskData(); //initial refresh
$scope.submitForm = function() {
var description = "";
var taskId = "";
$scope.formData = {
taskId: $scope.taskId,
description: $scope.description,
};
$http({
method: "POST",
url: 'savetask',
data: angular.toJson($scope.formData),
headers : {
'Content-Type': 'application/json',
}
}).then(_success, _error);
};
function _refreshTaskData() {
$http({
method : 'GET',
url : 'getTask',
}).then(function(res) { // success
$scope.tasks = res.data;
}, function(res) { // error
console.log("Error: " + res.status + " : " + res.data);
});
}
function _success(res) {
$mdDialog.hide();
console.log('in success function');
_refreshTaskData(); ;
}
function _error(res) {
//error handling
}
});
In my view:
<table>
<tr ng-repeat=" t in tasks">
<td>{{t.id}}</td>
<td>{{t.description}}</td>
</tr>
</table>
You must understand that these JS frameworks are asynchronous. Now what happens is, if you do an API call and make another API call whose result is based on the first one, the console does not wait for the result from one API and directly moves forward. SO what's happening in your case is sometimes/many times, before the POST call is served, the controller is not able to get fresh data with GET in time, thus not updating the view. What you can possibly do is enforce the GET only when POST is served
$http({
method: "POST",
url: 'savetask',
data: angular.toJson($scope.formData),
headers : {
'Content-Type': 'application/json',
}
}).then(function(res){
$http({
method : 'GET',
url : 'getTask',
}).then(function(res) { // success
$scope.tasks = res.data;
}, function(err) { // error
console.log("Error: " + err.status + " : " + err.data);
});
});
It would be best if you are sending a success message from the backend and checking before GET call
I think you are not calling _refreshEmployeeData at any point of time. If you add that instead of _refreshTaskData in your JS, then you will be able to see the result in view.
Also kindly use ng-init to call the _refreshEmployeeData in the controller. That would be the best way to initialize the fields.

Angular $resources Cancel requests : $q

I'm trying to understand...
How can I implement a requests cancell for this kind of services.
I was reading, that I shoud use $q.defer()
angular.module('App').service('TService', function ($resource, portal) {
return $resource(portal.getUrlServer() + 'api/T/:id', { id: '#Id' }, {
T_GET: {
method: 'GET',
params:{
id_turno: '#id_turno',
},
url: portal.getUrlServer() + 'api/T/T_GET/'
},
G_GET_Turno: {
method: 'GET',
params: {
id_tramite_relevado : '#Id_Tramite_Relevado'
},
url: portal.getUrlServer() + 'api/T/G_GET_Turno/'
},
});
What I want to do is when any method is called twice, I just want to let run the last called and cancel the other requests.
From AngularJS docs:
If an action's configuration specifies that it is cancellable, you can cancel the request related to an instance or collection (as long as it is a result of a "non-instance" call).
// ...defining the `Hotel` resource...
var Hotel = $resource('/api/hotel/:id', {id: '#id'}, {
// Let's make the `query()` method cancellable
query: {method: 'get', isArray: true, cancellable: true}
});
// ...somewhere in the PlanVacationController...
...
this.onDestinationChanged = function onDestinationChanged(destination) {
// We don't care about any pending request for hotels
// in a different destination any more
this.availableHotels.$cancelRequest();
// Let's query for hotels in '<destination>'
// (calls: /api/hotel?location=<destination>)
this.availableHotels = Hotel.query({location: destination});
};

Unable to send data to web api methods using angularjs

Hi I am developing one application using web api2 and angularjs. Finding hard time to send data to web api methods. I am having problem to send data as objects n PUT and POST methods. In delete and getbyid methods i am able to send single parameter but i am not able to send data as object. I am receiving null as below.
I am calling as below using angularjs.
this.saveSubscriber = function (sub) {
return $http({
method: 'post',
data: sub,
url: '/NCT_Users/',
// contentType: "application/json"
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
});
}
If i comment header and uncomment contentType in above code I am getting totally null object as below.
May i know why i am not able to bind object to model? Any help would be appreciated. Thank you.
var person = {firstName:"John", lastName:"Doe", age:46};
$http.post('url', person)
.success(function (response){
alert(response);
});
accesstoken is defined variable.you can define your variables to pass it to server
var person = {
firstName:"John",
lastName:"Doe",
age:46
};
$http.post('url', person)
.success(function (response) {
alert(response);
});
try this way.
var sub = {
User_CreatedDate: "",
UserEmailId: "",
User_Id: "",
User_MobileNum: "",
User_Name: "",
User_Password: "",
User_Role: "",
User_Status: "",
User_UpdateDate: ""
};
$http.post('/NCT_Users/', sub).success(function (response) { alert(response); });
the fields are filled by you
It happens like this because you are sending an JS Object via an 'application/x-www-form-urlencoded' header. You have to send the data as parameters, try this updated function:
this.saveSubscriber = function (sub) {
return $http({
method: 'POST',
data: $.param(sub),
url: '/NCT_Users/',
headers : { 'Content-Type': 'application/x-www-form-urlencoded' }
});
}

Adding content-type header to Angular $http request

I'm trying to send HTTP request using the following code:
var editCompanyUrl = 'http://X.X.X.X:YYYY/editCompany';
var userId = localStorage.getItem("UserId");
var token = localStorage.getItem("Token");
var companyId = localStorage.getItem("companyId");
return $http({
method: 'POST',
url: editCompanyUrl,
params: {
token: token,
userId: userId,
companyId: companyId,
companyName: $scope.companyName,
},
timeout: 500
}).then(function (data) {
console.log(data);
//Store Company ID which is used for saving purposes
//localStorage.setItem("companyId", data.data.Company.id);
return data.data.Company;
}, function (data) {
console.log(data);
})
and handler of the request on the server side accepts requests with Content-Type: multipart/form-data. How can I add this content type to the request? I've tried many advices and tips from tutorials but no success. Could you please help me? In addition to it - what should I do when I will add a file with an image to this request? Can I just add it as additional parameter of the request?
Thank you very much!
Angular POST must be like below code.
var req = {
method: 'POST',
url: 'http://example.com',
headers: {
'Content-Type': undefined
},
data: { test: 'test' }
}
it should have data:{ }
so try to put your params: inside the data and it should work.

Restangular save and retry after refresh

I'm working on an SPA that is usually online but can go offline and I have to keep a log of all requests to an API. When certain requests fail I should retry them later.
I've got a local DB to save all requests. When my app starts I retrieve them all and retry the ones marked to.
What I need is a way to config a Restangular object based on what I already sent. I have a response interceptor and I'm saving the restangular response object.
{
config: {
headers: Object,
method: "GET",
params: Object,
transformRequest: Array[1],
transformResponse: Array[1],
url: "..."
},
data: {...},
headers: {...},
status: 200,
statusText: "OK"
}
Is there a function to create a Restangular with the given config object?
Thanks
If i would doing this i would setup setErrorInterceptor
var yourLocalDb = function($http) {
var failedRequests = [];
this.store = function(request) {
this.failedRequests.push(request);
}
this.retry = function() {
var self = this;
angular.forEach(this.failedRequests,function(request) {
$http(request.response.config).then(function() {
//in case of success
self.failedRequests.splice(self.failedRequests.indexOf(request),1);
request.responseHandler.apply(undefined,arguments);
}), request.deferred.reject);
});
}
}
Restangular.setErrorInterceptor(function(response, deferred, responseHandler) {
yourLocalDb.store({
response : response,
responseHandler : responseHandler,
deffered : deffered
});
}
then when you have connection you can just call
yourLocalDb.retry();
Not tested, but it should give you clue.

Resources