Angularjs model not updated when switching between users at login - angularjs

I need the following functionality: When a user goes to the login form, the browser should auto fill the username and password.
My implementation works (on FF and Chrome) but, there is this bug (not consistent) where the model data does not get updated correctly when switching between users. This means that I log in with user ONE, then log out, and enter the credentials for user TWO, but after I click the login button, I'm still logged in with user ONE.
The login form looks like this:
<form class="form-horizontal" ng-submit="login(credentials)">
<fieldset>
<div class="form-group" ng-class="{'has-error' : validationErrors.email}">
<div class="btn-icon-lined btn-icon-round btn-icon-sm btn-default-light">
<span class="glyphicon glyphicon-envelope"></span>
</div>
<input type="email" name="email" autocomplete="on" ng-model="credentials.email" class="form-control input-lg input-round text-center" placeholder="Email" >
<span class="help-block" ng-if="validationErrors.email">{{ validationErrors.email.0 }}</span>
</div>
<div class="form-group" ng-class="{'has-error' : validationErrors.password}">
<div class="btn-icon-lined btn-icon-round btn-icon-sm btn-default-light">
<span class="glyphicon glyphicon-lock"></span>
</div>
<input type="password" name="password" autocomplete="on" ng-model="credentials.password" class="form-control input-lg input-round text-center" placeholder="Password" >
<span class="help-block" ng-if="validationErrors.password">{{ validationErrors.password.0 }}</span>
</div>
<div class="form-group">
<input type="submit" value="Sign in" class="btn btn-primary btn-lg btn-round btn-block text-center">
</div>
</fieldset>
</form>
The login controller contains something like:
// Login Controller
app.controller( 'LoginCtrl', ['$rootScope','$scope', '$state', 'AppUser', 'Auth',
function($rootScope, $scope, $state, AppUser, Auth){
console.log("LoginCtrl");
$scope.credentials = {
"email" : "",
"password": ""
};
$scope.redirectAfterLogin = function() {
// set user data
AppUser.setUserData($scope.user);
...
}
// Login attempt handler
$scope.login = function(data) {
data = {'user':data};
Auth.login(data,
function(response) {
$scope.user = response.data;
...
},function(response){
$scope.validationErrors = {
"email" : [],
"password": []
};
...
}
);
};
}]);
Logout:
// logout
$scope.logout = function() {
// remove attempted URL, if any
AppUser.removeAttemptUrl();
data = {'user':
{
'email': $scope.user.email
}
};
Auth.logout(data,
function(){
AppUser.unSetUserData($scope.user); // se method below
$state.go(ApplicationState.LOGIN);
},
function(){
console.log("Logout failed");
});
}
angular.module('app.service').factory('AppUser', [
'$window', '$rootScope', 'LocalStorage', 'appConfig', '$injector', '$location',
function($window, $rootScope, localStorage, appConfig, $injector, $location){
// Redirect to the original requested page after login
var redirectToUrlAfterLogin = { url: '' };
var userKey = "AppUser";
var userData = {};
angular.element($window).on('storage', function(event) {
if (event.key === userKey) {
$rootScope.$apply();
}
});
return {
/**
* Redirect to the original requested page after login
* - we need to be able to save the intended URL, request it, remove it and redirect to it
*/
saveAttemptUrl: function() {
if ($location.path().toLowerCase() != ApplicationState.LOGIN) {
redirectToUrlAfterLogin.url = $location.path();
}
else {
redirectToUrlAfterLogin.url = '/';
}
},
getAttemptedUrl: function() {
return redirectToUrlAfterLogin.url;
},
removeAttemptUrl: function() {
// re-initialize URL
redirectToUrlAfterLogin = { url: '' };
},
redirectToAttemptedUrl: function() {
$location.path(redirectToUrlAfterLogin.url);
},
/**
* Returns the current user's state
* #returns {boolean}
*/
isAuthenticated: function() {
userData = JSON.parse(localStorage.get(userKey) || '{}').userData;
if (!this._isSessionExpired()) {
if (userData !== undefined){
return !!(userData.id !== null && userData.email);
}
else{
return false;
}
}
else{
if (userData !== undefined){
var data = {
'user':{
'email': userData.email
}
}
// we use $injector to avoid Circular Dependency which is thrown by injecting the $api service
$injector.invoke(['$api', function($api){
$api.auth.logout(data).success(function(result){
userData = {};
localStorage.remove(userKey);
});
}]);
return false;
}
}
},
getUserData: function() {
return userData;
},
setUserData: function(data) {
userData = data;
localStorage.set(userKey, JSON.stringify({
userData: data,
stamp: Date.now()
}));
},
unSetUserData: function() {
userData = {};
localStorage.remove(userKey);
},
_isSessionExpired: function() {
var session = JSON.parse(localStorage.get(userKey) || '{}');
return (Date.now() - (session.stamp || 0)) > appConfig.sessionTimeout;
},
userData : userData
};
}] );
Any ideas on why this is happening?

