Angular Chain HTTP is causing errors - javascript

I am trying the following code in an angular.js application to migrate data from one database to another. This is one part of the function in order to gain authorization credentials to send POSTs to the receiving database. However, it doesn't work. My first function, ATsintegrationsService.beginBackfill(clientIDs), returns the list of applicants fine. The error begins at getAuthToken(). Even though it hits the URL with the correct data, I keep on getting an error in the service. Can anyone shed some light on what is going on here, I'd really appreciate it. I'm at a loss for what may be causing my issues.
Main function (triggered by hitting an apply button):
$scope.beginBackfill = function() {
$scope.loading = true;
AtsintegrationsService.beginBackfill($scope.clientids).then(function (response) {
$scope.applicants = response.data;
$scope.getAuthToken();
$scope.createSuccess = true;
$scope.loading = false;
},
function(error) {
$scope.loading = false;
$scope.createFailure = true;
console.log("Failure to backfill data - " + error);
});
};
Here is $scope.getAuthToken():
$scope.getAuthToken = function() {
AtsintegrationsService.getAuthToken().then(function (response) {
$scope.authToken = response.data;
console.log($scope.authToken);
},
function(error) {
$scope.loading = false;
$scope.createFailure = true;
console.log("Failure to obtain auth token - " + error);
console.log(error);
});
};
And finally, the service code for getAuthToken() - some data has been removed and is indicated by {snip}.
srvc.getAuthToken = function () {
var url = {snip};
return $http({
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
responseType: 'json',
method: 'POST',
url: url,
data:
{
"grant_type": "{snip}",
"client_id": {snip},
"client_secret": "{snip}"
}
})
.success(function (data) {
console.log("We have a proper return.");
return data;
})
.error(function (data) {
console.log("There was an error in the service.");
return data;
});
};

We figured out the problem was with CORS headers; the code I have was fine.

Related

Reference error while trying make call to different end points

I am trying to call a odata end Point and check the response and make a another call to different endpoint if the condition is not met. If I don’t have the condition and making just one call to just one end point it works, but below code is throwing Reference error even with the attempt to the first call
$scope.getRequest = function () {
var url = $rootScope.BaseURL;
var config = {
headers: {
'Authorization': `Basic ${$scope.key}`,
'Prefer': 'odata.maxpagesize=2000'
}
};
$http.get(url, config)
.then(
function (response) { // success async
$scope.viewRequest.data = response.data;
},
function (response) { // failure async
console.log("There was an error getting the request from CORE");
}
);
if (viewRequest.data.REV_SAMPLE_CMQREQUEST.length = 0) {
var url = $rootScope.BaseURL + `CMQ_REQUEST('${$scope.viewRequest.barcode}’)`;
var config = {
headers: {
'Authorization': `Basic ${$scope.key}`,
'Prefer': 'odata.maxpagesize=2000'
}
};
$http.get(url, config)
.then(
function (response1) { // success async
$scope.viewRequest1.data = response1.data;
},
function (response1) { // failure async
console.log("There was an error getting the request from CORE");
}
);
}
};
Below is the screenshot of the error
$scope.getRequest = function () {
var url = $rootScope.BaseURL;
var config = {
headers: {
'Authorization': `Basic ${$scope.key}`,
'Prefer': 'odata.maxpagesize=2000'
}
};
$http.get(url, config)
.then(function (response) { // success async
$scope.viewRequest.data = response.data;
},
function (response) { // failure async
console.log("There was an error getting the request from CORE");
}
)
.then(nextViewRequest);
};
var newViewRequest = function (response) {
var url1 = $rootScope.BaseURL + `CMQ_REQUEST('${$scope.viewRequest.barcode}')`;
if ($scope.viewRequest.data.REV_SAMPLE_CMQREQUEST.length = 0) {
return $http.get(url1, config)
.then(
function (response1) { // success async
$scope.viewRequest1.data = response1.data;
},
function (response1) { // failure async
console.log("There was an error getting the request from CORE");
}
);
}
return $q.reject({ message: 'Validations didnt work' });
};
You are making 2 request in parallel rather than wait for the first one to finish and then make the second one, also the code is hard to read. My guess is that the second response is not returning anything because the first condition is not met.
I recommend you to read about promises chaining and the $q service to make custom rejections or resolve promises in your scenarios to order this logic your code should like something like this:
$scope.getRequest = function () {
// setup url and config
$http.get(url, config)
.then(nextViewRequest) // the return of this function will override the next result of the next promise chaining
.then(function(response) {
$scope.viewRequest1.data = response.data;
});
};
var nextViewRequest= function(response) {
// validations necessary
if(valid) {
return $http.get(url, config);
}
// If conditions are not met, then you can use the $q service to create a rejection
return $q.reject({message: 'validations on second request failed'});
};

