I have a MainController and a ChatController. The users login with username, passwod and jobname, which are controllered by MainController, but in ChatController, I still need parameter jobname, wondering how to pass it to ChatController?
I wrote methods 'saveJobname' and 'getJobname' in service Auth, but getJobname works well but saveJobname doesn't which could be seen via the console.log(..) statement in ChatController.
Here are some relevant codes:
// ---------------------MainController--------------------
app.controller('MainController', ['Auth', '$scope', '$window', '$rootScope', function(Auth, $scope, $rootScope, $window) {
$scope.info = Auth.info;
var vm = this;
vm.loginData = {};
vm.doLogin = function() {
// ...login processing
Auth
.login(vm.loginData.username, vm.loginData.password)
.success(function(data) {
// ...some more code here
if (data.success) { // if login successfully, then save jobname
$scope.info.myjobname = vm.loginData.jobname;
//Auth.saveJobname(vm.loginData.jobname); //does NOT work either
// ...some more codes here
$window.location.href = $window.location.href + '/../job.html';
}
});
};
}]);
// --------------------ChatController----------------------
app.controller('ChatController', ['Auth', ChatController]);
function ChatController(Auth) {
// ...come other codes here;
console.log(Auth.info.myjobname); // it prints 'hello.world!' but not 'vm.loginData.jobname';
// ...come other codes here;
}
// ------------------- AuthService ------------------------
app.factory('Auth', function($http, $q) {
var authFactory = {};
authFactory.info = {
myjobname: 'hello.world!'
};
// get the API from auth.post('/login', function(...){...})
authFactory.login = function(username, password) {
return $http.post('http://localhost:8080/auth/login', {
username: username,
password: password
}).success(function(data) {
//some code here about token processing
return data;
});
};
authFactory.saveJobname = function(jobname) {
authFactory.info.myjobname = jobname;
};
authFactory.getJobname = function() {
return authFactory.info.myjobname;
};
return authFactory;
});
I prefer the solution not using $rootScope, pls advise.
Thanks a lot.
Add one variable inside Auth factory something like authFactory.info = {} in that you can define your username, password & myjobname.
While using them you need to just bind info object inside controller like
$scope.info = Auth.info
And Auth factory would be like this
// AuthService
app.factory('Auth', function($http, $q) {
var authFactory = {};
authFactory.info = {
myjobname: 'hello.world!'
};
// get the API from auth.post('/login', function(...){...})
authFactory.login = function(username, password) {
return $http.post('http://localhost:8080/auth/login', {
username: username,
password: password
}).success(function(data) {
//some code here about token processing
return data;
});
};
authFactory.saveJobname = function(jobname) {
authFactory.info.myjobname = jobname;
};
authFactory.getJobname = function(){
return authFactory.info.myjobname;
};
return authFactory;
});
Related
I have two functions in login controller both functions are
implementing login purpose ,
In this controller !scope.isLoggedIn condition satistified need to check if inside condition.
i need to permanate login in application so i store userid and password credienticals in local sessionStorage
whenever values are available in localStorage i need to execute automaticLogin function,
i checked localStorage data is available or not in if condition
if both userid and password is available in localStorage i need to execute automaticLoginUser function
if not no need to execute automaticLogin function
whenever i am try to execute that automaticLoginUser function getting error
TypeError: scope.automaticLoginUser is not a function error.
Thank you in advanced..!
app.controller('LoginCtrl', ['$scope',
'userService', '$state', '$rootScope','BackendService', 'CartService',
function(scope, userService, $state, rootScope, BackendService, CartService) {
scope.user = {};
scope.isLoggedIn = false;
scope.userId = CartService.getuserId();
scope.userPassword = CartService.getuserPassword();
if (!scope.isLoggedIn) {
console.log('in side isLoggedIn');
if (scope.userId !== undefined && scope.userPassword !== undefined) {
var loginId = scope.userId;
var password = scope.userPassword;
scope.user.loginId = loginId;
scope.user.password = password;
console.log('after user' + scope.user);
var user = scope.user;
scope.automaticLoginuser(user);
}
scope.automaticLoginuser = function(user) {
alert("Inside automaticLoginuser");
CartService.saveuserId(scope.user.loginId);
CartService.saveuserPassword(scope.user.password);
userService.loginuser(user)
.then(function(response) {
scope.userUuid = response.data.userUuid;
userService.setuserUuid(scope.userUuid);
if (response.data.status === 'success') {
CartService.saveFuuid(scope.fuuid);
$state.go("app.userHome");
} else {
$state.go("app.login");
}
});
};
scope.loginuser = function(user) {
CartService.saveuserId(scope.user.loginId);
CartService.saveuserPassword(scope.user.password);
userService.loginuser(user)
.then(function(response) {
scope.userUuid = response.data.userUuid;
userService.setuserUuid(scope.userUuid);
if (response.data.status === 'success') {
$state.go("app.userHome");
} else {
$state.go("app.login");
}
});
};
}
]);
First I cannot overstate how ill advised it is to save a users username and password anywhere on the front end including local session storage. Hope you hashed it in some way.
Secondly, the issue you are facing is because you are trying to call scope within the controller before it is declared. This is unnecessary anyway as $scope is an instance of this which angular instantiates with the controller for you to be able to call it from the DOM.
So the correct thing will be to define the function normally since you only plan to call it in your controller.
function automaticLoginuser(user) {
alert("Inside automaticLoginuser");
CartService.saveuserId(scope.user.loginId);
CartService.saveuserPassword(scope.user.password);
userService.loginuser(user)
.then(function(response) {
scope.userUuid = response.data.userUuid;
userService.setuserUuid(scope.userUuid);
if (response.data.status === 'success') {
CartService.saveFuuid(scope.fuuid);
$state.go("app.userHome");
} else {
$state.go("app.login");
}
});
};
And then just call it normally
automaticLoginuser(user);
You just need to re-order your functions.
var app = angular.module("myApp", []);
app.controller('LoginCtrl', ['$scope',
/*'userService', '$state', '$rootScope','BackendService', 'CartService',*/
function(scope /*, userService, $state, rootScope, BackendService, CartService*/ ) {
scope.automaticLoginuser = function(user) {
alert("Inside automaticLoginuser");
/*CartService.saveuserId(scope.user.loginId);
CartService.saveuserPassword(scope.user.password);
userService.loginuser(user)
.then(function(response) {
scope.userUuid = response.data.userUuid;
userService.setuserUuid(scope.userUuid);
if (response.data.status === 'success') {
CartService.saveFuuid(scope.fuuid);
$state.go("app.userHome");
} else {
$state.go("app.login");
}
});*/
};
scope.loginuser = function(user) {
/*CartService.saveuserId(scope.user.loginId);
CartService.saveuserPassword(scope.user.password);
userService.loginuser(user)
.then(function(response) {
scope.userUuid = response.data.userUuid;
userService.setuserUuid(scope.userUuid);
if (response.data.status === 'success') {
$state.go("app.userHome");
} else {
$state.go("app.login");
}
});*/
};
scope.user = {};
scope.isLoggedIn = false;
scope.userId = 'admin'; //CartService.getuserId();
scope.userPassword = 'admin'; //CartService.getuserPassword();
if (!scope.isLoggedIn) {
console.log('in side isLoggedIn');
if (scope.userId !== undefined && scope.userPassword !== undefined) {
var loginId = scope.userId;
var password = scope.userPassword;
scope.user.loginId = loginId;
scope.user.password = password;
console.log('after user' + scope.user);
var user = scope.user;
scope.automaticLoginuser(user);
}
}
}
]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="LoginCtrl">
</div>
Controllers don't really have "constructors" - they're typically used just like functions. But you can place initialization in your controller function and it will be executed initially, like a constructor:
function exampleController($scope) {
$scope.firstMethod = function() {
//initialize the sampleArray
};
$scope.secondMethod = function() {
$scope.firstMethod();
};
$scope.firstMethod();
}
scope.automaticLoginuser is being defined after your if statement. The first thing to do would be define the method higher up in the controller.
Anyone can help with this? Can't update var ABCKey. Execute setAuthenticatedAccount and console.log return correct value. After that, run getAuthenticatedAccount, and receive undefined.
angular.module('authentication.service', [
])
.factory('Authentication', ['$state', '$cookies', '$http', 'app', 'routes', 'cfCryptoHttpInterceptor',
function($state, $cookies, $http, app, routes, cfCryptoHttpInterceptor) {
var ABCKey;
var setAuthenticatedAccount = function (account, tokenAuth) {
var accountInfo = {'email': account.email, 'username': account.username, 'token': tokenAuth}
var abc = CryptoJS.enc.Base64.parse(account.abc);
Authentication.setABCKey(abc);
console.log(Authentication.showABCKey())
}
var getAuthenticatedAccount = function() {
if(!$cookies.authenticatedAccount) {
return;
}
console.log(Authentication.showABCKey())
}
var setABCKey = function(key) {
ABCKey = key;
};
var showABCKey = function() {
return ABCKey;
};
var Authentication = {
setAuthenticatedAccount: setAuthenticatedAccount,
getAuthenticatedAccount: getAuthenticatedAccount,
setABCKey: setABCKey,
showABCKey: showABCKey
};
return Authentication;
}]);
Remove Authentication while you are calling your functions because it is creating object every time. And also set var ABCKey=null at the time of decelaration like this-
angular.module('authentication.service', [
])
.factory('Authentication', ['$state', '$cookies', '$http', 'app', 'routes', 'cfCryptoHttpInterceptor',
function($state, $cookies, $http, app, routes, cfCryptoHttpInterceptor) {
var ABCKey=null;
var setAuthenticatedAccount = function (account, tokenAuth) {
var accountInfo = {'email': account.email, 'username': account.username, 'token': tokenAuth}
var abc = CryptoJS.enc.Base64.parse(account.abc);
setABCKey(abc);
console.log(showABCKey())
}
var getAuthenticatedAccount = function() {
if(!$cookies.authenticatedAccount) {
return;
}
console.log(showABCKey())
}
var setABCKey = function(key) {
ABCKey = key;
};
var showABCKey = function() {
return ABCKey;
};
var Authentication = {
setAuthenticatedAccount: setAuthenticatedAccount,
getAuthenticatedAccount: getAuthenticatedAccount,
setABCKey: setABCKey,
showABCKey: showABCKey
};
return Authentication;
}]);
dont use var its single tone class you need to define ABCkey in this
var ABCKey;
try with this
this.ABCKey = '';
I recently started to learn unit test for angular apps. And already faced up with problem. I can not take scope variable from inside executed function. Here is my factory code
angular.module('app').factory('AuthenticationService', AuthenticationService);
AuthenticationService.$inject = ['$http'];
function AuthenticationService($http) {
var service = {};
service.login = login;
return service;
function login(data, callback) {
$http({
method: 'POST',
url: CONFIG.getUrl('auth/login'),
data: data
}).then(function (response) {
callback(response);
}, function (error) {
callback(error);
});
}
Part of my controller file. I only yet wan to test login function
function AuthCtrl($scope, $location, AuthenticationService) {
var vm = this;
vm.login = login;
vm.dataLogin = {
user_id: '',
password: '',
};
function login() {
vm.dataLoading = true;
AuthenticationService.login(vm.dataLogin, function (response) {
if (response.status == 200) {
if (response.data.error_code == 'auth.credentials.invalid') {
vm.invalidCredentials = true;
} else {
vm.invalidCredentials = false;
if (response.data.session_state == 'otp_required') {
vm.userNumber = response.data.user_phone;
$localStorage['session_token'] = response.data.session_token;
vm.needForm = 'someForm';
} else {
AuthenticationService.setCredentials(response.data);
$state.go('dashboard');
}
vm.dataLoading = false;
}
}
});
}
}
});
And my spec.js
describe('AuthCtrl, ', function() {
var $scope, ctrl;
var authSrvMock;
var mockJson = {
user_id: '001',
session_token: 'some_token'
};
var mockLoginData = {
user_id: '0000102',
password: '123456'
};
var mockResponseData = {
data: {
"session_expires": 1453822506,
"session_state": "otp_required",
"session_token": "tokennnn",
"status": "success",
"user_id": "0000102",
"user_phone": "+7 (XXX) XXX-XX-89"
},
status: 200
};
beforeEach(function () {
authSrvMock = jasmine.createSpyObj('AuthenticationService', ['login', 'logout']);
module('app');
inject(function ($rootScope, $controller, $q) {
$scope = $rootScope.$new();
authSrvMock.login.and.returnValue(mockResponseData);
ctrl = $controller('AuthCtrl', {
$scope: $scope,
AuthenticationService: authSrvMock
});
});
});
it('should call login function and pass to dashboard', function () {
ctrl.login();
expect(authSrvMock.login).toHaveBeenCalled();
// until this everything works here just fine
});
});
But after I want to test vm.invalidCredentials, if I will write
expect(ctrl.invalidCredentials).toBe(false)
I will get the error
Expected undefined to be false.
Why I can't see variables?
Bit of a noob myself at Jasmine, but I'm guessing it's because you need to get the promise from your login() to return in Jasmine.
Look into using $q.defer(), or even $httpBackend.
After some more digging process and experiments I found solution.
Here what I did
(function () {
'use strict';
describe('AuthCtrl', function () {
var controller, scope, myService, q, deferred, ctrl;
var mockResponseData = {
response1: {
//...
},
response2: {
//...
},
response3: {
//...
}
};
beforeEach(module('app'));
beforeEach(inject(function ($controller, $rootScope, $q, $httpBackend, AuthenticationService) {
function mockHttp(data, callback) {
deferred = $q.defer();
deferred.promise.then(function (response) {
callback(response);
}, function (error) {
callback(error);
});
}
controller = $controller;
scope = $rootScope.$new();
myService = AuthenticationService;
q = $q;
myService.login = mockHttp;
}));
describe('when returning promises', function () {
beforeEach(function () {
ctrl = controller('AuthCtrl', {
$scope: scope,
myService: myService
});
ctrl.initController();
});
it('shows another form to validate login process', function () {
ctrl.login();
deferred.resolve(mockResponseData.response1);
scope.$digest();
expect(ctrl.invalidCredentials).toBe(false);
expect(ctrl.needForm).toEqual('2sAuth');
expect(ctrl.dataLoading).toBe(false);
});
});
});
})();
Since in my factory almost every method requires data and callback I've created mockHttp functions which takes those arguments and deferred promise. In it block I simply call need function, resolve promise with my prepared answers mock and check my expectations. Everything work. Thanks to for aiming in wich way to look
I wrote a page that allows me to change my password. The code works and it does everything I want it to do, so I started writing tests. Since I'm not as experienced in Angular testing this had proven to be quite difficult and I can't get passed this error:
TypeError: 'undefined' is not an object (evaluating 'plan.apply')
at /Users/denniegrondelaers/asadventure/myproject-web/src/users/controllers/userPasswordController.js:9
at /Users/denniegrondelaers/asadventure/myproject-web/test/unitTests/specs/users/controllers/userPasswordControllerSpec.js:98
The controller:
userPasswordController.js
users.controllers.controller('userPasswordController',
['$scope', 'Session', '$state', 'UserService', 'languages',
function ($scope, Session, $state, UserService, languages) {
$scope.languages = languages;
$scope.password = "";
$scope.notEqual = false;
$scope.isSuccessful = false;
$scope.changePassword = function() {
var pw = {
userId: Session.getCurrentSession().userId,
oldPassword: encrypt($scope.password.oldPassword),
newPassword: encrypt($scope.password.newPassword),
newPasswordRepeat: encrypt($scope.password.newPasswordRepeat)
};
if (pw.newPassword === pw.newPasswordRepeat) {
$scope.notEqual = false;
UserService.setNewPassword(pw).then(function(res) {
$scope.formErrors = undefined;
$scope.isSuccessful = true;
}, function (error) {
$scope.formErrors = error.data;
}
);
} else {
$scope.notEqual = true;
}
};
var encrypt = function (password) {
var encrypted = CryptoJS.md5(password);
return encrypted.toString(CryptoJS.enc.Hex);
};
}
]
);
The service:
userService.js
userService.setNewPassword = function (password) {
return $http
.put(EnvironmentConfig.endpointUrl +
"/password/change", password)
};
The test:
userPasswordControllerSpec.js
describe('Users', function () {
describe('Controllers', function () {
fdescribe('userPasswordController', function () {
var $scope,
controller,
$q,
willResolve,
mockSession,
mockState,
mockUserService,
mockLanguages;
beforeEach(function () {
module('mysite.users.controllers');
module(function ($provide) {
$provide.value('translateFilter', function (a) {
return a;
});
$provide.value('$state', function (a) {
return a;
});
});
mockSession = {
getCurrentSession: function () {
return {userId: 4};
}
};
mockState = {
params: {
id: 1
},
go: function () {
}
};
mockLanguages = {
getLanguages : function () {
var deferred = $q.defer();
deferred.resolve({
data: [{}]
});
return deferred.promise;
}
};
mockUserService = {
setNewPassword : function () {
var deferred = $q.defer();
if (willResolve) {
deferred.resolve({
data: [{}]
});
}
return deferred.promise;
}
};
inject(function (_$q_, $controller, $rootScope) {
controller = $controller;
$q = _$q_;
$scope = $rootScope.$new();
});
controller('userPasswordController', {$scope: $scope, Session: mockSession, $state: mockState,
UserService: mockUserService, languages: mockLanguages
});
willResolve = true;
});
it('should change password', function () {
spyOn(mockUserService, 'setNewPassword').and.callThrough();
spyOn(mockState, 'go').and.callThrough();
spyOn(mockSession, 'getCurrentSession').and.callFake();
expect(mockUserService.setNewPassword).not.toHaveBeenCalled();
expect($scope.isSubmitable()).not.toBeTruthy();
$scope.compareStoreSelection = function () {
return true;
};
$scope.password = {
oldPassword: "123456",
newPassword: "password",
newPasswordRepeat: "password"
};
expect($scope.isSubmitable()).toBeTruthy();
>>> $scope.changePassword(); <<< LOCATION OF ERROR, line 98
expect(mockUserService.setNewPassword).toHaveBeenCalled();
$scope.$apply();
});
});
});
});
I've marked the line that gives the code in the test.
Anybody any idea how to fix this? A colleague suggested altering my controller code, but I'd like to keep it as it is, since it seems logical that this code shouldn't be altered for testing to work, right?
Solution
Yarons' suggestion to change the mockSession.getCurrentSession.callFake to mockSession.getCurrentSession.callThrough fixed it!
I am trying to use an ng-repeat inside of an ng-view, but it is not pulling in the data. I was reading on the forums that I could use a factory, but I don't think using a service would be acceptable since the data for my $scope uses $routeParams to query its data.
var myApp = angular.module('myApp', ['ngRoute']);
myApp.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/:name', {
templateUrl: 'welcome.html',
controller: 'myController'
}).
otherwise ({
redirectTo: '/'
});
}]);
myApp.controller('myController', ['$scope', '$routeParams', '$q', function($scope, $routeParams, $q) {
var pls = users($q, $routeParams.name);
$scope.sBP = pls;
}]);
function users($q, name) {
var playersDFD = $q.defer();
var players = new Array();
var GameScore = Parse.Object.extend("GameScore");
var query = new Parse.Query(GameScore);
query.equalTo("playerName", name);
query.find({
success: function (results) {
for (var i in results) {
sPlayer = new player(results[i].get("playerName"), results[i].get("score"), results[i].get("cheatMode"));
players.push(sPlayer);
}
playersDFD.resolve(players);
},
error: function (error) {
alert('error');
playersDFD.reject(data);
}
});
return playersDFD.promise
.then(function (results) {
return results;
})
.catch(function (error) {
alert(error.message);
});
};
function player(name, score, cheatm){
this.name = name;
this.score = score;
this.cheatm = cheatm;
};
And the view:
<p ng-repeat="s in sBP">
{{ s.name }}
</p>
Let your users function return the promise rather than trying to resolve it, this ends up with code that is a lot easier to follow and will give the consumers of the user function control of what to do once you receive a response. For example.
function users($q, name) {
var playersDFD = $q.defer();
var players = new Array();
var GameScore = Parse.Object.extend("GameScore");
var query = new Parse.Query(GameScore);
query.equalTo("playerName", name);
query.find({
success: function (results) {
for (var i in results) {
sPlayer = new player(results[i].get("playerName"), results[i].get("score"), results[i].get("cheatMode"));
players.push(sPlayer);
}
playersDFD.resolve(players);
},
error: function (error) {
alert('error');
playersDFD.reject(data);
}
});
return playersDFD.promise;
}
And then use the users function and handle then itself.
users($q, $routeParams.name).then(function (response) {
$scope.sBP = response;
}, function (error) {
// handle error.
});
Also I would recommend breaking out users into it's own service to inject $q rather than pass it in.
Hope that helps.