After you logout check the localStorage with the browser inspector.
Probably you will find some variable that you didn't clear.
So just clear the storage and it should be fine.
To clear the storage use:
localStorage.clear();
One additional problem it could be you didn't clean the $rootScope if you didn't refresh all the data are still in there.

Is this the problem? userKey doesn't seem to be defined in the code you've showed.
// add userKey param
unSetUserData: function(userKey) {
userData = {};
localStorage.remove(userKey);
},

Related

Clearing emails after sending in angular

I'm trying to figure out how I can clear the emails in the list. I've managed to create a function where I can remove emails one by one. But I can't seem to find a way on how to clear them all after sending clicking the send invite button.
I'm working on project using angular.js and below is a sample of the code that is a work in progress
<div class="content referral-sender-page">
<div class="wrapper">
<div class="main" ng-controller="ReferralDispatchController">
<h1 class="h large">Send Invites</h1>
<!-- TODO: Explanatory text -->
<div>
<section class="grid__item bp-md-one-third">
<h5 class="h medium gray">To</h5>
<span ng-repeat="e in emails" class="h small email-list">
<span remove-on-click ng-click="removeEmail(e)" class="email-item">{{ e }} <small class="close">X</small></span>
</span>
<div class="col-2">
<input class="input" type="email"
ng-model="email"
placeholder="Email">
<a ng-click="addEmail()" class="button pads primary" >+</a>
</div>
</section>
<section class="grid__item bp-md-two-thirds">
<h5 class="h medium gray">Message</h5>
<p>Write a message to send to your homies with your invite</p>
<textarea class="text-input" ng-model="message" rows="5">
This is awesome and you should try it!
</textarea>
</section>
</div>
<div class="space--bottom one-whole">
<a ng-click="sendReferral()" class="button pads primary">Send Email Invite</a>
</div>
</div>
</div>
</div>
var ctrls = angular.module('elstudio.controllers.site');
//Removes Element only
// ctrls.directive('removeOnClick', function() {
// return {
// link: function(scope, elt, attrs) {
// scope.removeEmail = function() {
// elt.remove();
// };
// }
// }
// });
ctrls.controller('ReferralDispatchController', function ($scope, UserService,
ReferralService) {
$scope.emails = [];
$scope.message = '';
$scope.removeEmail = function(e) {
var index = $scope.emails.indexOf(e);
$scope.emails.splice(index, 1);
};
$scope.addEmail = function() {
if (!$scope.email) {
$scope.$emit('notify', { message: 'Please provide a valid email address' });
return;
}
// If email already in list, ignore
// FIXME: Provide feedback
if ($scope.emails.indexOf($scope.email) != -1) {
$scope.email = '';
return;
}
$scope.emails.push($scope.email);
$scope.email = '';
};
$scope.sendReferral = function() {
if (!$scope.loginUser) {
$scope.$emit('notify', { message: 'Please sign up or log in to your Electric account.',
duration: 3000 });
angular.element('html, body').animate({ scrollTop: 0 }, 'slow');
angular.element('.login-toggle').click();
return;
}
if ($scope.email != '') {
$scope.emails.push($scope.email);
}
if (!$scope.emails) {
$scope.$emit('notify', { message: 'Please provide at least one email address' });
return;
}
var refer = {
emails: $scope.emails,
message: $scope.message
};
var sendSuccess = function() {
$scope.$emit('notify', { message: 'An invitation has been sent!',
duration: 4000 });
};
var sendFailed = function(error) {
// Retry?
$scope.$emit('notify', { message: "Couldn't send invitation",
duration: 4000 });
};
ReferralService.email(refer).$promise.then(sendSuccess, sendFailed);
};
});
$scope.email = []; used to clear the array.
var sendSuccess = function() {
$scope.$emit('notify', { message: 'An invitation has been sent!',
duration: 4000 });
$scope.email = [];
};
Please Use
var refer = {
emails: angular.copy($scope.emails),
message: angular.copy($scope.message)
};
Please view the detail
It will do deep copy. So when we change the value in $scope.emails and $scope.message copied value will not change
also clear the $Scope.email value in the sendSuccess function

