I am trying to implement angular resource for login like this
var data = new Login({
username: user.userName,
password: user.password
})
data.$save()
This is suppose to return some data to me if login is successful or return error if it is not.
What I want is the callback like the angular http post method like this .
data = JSON.stringify({
username: user.userName,
password: user.password
})
$http.post('API/sigin',data,
{
headers: {
'Content-Type': 'application/json'
}
}
)
.success(
function(response){
// success callback
console.log("doing sign in");
},
function(error){
// failure callback
return error
}
)
I switched to resource when http post failed me. It will just just hang perpetually and will later return error.
I am using angular 1.4.3.
any help, info will be appreciated
..factory.js
//Create a factory for the Login API
angular.module(...)
.factory('LoginEntity', ['$resource', function ($resource) {
return $resource(
'API/sigin',
{
save: {method: 'POST'},
update: {method: 'PUT'}
}
);
}])
...controller.js
angular.module(...)
.controller('xxxController', ['LoginEntity', function(LoginEntity){
//in Controller add LoginEntity dependency
LoginEntity.save({
username: user.userName,
password: user.password
},
function (response) {
//success callback
},
function () {
//error callback
//usually do some logging stuff here
});
}]);
Related
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;
});
I am trying to get an alert with after sending an email with nodemailer and not just the json response. Here is what I have so far:
app.js (nodejswith nodemailermodule):
transporter.sendMail(mailOptions, (error) => {
if (error) {
res.sendStatus(500)
} else {
res.sendStatus(200)
}
transporter.close();
});
});
angularjs:
$http.post({
url: '/contactUs',
data: '',
}).then(
function successCallback(response) {
$scope.alert("Message Sent!!")
},
function errorCallback(response) {}
)
you'll need to just call alert("Message Sent") instead of $scope.alert("Message Sent").
If you want it to be angularized, you can inject $window and call $window.alert("Message Sent") which will make it easier on you if you're unit testing.
Now i call rest API with:
Template.accedi.events({
'submit #form-login'(e) {
e.preventDefault();
var data = {
'username': $("[name=login_username]").val(),
'password': $("[name=login_password]").val()
};
var url = api_url + "/Token";
HTTP.call('POST', url, {
params: {
'grant_type': 'password',
'username': data.username,
'password': data.password
}
}, (error, result) => {
if (!error) {
Session.set('userData', JSON.stringify(result.data));
localStorage.setItem('userData', JSON.stringify(result.data))
Router.go('/');
}
}
}
})
This call rest api client side.
I need to call the api server side... there is a method?
You should create method which is then called from your client code. Something like below should works in your case.
Methods have to be defined in code which is loaded on the client and server.
Meteor.methods({
'login.token'({ username, password }) {
try {
let request = HTTP.call('POST', 'https://example.com', {
params: {
'grant_type': 'password',
'username': username,
'password': password
}
})
// You might want to process, validate etc. request response before return it to the client.
return request
} catch (err) {
throw new Meteor.Error(500, 'There was an error processing your request')
}
}
})
Your client code might looks similiar to this
Template.accedi.events({
'submit #form-login'(e) {
e.preventDefault();
var data = {
'username': $("[name=login_username]").val(),
'password': $("[name=login_password]").val()
};
Meteor.call('login.token', {
username: data.username,
password: data.password
}, (err, res) => {
if (err) {
console.log(err)
} else {
Session.set('userData', JSON.stringify(res.data));
localStorage.setItem('userData', JSON.stringify(res.data))
Router.go('/');
}
})
}
})
You can find more about methods in Meteor guide at this page https://guide.meteor.com/methods.html
I have following function, which returns promise for authentication
authenticate: function(options) {
return new Promise((resolve, reject) => {
$.ajax({
url: this.tokenEndpoint,
type: 'POST',
headers: {'Content-Type': 'application/json', 'Accept-Encoding': 'gzip, deflate'},
data: JSON.stringify({
username: options.identification,
password: options.password
})
}).then(function(response) {
console.log(response) // I get here object with good properties
resolve({
lastLoginDate: response.lastLoginDate,
login: response.login,
name: response.name,
role: response.role,
token: response.id_token
});
}, function(xhr, status, error) {
if(error !== undefined) {
console.log(error);
}
var response = xhr.responseText;
reject(response);
});
});
When i call it and pass good username and password it returns "undefined", but when i pass bad properties, my "reject" works perfectly . Does someone know why my "then" doesn't return expected output?
this.get('session').authenticate('authenticator:custom', {'identification': identification, 'password': password})
.then((data)=>{
console.log(data); //Undefined <- here is my problem.
})
.catch((reason) => {
console.log(reason); // It works, when pass bad password!
this.set('errorMessage', reason.error);
});
Firstly, $.ajax returns a jQuery Promise which these days is 99.999% as good as a native Promise - so no need to wrap $.ajax in a Promise
Secondly, .then takes two callback arguments, onfullfilled and onrejected, both of these callbacks only receive a single argument - your onrejected callback will never have status and error arguments - so that code is flawed
In the onfullfilled callback, the argument is an array, being the [result, status, jqXHR] that you would get in the $.ajax success call
Similarly, in the onrejected callback, the argument is an array, being [jqXHR, status, errorThrown]
Given all that, the authenticate function can be written
authenticate: function(options) {
return $.ajax({
url: this.tokenEndpoint,
type: 'POST',
headers: {'Content-Type': 'application/json', 'Accept-Encoding': 'gzip, deflate'},
data: JSON.stringify({
username: options.identification,
password: options.password
})
})
.then(function(arr) {
var response = arr[0];
console.log(response);
// return instead of resolve
return({
lastLoginDate: response.lastLoginDate,
login: response.login,
name: response.name,
role: response.role,
token: response.id_token
});
}, function(arr) {
var xhr = arr[0], status = arr[1], error = arr[2];
if(error !== undefined) {
console.log(error);
}
var response = xhr.responseText;
// return a rejection - could "throw response" instead
return Promise.reject(response);
}
);
}
and FYI - ES2015+ you could write
.then(function([response, status, xhr]) {
.....
}, function([xhr, status, error]) {
....
Service.js
this.userLogin = function (username, password) {
var dataBody = $.param({'username': username,'password': password});
return $http({
method: 'POST',
url: servicePathURL,
data: dataBody,
headers: {
"Authorization": "Basic",
"Content-Type": "application/x-www-form-urlencoded"
}
})
.then(function (response) {
$rootScope.globals = {
currentUser: {
username: username,
}
};
return response;
}).catch(function (error) {
throw error;
});
};
Controller.js
AuthenticationServiceLogin.userLogin($scope.username, $scope.password)
.then(function (response) {
if (response.status ==200) {
toaster.pop('success', "", "Login Successful");
$location.path('/home');
}
}).catch(function (error) {
toaster.pop('error', "", error.statusText);
});
In Controller.js, toaster.pop('error', "", error.statusText); is not being called when there is an exception while user logs in.
Also I have used $http method, is there any advantage to returning
a $q.defer() promise rather than an $http promise or considered as best practice ? If yes, how can I modify above $http code into promise ?
Your code appears to be fine. So long as you re-throw any errors encountered by your $http call, they should propagate all the way up to the controller. I'm inclined to say that any problems with your error handling are not in the code that you've posted.
There's no advantage to having a catch handler in service.js if you're not going to do any work with the error thrown. Service.js will want to look like this:
Service.js
this.userLogin = function (username, password) {
return $http({
method: 'POST',
url: servicePathURL,
data: $.param({'username': username,'password': password}),
headers: {
"Authorization": "Basic",
"Content-Type": "application/x-www-form-urlencoded"
}
})
.then(function (response) {
$rootScope.globals = {
currentUser: {
username: username,
}
};
return response;
// The catch block here is useless. The promise returned by $http will transmit any
// errors on its own.
//}).catch(function (error) {
// throw error;
});
};
In response to your second question: there is no advantage to using $q.defer() instead of returning the promise returned by $http itself, and a number of major disadvantages - namely that any exceptions thrown by your login method will disappear. See The Deferred Anti-pattern here for details: https://github.com/petkaantonov/bluebird/wiki/Promise-anti-patterns
$http is definitely the preferred option.