ng-click is not firing with factory class - javascript

I'm new in AngularJS. The following code is not executing after entering the username and password and clicking the login button. The login should execute the login method and populate person data binding object. Anybody knows why is not firing? Thanks.
Factory File
'use strict';
var usermodule = angular.module('retrieveBasicUserInfo', [])
.factory('basicUserInfo', function($http) {
var credentials = {
username: '',
password: ''
};
var person = "";
$http.defaults.useXDomain = true;
var getBasicUserInfo = function (credentials) {
var inputdata = { "Logon": credentials.username, "Pass": credentials.password};
$http.post('http://localhost:23034/api/wmsusers/login',JSON.stringify(inputdata),
{
headers: {
'Access-Control-Allow-Origin' : '*',
'Access-Control-Allow-Methods' : 'POST, GET, OPTIONS, PUT',
'Content-Type': 'application/json',
'Accept': 'application/json'
}
}).success(function (inputdata) {
person = inputdata[0];
});
};
return {
person: getBasicUserInfo
};
});
JavaScript File
'use strict';
var usermodule = angular.module('wms', ['retrieveBasicUserInfo'])
.controller('userAuthentication', ['basicUserInfo', function ($scope, basicUserInfo) {
$scope.credentials = {
username: '',
password: ''
};
$scope.login = function (credentials) {
console.log(credentials)
$scope.person = basicUserInfo.getBasicUserInfo(credentials);
}
}]);
HTML File
<div data-ng-controller="userAuthentication">
<div class="login-panel">
<p>Please complete the following form and click Login to continue:</p>
<form name="loginForm" data-ng-submit="login(credentials)" novalidate>
<label for="username">Username:</label>
<input type="text" id="username"
data-ng-model="credentials.username">
<label for="password">Password:</label>
<input type="password" id="password"
data-ng-model="credentials.password">
<button type="submit">Login</button>
</form>
</div>
<br>
<ul data-ng-model="$parent.person">
<li>Name: {{person.Name}}</li>
<li>Associate Id: {{person.Empid}}</li>
<li>Access Level: {{person.Access}}</li>
</ul>

Please see here http://jsbin.com/vaweja/2/edit.
Your factory returns object with person property and in your controller you are trying to reach getBasicUserInfo so chnage person to getBasicUserInfo. And you missed $scope in your controller definition
change that
return {
person: getBasicUserInfo
};
to
return {
getBasicUserInfo: getBasicUserInfo
};
and
var usermodule = angular.module('wms', ['retrieveBasicUserInfo'])
//and you missed $scope in line bellow after bracket
.controller('userAuthentication', ['$scope','basicUserInfo', function ($scope, basicUserInfo) {
$scope.credentials = {
username: '',
password: ''
};
$scope.login = function (credentials) {
console.log(credentials)
$scope.person = basicUserInfo.getBasicUserInfo(credentials);
}
}])
;

Related

AngularJS 'Cannot read property 'then' of undefined'