Angularjs checkbox initialization issue using json object

So i have a checkbox page barely working, the issue is when i first start this page, the checkbox is not checked, even though i try to initialize it from backend node server. No error in browser debugger though.
in the server mye,
app.get('/2getMyDiagValue', function(req, res)
{
console.log("get my diag");
var formDataArray = { "formDataObjects": [
{"flagName":"myStuff1", "flagVal":0},
{"flagName":"myStuff2", "flagVal":1}
]};
res.contentType('application/json');
res.send(formDataArray);
});
app.post('/2setMyDiagValue', function(req, res)
{
......
}
in the client mye,
app.controller('myDiagController', function($scope, $http, $routeParams, QueryMyService) {
$scope.message = 'SID Diagnostics';
// using http.get() to get existing my setting from server mye
QueryMyService.getInfoFromUrl7('/2getMyDiagValue').then(function(result) {
$scope.formData = result.formDataObjects;
}, function(error) {
alert("Error");
} );
$scope.submitForm = function() {
console.log("posting form data ...");
$http.post("/2setMyDiagValue",
JSON.stringify($scope.formData)).success(function(){} );
};
});
app.factory('QueryMyService', function($http, $q, $location) {
var factory = {};
var browserProtocol = 'http';
var port = ':1234';
var address = 'localhost';
var server = browserProtocol + '://' + address;
//////////////////////////////////////////////////////////
factory.getInfoFromUrl7 = function(myUrl) {
var deferred = $q.defer();
$http.get(myUrl).success(function(data) {
deferred.resolve(data);
}).error(function(){
deferred.reject();
});
return deferred.promise;
}
return factory;
}
checkbox webpage itself
<form ng-submit="submitForm()" ng-controller="myDiagController">
<div class="control-group" style="color:black">
<label>My Checkbox</label>
<div class="checkbox">
<label class="checbox-inline" >
<input class="big-checkbox" type="checkbox" ng-model="formData.myStuff1"
ng-true-value="1" ng-false-value="0" ng-checked="formData.myStuff1 == 1">
<h4>Message 1</h4>
<input class="big-checkbox" type="checkbox" ng-model="formData.myStuff2"
ng-true-value="1" ng-false-value="0" ng-checked="formData.myStuff2 == 1">
<h4>Message 2</h4>
</label>
</div>
<br>
<input class="btn-primary" type="submit">
</form>
i did try to modify ng-checked like this and the checkbox did show checked.
ng-checked="true"
well, just used "res.json" in the node.js side and made it work, guess i just don't have time to learn, while this fxxking company gave me a tough schedule

Angular (1.4) Design and layout

I couldn't think of a good title for this as I'm not 100% sure what to ask for plus this might be tricky without posting my whole application.
I'm new to angular, and want to create a site for holding recipes.
I'm using MVC and Web API and I have the basics together.
I want to make the recipe editing process a good user experience so want the user to be able to add an ingredient and edit and save it all without leaving the page.
At the moment I have an angular module and controller for the recipe editing, I want to have a sub-application to allow them to add and edit ingredients. I don't want them to have to navigate away.
What I need to know is a) the terminology. I'm thinking of the ingredient editor as a sub app, but is it just a sub controller?
and b) what is the pattern called? Master Detail View?
The following is my current "EditRecipeViewModel"
At the moment my newAddIngredient pushes an ingredient object into an array, this can then be edited and saved with saveNewIngredient, however this is nasty and doesn't work for editing the ingredient. I think I want the functionality for editing an ingredient encapsulated in a separate something, but is that a module a controller or what? maybe I'm trying to run before I can walk??
//edit recipe
//add ingredients
//add picture(s)
//confirm
//save
var editRecipeModule = angular.module('editRecipe', ['common'])
.config(function ($routeProvider, $locationProvider) {
$routeProvider.when(CookBook.rootPath + 'recipe/edit', { templateUrl: CookBook.rootPath + 'Templates/EditRecipe/EditRecipe.html', controller: 'EditRecipeViewModel' });
$routeProvider.when(CookBook.rootPath + 'recipe/edit/confirm', { templateUrl: CookBook.rootPath + 'Templates/EditRecipe/ConfirmRecipe.html', controller: 'ConfirmRecipeViewModel' });
$routeProvider.otherwise({ redirectTo: CookBook.rootPath + 'recipe/edit/' });
$locationProvider.html5Mode({ enabled: true });
});
editRecipeModule.controller("EditRecipeViewModel", function ($scope, $window, viewModelHelper, validator) {
$scope.viewModelHelper = viewModelHelper;
$scope.editRecipeModel = new CookBook.EditRecipeModel();
$scope.newIngredient = new CookBook.IngredientModel();
$scope.ingredients = [];
var editRecipeRules = [];
var setupRules = function () {
editRecipeRules.push(new validator.PropertyRule("Name", {
required: { message: "Recipe name is required." }
}));
editRecipeRules.push(new validator.PropertyRule("Description", {
required: { message: "Please add a description." }
}));
editRecipeRules.push(new validator.PropertyRule("Method", {
required: { message: "All good recipes need a method." }
}));
}
var editIngredientRules = [];
var setupIngredientRules = function () {
editIngredientRules.push(new validator.PropertyRule("Name", {
required: { message: "Name is required" }
}));
editIngredientRules.push(new validator.PropertyRule("Amount", {
required: { message: "Amount is required" }
}));
editIngredientRules.push(new validator.PropertyRule("Unit", {
required: { message: "Unit is required" }
}));
}
$scope.confirm = function () {
validator.ValidateModel($scope.editRecipeModel, editRecipeRules);
viewModelHelper.modelIsValid = $scope.editRecipeModel.isValid;
viewModelHelper.modelErrors = $scope.editRecipeModel.errors;
if (viewModelHelper.modelIsValid) {
//save via web api
}
}
$scope.newAddIngredient = function () {
$scope.newIngredient = new CookBook.IngredientModel();
$scope.newIngredient.EditMode = true;
$scope.ingredients.push($scope.newIngredient);
}
$scope.saveNewIngredient = function() {
$scope.newIngredient.EditMode = false;
}
$scope.addIngredient = function () {
validator.ValidateModel($scope.newIngredient, editIngredientRules);
viewModelHelper.modelIsValid = $scope.newIngredient.isValid;
viewModelHelper.modelErrors = $scope.newIngredient.errors;
if (viewModelHelper.modelIsValid) {
$scope.ingredients.push($scope.newIngredient);
$scope.newIngredient = new CookBook.IngredientModel();
}
}
setupRules();
setupIngredientRules();
});
editRecipeModule.controller("ConfirmRecipeViewModel", function ($scope, $window, viewModelHelper) {
$scope.viewModelHelper = viewModelHelper;
//$scope.editRecipeModel = new CookBook.editRecipeModel();
});
Having done some more reading
I now know the answer is to use an additional controller to deal with that small part of the UI.
The key part i was missing was to put the controller to use in the HTML.
ng-controller="IngredientViewModel as ivm"
My HTML.
<div class="row" ng-controller="IngredientViewModel as ivm" ng-repeat="ingredient in ingredients">
<span class="col-lg-3 col-md-3 col-sm-3 col-xs-3">
<input ng-show="ivm.ingredient.EditMode" ng-model="ivm.ingredient.Name" ng-change="newIngredientChanged()"></input>
<span ng-hide="ivm.ingredient.EditMode">{{ivm.ingredient.Name}}</span>
</span>
<span class="col-lg-3 col-md-3 col-sm-3 col-xs-3">
<input ng-show="ivm.ingredient.EditMode" ng-model="ivm.ingredient.Amount"></input>
<span ng-hide="ivm.ingredient.EditMode">{{ivm.ingredient.Amount}}</span>
</span>
<span class="col-lg-3 col-md-3 col-sm-3 col-xs-3">
<input ng-show="ivm.ingredient.EditMode" ng-model="ivm.ingredient.Unit"></input>
<span ng-hide="ivm.ingredient.EditMode">{{ivm.ingredient.Unit}}</span>
</span>
<span class="col-lg-3 col-md-3 col-sm-3 col-xs-3">
<button ng-show="ivm.ingredient.EditMode" ng-click="ivm.save()">OK</button>
<button ng-hide="ivm.ingredient.EditMode" ng-click="ivm.edit()">Edit</button>
</span>
</div>
The controller..
editRecipeModule.controller("IngredientViewModel", function ($scope, $window, viewModelHelper, validator) {
var local = this;
local.ingredient = new CookBook.IngredientModel();
local.ingredient.Name = "bob";
local.ingredient.Amount = "100";
local.ingredient.Unit = "g";
local.ingredient.EditMode = true;
var editRules = [];
var setupRules = function () {
editRules.push(new validator.PropertyRule("Name", {
required: { message: "Name is required" }
}));
editRules.push(new validator.PropertyRule("Amount", {
required: { message: "Amount is required" }
}));
editRules.push(new validator.PropertyRule("Unit", {
required: { message: "Unit is required" }
}));
}
local.save = function () {
validator.ValidateModel(local.ingredient, editRules);
viewModelHelper.modelIsValid = local.ingredient.isValid;
viewModelHelper.modelErrors = local.ingredient.errors;
if (viewModelHelper.modelIsValid) {
local.ingredient.EditMode = false;
}
}
local.edit = function () {
local.ingredient.EditMode = true;
}
setupRules();
});