Redirecting to another page prevents functions from returning their values

I have a Login page and if user logs in I want to redirect the user to another HTML page where I will list users tasks that I get from server.
The problem is:
Even though the functions I wrote works properly and backend API returns the values I want (I can see the value details on Console) when I use redirect code $window.location.href = '../Kullanici/userPanel.html the page redirects immedietly after login and for some reason I can't use the values returned by functions after redirection. Not only that I can't see the details of the value returned on console log anymore.
And here is my code for it:
Controller:
app.controller('myCtrl', ['$scope', '$http', '$window','$mdToast', 'userTaskList',
function ($scope, $http, $window, $mdToast, userTaskList) {
$scope.siteLogin = function () {
var userName = $scope.panel.loginUserName;
var password = $scope.panel.loginPassword;
var loginMember = { //JSON data from login form
K_ADI: $scope.panel.loginUserName,
PAROLA: $scope.panel.loginPassword
};
$http({
method: 'POST',
url: 'http://localhost:5169/api/Kullanicilar/KullaniciDogrula',
headers: {
'Content-Type': 'application/json'
},
data: loginMember
}).then(function successCallback(response) {
console.log("message sent", response);
$scope.data = response.data.error.data;
if ($scope.data === true) {//if username and password is correct
console.log("User exists");
userTaskList.showActiveTasks(userName)
.then(function (activeTaskResponse) {
var activeTasks = activeTaskResponse;
console.log("Active tasks (controller): ", activeTaskResponse);
userTaskList.showFinishedTasks(userName)
.then(function (finishedTaskResponse) {
var finishedTasks = finishedTaskResponse;
console.log("Finished tasks(controller): ", finishedTaskResponse);
$scope.getMessage();
$window.location.href = '../Kullanici/userPanel.html';
}, function (err) {
console.log(err);
});
}, function (err) {
console.log(err);
});
}
}, function errorCallback(response) {
console.log("Couldn't send", response);
});
}
So what causes this problem and how can I fix it?
Edit: I nested .then parts but it doesnt work properly and gives This value was just evaluated now warning. So I stil can't use data on the redirected HTML page.
I also removed the factory since it makes the code look really messy and its probably not the source of the problem.
I would have nested the your two functions inside the first promise, then redirect once all of them are done. Something like
app.controller('myCtrl', ['$scope', '$http', '$window','$mdToast', 'userTaskList',
function ($scope, $http, $window, $mdToast, userTaskList) {
$scope.siteLogin = function () {
var userName = $scope.panel.loginUserName;
var password = $scope.panel.loginPassword;
var loginMember = { //JSON data from login form
K_ADI: $scope.panel.loginUserName,
PAROLA: $scope.panel.loginPassword
};
$http({
method: 'POST',
url: 'http://localhost:5169/api/Kullanicilar/KullaniciDogrula',
headers: {
'Content-Type': 'application/json'
},
data: loginMember
}).then(function successCallback(response) {
console.log("message sent", response);
$scope.data = response.data.error.data;
if ($scope.data === true) {//if username and password is correct
console.log("User exists");
userTaskList.showActiveTasks(userName)
.then(function (res) {
var activeTasks = res;
console.log("Active tasks (controller): ", res);
userTaskList.showFinishedTasks(userName)
.then(function (res) {
var finishedTasks = res;
console.log("Finished tasks(controller): ", res);
$scope.getMessage();
$window.location.href = '../Kullanici/userPanel.html';
}, function (err) {
console.log(err);
});
}, function (err) {
console.log(err);
});
} else { //if username or password is wrong
$mdToast.show(
$mdToast.simple()
.textContent('Username or Password is wrong')
.position('right')
.hideDelay(3000)
);
}
}, function errorCallback(response) {
console.log("Couldn't send", response);
});
}
}
]);
Oh I injected ngRoute to my AngularJS module but haven't use it yet.
Using $window.location.href kills the app and loads the other page, losing $rootScope, $scope, and all service data.
Re-factor your code to use a router and store the data in a service:
$routeProvider
.when('/userPanel' , {
templateUrl: 'partials/userPanel.html',
controller: panelController
})
panelService.set(data);
$location.path("/userPanel.html");
OR use localStorage to store the data:
localStorage.setItem('panelData', JSON.stringify(data));
$window.location.href = '../Kullanici/userPanel.html';
Data stored in a service will survive route changes (which destroy $scope). Data stored in localStorage will survive page changes (which destroy apps).
The code can be simplified
This will solve the problem of having the page wait for the data before changing the route.
Since the getMessages function makes an HTTP request it needs to be modified to return a promise:
$scope.getMessages = getMessages;
function getMessages() {
return $http({
method: 'GET',
url: 'http://localhost:5169/api/chat/chatCek'
}).then(function successCallback(res) {
console.log("Mesajlar", res);
$scope.messages = res.data.error.data;
return res.data.error.data;
}, function errorCallback(res) {
console.log("Hata", res);
throw res;
});
}
Then to delay the changing of the route until the getMessages data returns from the server, chain from the getMessages promise:
$http({
method: 'POST',
url: 'http://localhost:5169/api/Kullanicilar/KullaniciDogrula',
data: loginMember
}).
then(function successCallback(response) {
console.log("message sent", response);
$scope.data = response.data.error.data;
if ($scope.data !== true) { throw "user error" };
//username and password is correct
console.log("User exists");
return userTaskList.showActiveTasks(userName);
}).
then(function (activeTaskResponse) {
var activeTasks = activeTaskResponse;
console.log("Active tasks (controller): ", activeTaskResponse);
return userTaskList.showFinishedTasks(userName)
}).
then(function (finishedTaskResponse) {
var finishedTasks = finishedTaskResponse;
console.log("Finished tasks(controller): ", finishedTaskResponse);
//CHAIN from getMessages promise
return $scope.getMessages();
}).
then(function(data) {
console.log(data);
//SAVE data before changing route
panelService.set(data);
$location.path( "/userPanel" );
//OR STORE data before changing app
//localStorage.setItem('panelData', JSON.stringify(data));
//$window.location.href = '../Kullanici/userPanel.html';
}).
catch(function (response) {
console.log("Couldn't send", response);
throw response;
});

How to design services to fetch data that are required to be called multiple times?

I have a service that returns a promise.
function GetSuggestedPeersService($http, SITE_CONFIG) {
var getSuggestedPeersService = this;
var data;
getSuggestedPeersService.getSuggestedPeersList = function() {
var baseUrl = SITE_CONFIG.baseUrl + "fetchSuggestedPeers";
var response = $http({
method : 'POST',
url : baseUrl,
headers : {
'Content-Type' : 'application/x-www-form-urlencoded'
},
data : data
});
return response;
}
getSuggestedPeersService.setSuggestedPeers = function(suggestedPeers) {
getSuggestedPeersService.suggestedPeers = suggestedPeers;
}
getSuggestedPeersService.getSuggestedPeers = function() {
return getSuggestedPeersService.suggestedPeers;
}
}
Now I use the following in the Controller to resolve the promise:
//gets the suggested peers
var promiseSuggestedPeers = GetSuggestedPeersService.getSuggestedPeersList();
promiseSuggestedPeers.then(function (response) {
peerHealthController.GetSuggPeersShow = response.data;
GetSuggestedPeersService.setSuggestedPeers(peerHealthController.GetSuggPeersShow);
return peerHealthController.GetSuggPeersShow;
})
.catch(function (error) {
console.log("Something went terribly wrong Suggested Peers.");
});
Now my question is call this service multiple times and need to update this on other service calls as well.
What is the best way to write the controller part so as not to repeat the resolve promise every time I call the service?
It's been long time.
But I just wanted to answer this question.
The best way to design this would be to use a factory. So this will become a reusable service.
An example code can be the following:
var httpMethods = peerHealthApp.factory('HttpService',HttpService);
httpMethods.$inject = ['$http', 'SITE_CONFIG'];
function HttpService($http, SITE_CONFIG){
console.log("SITE_CONFIG from Peer Service: " + SITE_CONFIG);
var factory = {
httpGet : function(relativePath,data){
var baseUrl = SITE_CONFIG.baseUrl + relativePath;
var response = $http({
method : 'GET',
url : baseUrl,
headers : {
'Content-Type' : 'application/x-www-form-urlencoded'
},
data : data
});
return response;
},
httpPost : function(relativePath, data){
var baseUrl = SITE_CONFIG.baseUrl + relativePath;
var response = $http({
method : 'POST',
url : baseUrl,
headers : {
'Content-Type' : 'application/x-www-form-urlencoded'
},
data : data
});
return response;
}
};
return factory;
}
And the above can be used again and again like the following:
var data=$.param({
"url":moderatedArticleLink
});
var promiseURLMetaData = HttpService.httpPost("parseUrlMetadata", data);
promiseURLMetaData.then(function (response) {
var urlMetaData = response.data;
return urlMetaData;
})
.catch(function (error) {
console.log("Something went terribly wrong while trying to get URL Meta Data.");
});
What is the best way to write the controller part so as not to repeat the resolve promise every time I call the service?
Instead of saving the data in a service, I recommend saving the promise:
if ( !Service.get() ) {
var promise = Service.fetch();
Service.set(promise);
});
Service.get().then(function (response) {
$scope.data = response.data;
}).catch( function(errorResponse) {
console.log(errorResponse.status);
throw errorResponse;
});
By checking for the promise and only fetching if necessary, multiple controllers can share the data without caring about the order of controller instantiation. This avoids race conditions and multiple XHRs to the same resource.

AngularJS Promise called from modal causes error

I'm currently trying to create some kind of modal dialog in AngularJS to Login a User. Therefore I created a small example using the template on the official ui-bootstrap page. To authentication the user, the credentials are sent to an REST-service. For sake of simplicity I used a dummy to simulate an http call. The received data should be passed back to the controller which called the modal dialog but somehow my prmisehandling doesn´t work and I recieve an error that the following code is wrong:
testLoginService.loginUser(user.name, user.pass)
.then(function (sessionId){
user.session = sessionId;
});
Here is the error that occurs in the console:
Error: testLoginService.loginUser(...) is undefined
$scope.ok#http://localhost:8080/LoginModal/example.js:32:2
Parser.prototype.functionCall/<#http://ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.js:10567:15
ngEventDirectives[directiveName]</<.compile/</</<#http://ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.js:18627:17
$RootScopeProvider/this.$get</Scope.prototype.$eval#http://ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.js:12412:16
$RootScopeProvider/this.$get</Scope.prototype.$apply#http://ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.js:12510:18
ngEventDirectives[directiveName]</<.compile/</<#http://ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.js:18626:15
createEventHandler/eventHandler/<#http://ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.js:2780:7
forEach#http://ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.js:330:11
createEventHandler/eventHandler#http://ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.js:2779:5
Here is my code on plunkr. What causes the error in my code and how to fix it? At the end I want to work with data received from the loginService and display the sessionID or other userspecific data on the user interface.
Thanks in advance
try the following,
use a callback function
testLoginService.loginUser(user.name, user.pass,function (data){
user.session = data.id;
});
the ajax request
this.loginUser = function(user, password,callback)
{
var wsUrl = "http://jsonplaceholder.typicode.com/posts";
var soapRequest = {
title: user,
body: password,
userId: 1
}
var config = {
headers : {
}
}
$http.post(wsUrl, soapRequest, config)
.success(callback)
.error(function (data, status, header, config) {
alert(req.responseText + " " + status);
})
};
demo: http://plnkr.co/edit/ucibA2X7s40BdxhOQ0K2?p=preview
Change your service call like this.
this.loginUser = function(user, password) {
var wsUrl = "http://jsonplaceholder.typicode.com/posts";
var soapRequest = {
title: user,
body: password,
userId: 1
};
var httpConfig = {
method: "POST",
url: wsUrl,
data: soapRequest
};
return $http(httpConfig);
};
Plunker: http://plnkr.co/edit/pjv9dTWso2fSawIygfSZ?p=preview
You need to add return to $http.post inside your service and handle success or error events in the controller:-
//service
this.loginUser = function(user, password)
{
var wsUrl = "http://jsonplaceholder.typicode.com/posts";
var soapRequest = {
title: user,
body: password,
userId: 1
}
var config = {
headers : {
}
}
return $http.post(wsUrl, soapRequest, config)
};
//controller
testLoginService.loginUser(user.name, user.pass)
.success(function (response){
user.session = response;
});
You were not returning any promise inside the loginUser method of the service
This is because you are not returning a promise. Try this :
this.loginUser = function(user, password)
{
var q = $q.defer();
var wsUrl = "http://jsonplaceholder.typicode.com/posts";
var soapRequest = {
title: user,
body: password,
userId: 1
}
var config = {
headers : {
}
}
$http.post(wsUrl, soapRequest, config)
.success(function (data, status, headers, config) {
q.resolve(data.id);
})
.error(function (data, status, header, config) {
alert(req.responseText + " " + status);
q.reject();
});
return q.promise;
};

Angular $http set cookie on each request after login

I'm having troubles with $http calls in AngularJS. I've created the following services
crApp.service('authService', function ($http) {
var urlBase = 'http://192.168.xx.xx:8081';
// POST api/login/
this.login = function (credentials) {
return $http.post(urlBase + "/api/login", credentials);
};
// POST api/logout/
this.logout = function () {
return $http.post(urlBase + "/api/logout/", "");
};
}); //end service
crApp.service('dataService', function ($http) {
var urlBase = 'http://192.168.xx.xx:8081';
// POST api/query/
this.pull = function (query) {
return $http.post(urlBase + "/api/query", query);
};
From the controller I call the login method:
$scope.login = function(){
authService.login(credentials)
.success(function(data) {
console.log("RESULT LOGIN: " + data );
})
.error(function(data, status, headers, config) {
console.log(data);
console.log(status);
console.log(headers);
console.log(config);
});
};
So far so good and I receive a response where a cookie is set:
After succesfull login I call the following method:
var locations = { query: "from location select uid, name, description, address, phone", dataFormat: "verbose" };
$scope.getLocations = function() {
dataService.pull(portals)
.success(function (data) {
console.log("RESULT QUERY: " + data)
})
.error(function(data, status, headers, config) {
console.log("Query niet gelukt!");
console.log(data);
console.log(status);
console.log(headers);
console.log(config);
});
};
Result:
So cookie is not set in the headers.
I'm using AngularJS 1.3.15 and calls are made to a remote server on a different domain, but it does work in the REST Client tool in WebStorm (Jetbrains). So it must be something i'm missing in Angular!??
Hopefully someone can help me out.
You need to set withCredentials = true in the $http config to allow cookies to be set on CORS requests. This article explains more about cookies and CORS.
In your app config:
$httpProvider.defaults.withCredentials = true;
For example:
angular.module('myApp', [])
.config(['$httpProvider'){
$httpProvider.defaults.withCredentials = true;
}]);
You can read about this option in the $http provider documentation.

Categories