I've this problem, when I click on login button, the chrome console log this:
angular.min.js:117 TypeError: Cannot read property 'then' of undefined
at m.$scope.logIn (loginModuleController.js:11)
Service:
angular.module('loginModule')
.factory('loginService', function($http){
return{
login: function(username, password){
var session;
$http.post('../server/php/auth/auth.php', {
username: username,
password: password
})
.then(function(res){
session = res;
});
return session;
},
isLogged: function(){
return $http.get('../angCMS/server/php/auth.php?is_logged=true');
},
logOut: function(){
return $http.get('../angCMS/server/php/auth.php?logout=true');
}
};
});
controller:
angular.module('loginModule')
.controller('LoginCtrl', ['$scope', 'loginService', function($scope, loginService){
$scope.auth = false;
$scope.username;
$scope.password;
$scope.logIn = function(){
loginService.login($scope.username, $scope.password).then(function(response){
}, function(res){
});
};
$scope.isLogged = function(){
loginService.isLogged()
.then(function(response){
if(response){
$scope.auth = true;
}
});
};
$scope.logOut = function(){
loginService.logOut()
.then(function(response){
if(response){
$scope.auth = false;
}
});
};
}]);
and this is the html template:
<div class="container" ng-if="auth==false">
<div class="col-md-4 col-md-offset-4">
<div class="row">
<br/><h2 align="center">Login</h2>
</div>
<div class="well">
<form class="form-horizontal">
<fieldset>
<div class="form-group">
<input type="text" class="form-control" placeholder="Username" ng-model="username" required>
</div>
<div class="form-group">
<input type="password" class="form-control" placeholder="Password" ng-model="password" required>
</div>
<div class="form-group">
<button class="btn btn-md btn-primary btn-block" type="submit" ng-click="logIn()">Sign in</button>
</div>
</fieldset>
</div>
</form>
</div>
</div>
PHP login method:
public function login($user, $pass){
$user = htmlspecialchars(trim($user));
$pass = md5(htmlspecialchars(trim($pass)));
$res = $this->DB->prepare("SELECT * FROM `admin` WHERE username = :user");
if(!$res->execute(Array(":user"=>$user)))
die(mysql_error());
$row = $res->fetch(PDO::FETCH_ASSOC);
if(!$row['password'] == $pass)
die("Errore: password errata!");
$_SESSION['logged'] = $row;
array_push($session, $_SESSION['logged'], true);
return $session;
}
This is more of a misuse of promises issue.
You might want to first take a look of how promises work:
https://docs.angularjs.org/api/ng/service/$q
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise
From your service code:
login: function(username, password){
var session;
$http.post('../server/php/auth/auth.php', {
username: username,
password: password
})
.then(function(res){
session = res;
});
return session;
}
When login(username, password) is called, session is still undefined upon returning.
This is because $http.post() is an asynchronous function, the .then() clause does not get executed immediately.
As pointed out by Snixtor's answer,
you should "return the return value of $http.post()":
login: function(username, password){
return $http.post('../server/php/auth/auth.php', {
username: username,
password: password
});
}
Then referring to your controller's logIn method:
$scope.logIn = function(){
loginService.login($scope.username, $scope.password).then(function(response){
// response === 'session'
}, function(res){
});
};
the response parameter from loginService.login().then() is exactly the value of your intended session variable from your previous implementation.
You're returning an unassigned variable named "session". So what you are doing here in your logged in method is returning undefined. Undefined does not have a method called then.
login: function(username, password){
var session;
$http.post('../server/php/auth/auth.php', {
username: username,
password: password
})
.then(function(res){
session = res;
});
return session;
},
My guess is you actually want to return the $http.post method, which in turn returns a promise. That way you can use the session in the controller?
Your service function login is failing to return the promise created by the call to $http.post. Instead, you need this:
login: function(username, password){
return $http.post('../server/php/auth/auth.php', {
username: username,
password: password
});
}
Note too that I've removed the session variable from the function. It's the then function in your controller that needs to be dealing with the response.
Your isLogged and logOut functions look good already. Just repeat that pattern.

Why $scope is not working on the view?