Using $rootscope to change ng-show between controllers

What I want to do is pretty simple. I have two forms. One form is visible in the beginning and once that form is submitted it dissappears and the second form appears. I am trying to use a flag variable set at $rootscope.showFlag but it doesn't seem to work.
Here is my HTML part:
<div ng-app="myapp" >
<div class="container" ng-controller="addItemController" ng-show="showFlag">
<form class="form-signin">
<h2 class="form-signin-heading">Add an item</h2>
<input type="text" name="itemName" ng-model="myForm.itemName" id="inputItemName" class="form-control" placeholder="Name of the item" autofocus required>
<button class="btn btn-lg btn-primary btn-block" ng-click="myForm.submitTheForm()">Add item</button>
</form>
</div> <!-- /container -->
<div class="container" ng-controller="MyCtrl" ng-show="!showFlag">
<input type="text" ng-model="username"></br></br>
<button class="btn btn-lg btn-primary btn-block" ngf-select ng-model="files">Select file</button>
</div>
</div>
And this is my Angular app:
var app = angular.module("myapp", ['ngFileUpload'])
.run(function($rootScope) {
$rootScope.showFlag = true;
});
app.controller("addItemController", function($rootScope, $scope, $http) {
$scope.myForm = {};
$scope.showFlag = true;
Data.Show = 10;
$scope.myForm.submitTheForm = function(item, event)
{
console.log("--> Submitting form");
var dataObject = {
itemName : $scope.myForm.itemName,
};
var responsePromise = $http.post("/angularjs-post", dataObject, {});
responsePromise.success(function(dataFromServer, status, headers, config) {
console.log(dataFromServer.title);
//alert("Submitting form OK!");
$rootScope.showFlag = false;
});
responsePromise.error(function(data, status, headers, config) {
alert("Submitting form failed!");
});
}
$scope.myForm.uploadPhoto = function(item, event)
{
console.log('Uploading photo');
}
});
app.controller('MyCtrl', ['$scope', 'Upload', function ($rootScope, $scope, Upload) {
$scope.$watch('files', function () {
$scope.upload($scope.files);
});
$scope.log = '';
$scope.upload = function (files) {
if (files && files.length) {
var file = files[0];
Upload.upload({
url: '/upload',
fields: {
'username': $scope.username
},
file: file
}).progress(function (evt) {
// during progress
}).success(function (data, status, headers, config) {
// after finishing
});
}
};
}]);
You set showFlag to true in two places.
In the root scope.
.run(function($rootScope) {
$rootScope.showFlag = true;
});
And in the local scope.
app.controller("addItemController", function($rootScope, $scope, $http) {
$scope.myForm = {};
$scope.showFlag = true;
As the ng-show for the first form looks in the local scope first it won't be affected even when you set the rootScope flag to false.
One possible reason could be that you have misspelled the controller name
it should be addSellItemController.
<div class="container" ng-controller="addSellItemController" ng-show="showFlag">
Another small mistake is you have not added $rootScope as a dependency in your MyCtrl directive.
app.controller('MyCtrl', ['$rootScope','$scope', 'Upload', function ($rootScope, $scope, Upload) {
...
});

can't show logout button after $createUser

I'm following thinkster's ang-news tutorial to build authentication using firebase. I can create users with a service and controller but after registering a new user they are not logged in.
I have a auth.js service:
app.factory('Auth', ['$rootScope', 'FIREBASE_URL', '$firebaseSimpleLogin', function($rootScope, FIREBASE_URL, $firebaseSimpleLogin){
var ref = new Firebase(FIREBASE_URL);
var auth = $firebaseSimpleLogin(ref);
var Auth = {
register: function(user){
return auth.$createUser(user.email, user.password);
},
signedIn: function(){
return auth.user !== null; // user signed in if user property is not null
},
login: function(user){
return auth.$login('password', user); // type of login
},
logout: function(){
auth.$logout();
}
};
$rootScope.signedIn = function(){
return Auth.signedIn();
};
return Auth;
}]);
auth.user always stays null.
This is my controller:
app.controller('AuthCtrl', ['$scope', '$location', 'Auth', function($scope, $location, Auth){
if (Auth.signedIn()){
$location.path('/')
}
$scope.register = function(){
Auth.register($scope.user).then(function(authUser){
console.log('authUser: ' + JSON.stringify(authUser))
$location.path('/');
})
}
}])
Then I have a register.html with an email/password form. It calls register():
<form ng-submit='register()' novalidate>
<input type='email' placeholder='Email' class='form-control' ng-model='user.email'>
<input type='password' placeholder='Password' class='form-control' ng-model='user.password'>
<input type='submit' class='btn btn-success' value='Register'>
</form>
The users get generated in my Firebase Forge, but after I submit the register form, the Logout button does not show:
<ul class='nav navbar-nav navbar-right' ng-show='signedIn()'>
<li>
<a href='#' ng-click='logout()'>Logout</a>
</li>
</ul>
Why does signedIn() stay falsey after I create a user in the firebase forge?
Creating a user does not automatically log them in (though it used to in an older version of angularFire).
Change your controller method to look like:
$scope.register = function(){
Auth.register($scope.user).then(function(authUser){
console.log('authUser: ' + JSON.stringify(authUser))
Auth.login($scope.user);
$location.path('/');
})
}
This will create the user in the Forge and then once that promise resolves, it will automatically log them in.

Resources