I am currently trying to implement this AngularJS example Tutorial Example Login but instead of having the username and password stored as strings, I am trying to extract the from a local file.
I know that this is a bad practice but that is how I am trying to do it.
In the section AngularJS Authentication Service. Path: /modules/authentication/services.js in the example, the username and password are stored in a timeout function as:
$timeout(function(){
var response = { success: username === 'test' && password === 'test' };
if(!response.success) {
response.message = 'Username or password is incorrect';
}
callback(response);
}, 1000);
but I am trying to create a static json file which holders the username and password as objects. My idea was to make a $http.get request to the file and append the json objects to the username and password parameters like this:
var details;
$http.get("data.json").then(function(response){
$scope.details = response.data;
console.log(username);
});
$timeout(function () {
var response = { success: username === details.username && password === details.password
if (!response.success) {
response.message = 'Username or password is incorrect';
}
callback(response);
}, 1000);
but I am getting two errors :
1.ReferenceError: $scope is not defined
2.TypeError: Cannot read property 'username' of undefined
What is the esiest way to achieve what I am trying to do? Extract the
username and password from a json file and not have them as a static
string?
Some snippets are from http://jasonwatmore.com/post/2014/05/26/angularjs-basic-http-authentication-example
Live demo: http://plnkr.co/edit/WvOwk1?p=preview
What did I change?
The original login snippet is:
service.Login = function (username, password, callback) {
$timeout(function(){
var response = { success: username === 'test' && password === 'test' };
if(!response.success) {
response.message = 'Username or password is incorrect';
}
callback(response);
}, 1000);
};
I changed it to:
var promise = $http.get("data.json").then(function (response) {
return response.data;
});
service.Login = function (username, password, callback) {
promise.then(function (data) {
var success = data.some(function (user) {
if (user.username == username && user.password == password) {
callback({
success: true
});
return true;
} else {
return false;
}
});
if (!success) {
callback({
success: false,
message: 'Username or password is incorrect'
});
}
});
};
And added a data.json:
[{
"username": "test",
"password": "test"
}, {
"username": "test2",
"password": "test2"
}]
Why promise?
Since you use json file as db, you should load the json file with network. And you don't need to load the data.json since it doesn't change, so you can just load it once. Using promise.then to ensure the verification is after the $http.get.
If you want to load the "data.json" each time the user submits the form, just replace promise.then with
$http.get("data.json").then(function (response) {
return response.data;
}).then
check this example:
.controller('NameOfYourController', function($scope, $http, $timeout) {
$scope.details = ""; // you can even omit the declaration here
$http.get("data.json").then(function(response){
$scope.details = response.data;
console.log($scope.details.username); // or response.data.username
$timeout(function () {
// you get to the response obj using: response.data.your_object
// $timeout logic goes here
}, 1000);
});
});
note: if you are inside a service you do not have a $scope
I'm not entirely sure why $scope is undefined from your example. You're most likely not injecting it like you are with $http or $timeout. Another possibility is that you are trying to use $scope in something other than a controller.
As for your second error, details is undefined since it is set after the .then() promise is resolved. You would want to move your $timeout logic into that block of code like this:
var details;
$http.get("data.json").then(function(response){
$scope.details = response.data;
// ADD YOUR $timeout LOGIC HERE SO DETAILS IS NOT UNDEFINED
});
Looking at the example , are You trying to put function for reading json file in Service method. If you are doing it then there is no $scope available in service. Hence you are getting below error
ReferenceError: $scope is not defined
In your code , there is local variable details is defined but not initialized. hence its value is undefined.
var details;
and in timeout function you are trying to access details.username
username === details.username
hence you are getting below error
TypeError: Cannot read property 'username' of undefined
But if you want to do it most easiest way then just put your code in controller like below in this plunker. you should have creates data.json file to run below code.
'use strict';
angular.module('Authentication')
.controller('LoginController',
['$scope', '$rootScope', '$location', 'AuthenticationService','$http','$timeout',
function ($scope, $rootScope, $location, AuthenticationService,$http,$timeout) {
// reset login status
AuthenticationService.ClearCredentials();
var details;
$http.get("data.json").then(function(response){
$scope.details = response.data;
//alert($scope.details.username);
});
function Login(username,password,callback){
$timeout(function(){
var response = { success: username === $scope.details.username && password === $scope.details.password };
if(!response.success) {
response.message = 'Username or password is incorrect';
}
callback(response);
}, 1000);
}
$scope.login = function () {
$scope.dataLoading = true;
Login($scope.username, $scope.password, function(response) {
if(response.success) {
AuthenticationService.SetCredentials($scope.username, $scope.password);
$location.path('/');
} else {
$scope.error = response.message;
$scope.dataLoading = false;
}
});
};
}]);
But if you want to go with same controller and make changes in service then find answer by #blackmiaool which is absolutely perfect.
What is the esiest way to achieve what I am trying to do? Extract the
username and password from a json file and not have them as a static
string?
The first approach is most easiest approach but it is not a standard practice.
The second approach is correct and standard approach for what you are trying to do.
Observations based on the below errors :
1. ReferenceError: $scope is not defined
This error comes when we are trying to access the $scope object but forgot to inject as a dependency into the controller.
app.controller('MyCtrl', ['$scope', function ($scope) { ... }
2. TypeError: Cannot read property 'username' of undefined
What is username in your code ?
You should use $scope.details.username instead of only username.
Your code should be formatted like this :
angular.module('myApp',[]).controller('LoginController',['$scope', function ($scope) {
var details;
$http.get("data.json").then(function(response){
$scope.details = response.data;
console.log($scope.details.username);
});
$timeout(function () {
var response = { success: username === $scope.details.username && password === $scope.details.password
if (!response.success) {
response.message = 'Username or password is incorrect';
}
callback(response);
}, 1000);
}]);
Related
I have a service to get (with array) all post from a server. I need to filter this array by id and show only this post in a single page.
In the service I have this code.
.service('PostAPI', function($http) {
this.getAll = function() {
return $http.get("ajax/getAllPosts.php");
}
this.getOne = function(data) {
return $http.get("ajax/searchPost.php?postID=" + data);
}
this.delete = function(data) {
if (confirm("Are you sure to delete this line?")) {
return $http.delete("ajax/deletePost.php?postID=" + data);
}
}
this.update = function(data) {
return $http.put("ajax/updatePost.php?postID" + data);
}
this.create = function() {
return $http.post("ajax/addPost.php");
}
})
In the controller
.controller("PostControlador", function($scope, $routeParams, PostAPI) {
GetPost();
$scope.title = "Editar post";
function GetPost() {
PostAPI.getOne($routeParams.id).success(function(data) {
$scope.post = data;
console.log($scope.post);
});
};
In post HTML I have this.
<div>
<div>{{post.TASK}}</div>
<div>{{post.STATUS}}</div>
<b>Back</b>
</div>
I'm not able to get any data to show in the page, and also, i have no errors in my console. ¿Any idea?
Check your ajax/searchPost.php?postID= api that is this api returning single object or array, If this api returning object than it should work but If you getting array of single element in response of api then in your api success code use first element of array by data[0].
Controller code
.controller("PostControlador", function($scope, $routeParams, PostAPI) {
GetPost();
$scope.title = "Editar post";
function GetPost() {
PostAPI.getOne($routeParams.id).success(function(data) {
$scope.post = data[0];
console.log($scope.post);
});
};
use then instaed of success. .then returns a promise so that you can handle the asynchrounous calls.
Also you are calling the getPost() method before function definition. So it may not get the promise.
call your getPost(), method after the function definition and check, so that it can receive the promise.
.controller("PostControlador", function($scope, $routeParams, PostAPI) {
$scope.title = "Editar post";
function GetPost() {
PostAPI.getOne($routeParams.id).then(function(data) {
$scope.post = data[0];
console.log($scope.post);
});
};
GetPost();
Im writing my first app with Angular and now faced up with the problem... I have address for POST request with authentication token. Something like:
http://example.com/orders?authentication_token=123456
So I need to make ng-submit or ng-click that send that request and get a bunch of items and show them on the page...
Also, I have a body for them:
{
"order": {
"seller_id":84,
"price":123,
"delivary_date":"12-12-2025",
}
}
So, what the best way to do that?
So you will have to make one angular service which would communicate with server and fetch the data and one angular controller which will interact with service to get the data and display over the UI.
Lets say service name is MyService:
app.service('MyService', function($http) {
var params = {}; // some parameters
this.getData = function(successCallback, failureCallback) {
$http.post("URL", params).then(function(data) {
successCallback(data);
}, function(data, status) {
failureCallback(data, status);
});
}
});
Controller name is MyCntrl:
app.controller('MyCntrl', function($scope, MyService) {
function successCallback(data) {
$scope.itemList = data;
}
function failureCallback(data, status) {
$scope.itemList = {};
}
$scope.handleClick = function() {
MyService.getData(successCallback, failureCallback);
}
});
I believe it would help you to resolve your requirement!!!
Assume you have a orderCtrl. ng-click or ng-submit is based on your app requirement. Call the function someFunction() that triggers $http post and you can handle the success and failure response.
app.controller('orderCtrl', function($scope, $http) {
$scope.someFunction = function(){
var data = {}; // prepare your data here.
$http({
method : "POST",
url : "specify your url here",
data : data
}).then(function mySucces(response) {
var response = response.data;
// handle your success here
}, function myError(response) {
// handle the failure here
});
});
});
Note :
If you are using a form and you want to trigger this function after user filling all the information, then use ng-submit. If it is independent then use ng-click.
I'm saying again, it's all depends on what you are doing.
My code of login.js is
var loginModule = angular.module('loginModule', [])
.controller('LoginCtrl', function ($scope, $auth, $location) {
if (!$auth.isAuthenticated()) {
$scope.oneAtATime = true;
$scope.login = function () {
$auth.login({userName: $scope.username, password: $scope.password, isEncript: false})
.then(function () {
console.log($auth.getMessage());
})
.catch(function (response) {
console.log(response);
});
};
}
else {
$location.path('/home');
}
$scope.status = 'true';
});
and unit test code is
describe('login()', function() {
it('should be able to handle login errors', function () {
var user = {
email: 'foo#bar.com',
password: '1234',
isEncript: false
};
this.$httpBackend.expectPOST('app/controller/apicall.php?serviceName=login').respond(200);
this.$auth.login(user).then(angular.noop, function () {
});
this.$httpBackend.flush();
expect(user.isEncript).toBe(false);
});
});
});
......................the error i am getting is below .......................................
$auth login() should be able to handle login errors FAILED
Error: Unexpected request: POST ../../controller/apicall.php?serviceName=login
Expected POST /app/controller/apicall.php?serviceName=login
help me to solve how should i solve this error.
Something is calling
../../controller/apicall.php?serviceName=login
You can work out whats calling that, or just change your
this.$httpBackend.expectPOST('app/controller/apicall.php?serviceName=login').respond(200);
to
this.$httpBackend.expectPOST('../../controller/apicall.php?serviceName=login').respond(200);
and that should do it.
This error say that your $auth service send request to the other URL.
Therefore at first you need check and test what do your $auth service when you call its 'login' method.
The better way in order to test is to have separate suites for $auth service (where you will test how it interact with backend) and for LoginCtrl controller (where you will mock $auth service and test only behavior of the controller).
You can use this plunker http://tinyurl.com/lv3gskf as example. (I use tinyurl.com because stackoverflow not allow to post links to plunker without code)
I built a simple app with user authentication base on this: link
Basically, I have a userAccountService, responsible for communicating with server and login controller handling the login process.
From other controller I want to check if user is already logged in (to hide LogIn button, and show user profile instead).
So I have a navController
function navCtrl ($scope, $modal, userAccountService) {
$scope.IsUserLoggedIn = function () {
return userAccountService.isUserLoggedIn;
}
}
So in HTML I use this ng-hide="isUserLoggedIn()
my userAccountService:
app.factory('userAccountService', ['$http', '$q', userAccountService]);
function userAccountService($http, $q) {
var service = {
registerUser: registerUser,
loginUser: loginUser,
logOut: logOut,
getValues: getValues,
isUserLoggedIn: false,
accessToken: ""
};
// code ommited
function loginUser(userData) {
var tokenUrl = serverBaseUrl + "/Token";
if (!userData.grant_type) {
userData.grant_type = "password";
}
var deferred = $q.defer();
$http({
method: 'POST',
url: tokenUrl,
data: userData,
})
.success(function (data,status,headers,cfg) {
// save the access_token as this is required for each API call.
accessToken = data.access_token;
isUserLoggedIn = true;
// check the log screen to know currently back from the server when a user log in successfully.
console.log(data);
deferred.resolve(data);
})
.error(function (err, status) {
console.log(err);
deferred.reject(status);
});
return deferred.promise;
}
}
What am I doing wrong? Here's another interesting read I took inspiration from: link
You can't return a variable, but you can return a function, so create a function that returns that variable.
Try something like this, it returns your service object (you might want to put a $watch on it):
Service
function userAccountService($http, $q) {
function getData() {
return service;
}
...
}
Controller
$scope.IsUserLoggedIn = userAccountService.getData().isUserLoggedIn;
Also, you're not correctly updating the state variable from your success callback - you're creating global variables instead of using the service object properties. So, for example:
isUserLoggedIn = true;
should be:
service.isUserLoggedIn = true;
I'm trying to set the headers of a resource (code bellow).
It happens that, when I instantiate my resource ($scope.user = new rsrUser;) angularjs fetches the cookies that aren't yet defined (an "undefined" error is fired from inside "getHMAC()"). The cookies will only be defined when "$scope.login()" is fired (it happens when the user clicks a button in the interface).
Is there a better way of doing this?
controllers.js
angularjsWebInterfaceControllers.controller('loginCtrl', ['$scope', 'rsrUser',
function($scope, rsrUser){
$cookieStore.put("username","therebedragons");
$cookieStore.put("password","therebedragons");
$scope.user = new rsrUser;
$scope.user.username = ""; //bound to input field in interface
$scope.user.password = ""; //bound to input field in interface
$scope.login = function() {
$cookieStore.put("username", $scope.user.username);
$cookieStore.put("password", $scope.user.password);
$cookieStore.put("state", "loggedOUT");
$scope.user.$logIn(
function(){
$cookieStore.put("state", "loggedIN");
}, function() {
$cookieStore.put("username","therebedragons");
$cookieStore.put("password","therebedragons");
$cookieStore.put("state", "loggedOUT");
}
)
};
}]);
services.js
angularjsWebInterfaceServices.service('rsrUser', [ '$resource', '$cookieStore',
function($resource, $cookieStore){
var req = "/login"
var timestamp = getMicrotime(true).toString();
var username = $cookieStore.get("username");
var key = $cookieStore.get("password");
return $resource(baseURL + req, {}, {
logIn: {method:'POST',
isArray:false,
headers:{
'X-MICROTIME': timestamp,
'X-USERNAME': username,
'X-HASH': getHMAC(username,timestamp,req,key)
}
}
});
}]);
EDIT: Actually, the cookies are defiend as soon as the controller is instantiated;
The value for a header can be a function that returns a string (see arguments here: http://docs.angularjs.org/api/ng/service/$http#usage). That way the cookie isn't accessed in your resource until the logIn method is called.
return $resource(baseURL + req, {}, {
logIn: {method:'POST',
isArray:false,
headers: {
'X-MICROTIME': timestamp,
'X-USERNAME': function() {
return $cookieStore.get("username");
},
'X-HASH': function() {
var username = $cookieStore.get("username");
return getHMAC(username,timestamp,req,key)
}
}
}
});