I got the next controller:
.controller('LogInController', function(logInFactory, $scope, $location, $state){
$scope.logIn = function() {
$scope.dataLoading = true;
logInFactory.logIn($scope.email, $scope.password, function (response) {
if (response.success) {
$scope.userName = response.userName;
console.log('userName', $scope.userName);
logInFactory.setCredentials($scope.email, $scope.password);
$location.path('/users');
} else {
$scope.dataLoading = false;
}
});
};
$scope.clearCredentials = function(){
$state.go('login');
logInFactory.clearCredentials();
};
});//End controller
I want to use it in this view:
<div class="header" ng-controller = 'LogInController'>
<img src= "logo.jpg">
{{userName}}
<button ng-click = 'clearCredentials()'> Cerrar sesión</button>
</div>
But userName is not showing in the view but when I print it on the controller it is displayed correctly. That view is displayed after call the logIn() function.
This is the logIn function in my factory:
var logIn = function(email, password, callback){
var URL;
if(ENV.mocksEnable){
URL = ENV.apiMock + ENV.logInMock;
return (
$timeout(function () {
var response;
getUser()
.then(function (user) {
console.log('USER', user);
if (user !== null) {
response = { success: true, userName: user.userName};
} else {
response = { success: false, message: 'Username or password is incorrect' };
}
callback(response);
});
}, 1000)
);
}else{
URL = ENV.apiURL + ENV.logIn;
return (
$http.post(URL, {email : email, password : password})
.then(function onFulfilled(response){
var data = response.data;
userName = data.username;
userEmail = data.email;
userId = data.id;
profiles = data.profiles;
callback(response);
return data;
})
.catch(function onRejected(errorResponse){
console.log('Error in logInFactory');
console.log('Status: ', errorResponse.status);
callback(errorResponse);
return errorResponse;
})
);
}
};//End login
I trigger the logIn() function in this view
<form ng-submit = 'logIn()'>
<h1>Log In</h1>
Correo electrónico:
<input type="email" ng-model='email' required><br>
Contraseña
<input type="password" ng-model='password' required><br>
<input type="submit" value="Log in">
</form>
When I tigger logIn() I should go to that header and show the userName.
why are you triggering clearCredentials() ? whereas according to this code you should triggering login() instead.
The result of your logIn() function may be out of Angular scope.
Try wrapping the result of the logIn function into a $timeout (which calls $apply, a way to force Angular to refresh a controller scope):
$timeout(function() {
if (response.success) {
$scope.userName = response.userName;
console.log('userName', $scope.userName);
logInFactory.setCredentials($scope.email, $scope.password);
$location.path('/users');
} else {
$scope.dataLoading = false;
}
});
Do not forget to inject the dependency $timeout in your controller.
You have $scope.userName inside the success of the logIn method. It won't be available until that has happened.
If you put $scope.userName outside of the method and set it to something, it would appear.
.controller('LogInController', function(logInFactory, $scope, $location, $state) {
$scope.userName = 'test name';
$scope.logIn = function() { ...
Something like that.
we don't have your factory code but this line is very strange to me :
logInFactory.logIn($scope.email, $scope.password, function (response) { ..; } )
so your passing the fonction to the factory and it is not the factory who returning data to the controller.
it should be something like this :
logInFactory.logIn($scope.email, $scope.password).then(function (response) { ..; } );
EDIT :
You have to remove the callback function from your factory and make the factory return data and handle data like this logInFactory.logIn($scope.email, $scope.password).then(function (response) { ..; } );.
You have log in the console but the $scope is not shared between the factory and controller so the callback in your factory edit the $scope.userName but the controller cannot get this change.
My problem was that I was expecting to get data from a controller to two different views. And when I go from LogIn view to my header view, the controller refresh its data. So, I have to create in my factory:
var getUserName = function() {
return userName;
};
And in the controller
$scope.userName = logInFactory.getUserName();
Now my userName persists in the factory.

angularjs $http.post with parameters

I'm new at angular and if my question is kinda low lvl dont be angry with me.
I have web service which returns sessionId and login success message if user will pass auth. for example url is that:
http://localhost:8181/login?username=USERNAME&password=12345
and here's my response:
{"sessionId":"0997cec2a8b34c84ba8419ab1204e6aa","loginSucceeded":true}
here's my login controller:
app.controller('loginCtrl', function($scope, loginService){
$scope.login=function(user){
loginService.login(user);
}
});
and here's my service:
app.factory('loginService', function($http){
return{
login: function(user){
var $promise=$http.post('http://localhost:8181/login?', user);
$promise.then(function(msg){
if(msg.loginSucceeded=="true")
console.log("opa")
else
console.log("den");
});
}
}
});
and I have user.username and user.password in my scope (using textboxes).
How can I pass those parameters in url and how can I parse that response?
In your code you're passing the username and password in the URL of the POST request. If that's what you really want (it's more common to pass them as POST data) than you can use this:
login: function(user){
var url = 'http://localhost:8181/login?username=' + user.name + '&password=' + user.password;
$http.post(url).then(function(msg){
if(msg.loginSucceeded==="true"){
console.log("opa")
}else{
console.log("den");
}
});
}
If you want to pass the data as POST data, you can pass that as the second argument in the $http.post() call:
login: function(user){
var url = 'http://localhost:8181/login';
var data = {username: user.name, password: user.password};
$http.post(url, data).then(function(msg){
if(msg.loginSucceeded==="true"){
console.log("opa")
}else{
console.log("den");
}
});
};
I never seen anyone passing login data via query string,
if you are in simple http protocol... you should consider using Basic Access Authentication or oAuth...
by the way, if you need to do what described above... this could be help you!
angular
.module('test', [])
.service('LoginService', function($q, $http) {
var self = this;
self.login = function(username, password) {
var configs = { cache: false };
var payload = {
"username" : username,
"password" : password
};
// The Method Post is generally used with a payload, but if you need to pass it as query string... you have to do:
configs.params = payload;
return $http
.post('/api/login', null /* but normally payload */, configs)
.then(function(result) {
console.log('LoginService.login:success', result);
return result.data;
})
.catch(function(error) {
console.log('LoginService.login:error', error);
return $q.reject(error);
});
;
};
})
.controller('LoginCtrl', function(LoginService, $scope) {
var vm = $scope
vm.username = 'hitmands';
vm.password = 'helloWorld';
vm.debug = 'CIAO';
vm.onFormSubmit = function(event, form) {
if(form.$invalid) {
event.preventDefault();
return;
}
vm.debug = null;
return LoginService
.login(vm.username, vm.password)
.then(function(data) { vm.debug = data; })
.catch(function(error) { vm.debug = error; })
;
};
})
;
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<article ng-app="test">
<div ng-controller="LoginCtrl">
<form ng-submit="onFormSubmit($event, loginForm);" name="loginForm">
<input type="text" placeholder="username" ng-model="username">
<input type="password" placeholder="Password" ng-model="password">
<div>
<button type="submit">Send Login Data</button>
</div>
<div style="color: blue; padding: 1em .5em;" ng-bind="debug | json">
</div>
</form>
</div>
</article>

How do I return strings from an asynchronous POST request?

I'm trying to add a signup function, using a controller and a factory, to my Angular app, but I haven't been able to get several strings (tied conditionally to success or failure) to return from my factory to my controller.
The return statements below only return empty strings at first (I assume this has to do with the asynchronous http, but am not sure). In any case, how would I return the two strings I desire (_alertType and _alertMessage) with the updated values from .success or .error?
signup.html
<div class="col-md-6 container-fluid">
<div class="jumbotron text-center" ng-controller="SignupController as vm">
<p class="lead">
<h2>Account Creation</h2>
Welcome! Please make an account
</p>
<form ng-submit="vm.signup()">
<p><input type="text" name="username" value="" placeholder="Username or Email" ng-model="username"></p>
<p><input type="password" name="password" value="" placeholder="Password" ng-model="password"></p>
<p class="submit"><input type="submit" name="commit" value="Sign Up"></p>
<alert ng-show="vm.alertMessage" type="{{ vm.alertType }}">{{ vm.alertMessage }}</alert>
</form>
</div>
</div>
signup.factory.js
(function() {
angular
.module('app')
.factory('signupFactory', signupFactory);
signupFactory.$inject = ['$http'];
function signupFactory($http) {
var _alertType = '';
var _alertMessage = '';
var service = {
signup: signup,
getAlertType: getAlertType,
getAlertMessage: getAlertMessage
};
return service;
function signup(username, password) {
var request = $http({
method: 'POST',
url: 'http://localhost:8080/user',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
data: {
username: username,
password: password
}
});
request.success(function(){
_alertType = "success";
_alertMessage = "Signed Up";
});
request.error(function(){
_alertType = "danger";
_alertMessage = "Signup Failed";
});
}
function getAlertType() {
return _alertType;
}
function getAlertMessage() {
return _alertMessage;
}
}
})();
signup.controller.js
(function() {
'use strict';
angular
.module('app')
.controller('SignupController', SignupController);
SignupController.$inject = ['$scope', 'signupFactory'];
function SignupController($scope, signupFactory) {
var vm = this;
vm.signup = function() {
signupFactory.signup($scope.username, $scope.password);
vm.alertMessage = signupFactory.getAlertMessage();
vm.alertType = signupFactory.getAlertType();
}
}
})();
You should look for promises
var promise = asyncGreet('Robin Hood');
promise.then(function(greeting) {
alert('Success: ' + greeting);
}, function(reason) {
alert('Failed: ' + reason);
});

Add new parameter to $resource after using ngChange, Angular

I am having trouble trying to append a new url parameter after selecting a genre to create a request to the API.
My ng-change is genreChange. When it been selected, it should automatically append the new url parameter like this &with_genre=fiction in the $scope.movies url before submitting the form with submitButton
<form ng-submit="submitButton()" name="cForm" class="form-horizontal">
<h2>Discover the gems</h2>
<div class="form-group">
<select class="form-control" ng-model="genreSelect" ng-change="genreChange()">
<option ng-repeat="genre in genreList.genres" value="{{genre.id}}">{{genre.name}}</option>
</select>
</div>
<input type="submit" value="hello" />
</form>
-
$scope.genreChange = function() {
$scope.genreVar = $scope.genreSelect;
$scope.movies.get({with_genres: $scope.genreVar});
}
$scope.movies = $resource('http://api.themoviedb.org/3/discover/movie:action', {
api_key: apikey,
callback: 'JSON_CALLBACK'
}, {
get: {
method: 'JSONP'
}
});
$scope.submitButton = function() {
$scope.films = $scope.movies.get();
}
I am doing this method just in case a user leaves it blank.
Thanks
This is what Resource.bind does.
var MovieResource = $resource('http://api.themoviedb.org/3/discover/movie:action', {
api_key: apikey,
callback: 'JSON_CALLBACK'
}, {
get: {
method: 'JSONP'
}
});
$scope.movies = MovieResource;
$scope.genreChange = function() {
$scope.genreVar = $scope.genreSelect;
$scope.movies = MovieResource.bind({with_genres: $scope.genreVar})
}
$scope.submitButton = function() {
$scope.films = $scope.movies.get();
}

Categories