On hard refresh, $rootScope disappears and cannot access current user - angularjs

I am using $rootScope to always access the current logged in user. When the user submits a new meal into the system the meal attributes are stored plus the user id who submitted them.
This works, but the moment I hard refresh my browser, the $rootScope.user object disappears.
How do I prevent that?
In app.js I have:
$rootScope.user;
Here's what happens when the user logs in:
Auth.$onAuth(function (user) {
if (user === null) {
console.log("Not logged in yet");
} else {
console.log("Logged in as", user.uid);
}
$rootScope.user = user;
});
Then, when the user accesses the AddMeal page, within the AddCtrl we have:
var firebaseObj = new Firebase("https://myapp.firebaseio.com/courses/");
var fb = $firebaseArray(firebaseObj);
console.log($rootScope.user)
$scope.newMeal = {
name: "",
price: "",
ingredients: "",
description: "",
category: "",
cuisine: "",
userID:""
};
$scope.submitMeal = function () {
if (angular.equals({}, $scope.newMeal)) {
alert("Your form is empty");
$rootScope.notify('Your form is empty')
} else {
console.log($scope.newMeal);
var name = $scope.newMeal.name;
var price = $scope.newMeal.price;
var ingredients= $scope.newMeal.ingredients;
var description = $scope.newMeal.description;
var category= $scope.newMeal.category;
var cuisine= $scope.newMeal.cuisine;
fb.$add({
name: name,
price: price,
ingredients: ingredients,
description: description,
category: category,
cuisine: cuisine,
userID: $rootScope.user.uid
}).then(function(ref) {
$scope.newMeal = {};
console.log(ref);
}, function(error) {
console.log("Error:", error);
});
$rootScope.notify('New meal has been added!')
}
Here is my run function in app.js:
.run(function ($ionicPlatform, $rootScope, $firebaseAuth, $firebase, $window, $ionicLoading) {
$ionicPlatform.ready(function () {
// Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
// for form inputs)
if (window.cordova && window.cordova.plugins.Keyboard) {
cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
cordova.plugins.Keyboard.disableScroll(true);
}
if (window.StatusBar) {
// org.apache.cordova.statusbar required
StatusBar.styleDefault();
}
$rootScope.show = function(text) {
$rootScope.loading = $ionicLoading.show({
content: text ? text : 'Loading..',
animation: 'fade-in',
showBackdrop: true,
maxWidth: 200,
showDelay: 0
});
};
$rootScope.hide = function() {
$ionicLoading.hide();
};
$rootScope.notify = function(text) {
$rootScope.show(text);
$window.setTimeout(function() {
$rootScope.hide();
}, 1999);
};
$rootScope.user;
});
})

AngularJS works as a SPA (here you can read a bit about it). The point is that when the page reloads, as any other SPA, it will lose all its data and the app will be "reeboted". This is why you are getting this problem.
There's an easy way to solve it:
When the app loads/reloads, it goes to the app.config() and rigth after that it goes to the app.run() (if any).
So my solution for you is to keep your user's info data on the localstorage (works like a cookie) and then ask for it from there when the app initialize.
angular.module('MyApp').run(function($rootScope){
if(!angular.isDefined($rootScope.userInfo) && localstorage.userInfo){
// UserInfo exists in localstorate but not on $rootScope. This means the page was reloaded or the user is returning.
$rootScope.userInfo = localstorage.userInfo;
}else if(!angular.isDefined($rootScope.userInfo) && !localstorage.userInfo){
// User is not logged at all. Send him back to login page
}else if(angular.isDefined($rootScope.userInfo)){
// User is logged in. You can run some extra validations in here.
}
});
I'm assuming you keep your users info on a variable $rootScope.userInfo
That been said, I strongly recommend you try a Service to keep your data rather than on the $rootScope. Here's a guide on how you can achieve that.
I hope this solves your issue.
**UPDATE
If you're working with Ionic you can try something like this:
var myApp = angular.module('myApp', ['ionic']);
myApp.run(function($ionicPlatform) {
$ionicPlatform.ready(function() {
//load your settings from localStorage or DB where you saved.
});
});
Took it from this reference.

Related

Firebase angularjs firebase current auth gets replaced when creating a new user

I am working on angular firebase web app, in which as soon as admin login, he can create users by his own.
When admin log in , he is authenticated with firebase.auth()
But what is happening is, as admin creates a new user, the current auth details(admin) gets replaced by newly created user. I want the user creation without creating a newer session
Have a look at my controller:
app.controller('UserAdd', ['$scope','$sessionStorage','$http','$firebaseAuth', '$firebaseArray', '$location' ,'$firebaseObject', 'FBURL', function($scope,$sessionStorage,$http,$firebaseAuth,$firebaseArray, $location ,$firebaseObject, FBURL){
var user = firebase.database().ref().child("users");
$scope.user_auth_data = firebase.auth().currentUser;
$sessionStorage.uID = $scope.user_auth_data.uid ;
$scope.access_points= [];
$scope.teams = [];
$scope.org_details = [];
user.child($sessionStorage.uID).child("OrganizationId").on('value',function(org_id){
$sessionStorage.org_id = org_id.val();
})
user.child($sessionStorage.uID).child("ImagePath").on('value',function(img){
$scope.user_image = img.val();
})
//access points
firebase.database().ref().child("organization").child($sessionStorage.org_id).child("access_points").on('value',function(access_points){
angular.forEach(access_points.val(),function(ap,key){
$scope.access_points.push({id:key,ssid:ap.SSID,bssid:ap.BSSID,display_name:ap.DisplayName,lat:ap.Latitude,lng:ap.Longitude});
})
});
var obj = $firebaseArray(firebase.database().ref().child("organization").child($sessionStorage.org_id).child("access_points"));
obj.$loaded(
function(data) {
},
function(error) {
console.error("Error:", error);
}
);
firebase.database().ref().child("organization").child($sessionStorage.org_id).child("teams").on('value',function(teams){
angular.forEach(teams.val(),function(team,key){
$scope.teams.push({id:key,team_name:team.TeamName,team_leader:team.TeamLeader,channel_name:team.ChannelName});
})
});
var obj = $firebaseArray(firebase.database().ref().child("organization").child($sessionStorage.org_id).child("teams"));
obj.$loaded(
function(data) {
},
function(error) {
console.error("Error:", error);
}
);
$scope.selectItem = function(){
};
//add user
$scope.addUser = function() {
firebase.auth().createUserWithEmailAndPassword($scope.Email, $scope.Password)
.then(function(user) {
//adding single values in user node
var ref = firebase.database().ref().child("users").child(user.uid);
ref.set({
EmployeeId: $scope.emp_id,
Contact: $scope.Contact,
DOB: $scope.date_of_birth,
Designation: $scope.Designation,
Email: $scope.Email,
FirstName: $scope.FirstName,
LastName: $scope.LastName,
OrganizationId: $sessionStorage.org_id,
Gender: $scope.selectedGender,
IsAdmin: false
});
$scope.selectedAccess.forEach(function(access_values){ //adding nested access_points
var ref1 = firebase.database().ref().child("users").child(user.uid).child("AccessPoint").child(access_values.id);
ref1.set({
SSID: access_values.ssid,
BSSID: access_values.bssid,
DisplayName: access_values.display_name,
Latitude: access_values.lat,
Longitude: access_values.lng
});
});
$scope.selectedTeam.forEach(function(team_values){ //adding nested team
var ref2 = firebase.database().ref().child("users").child(user.uid).child("team").child(team_values.id);
ref2.set({
ChannelName: team_values.channel_name,
TeamName: team_values.team_name,
TeamLeader: team_values.team_leader
});
});
$scope.teams.forEach(function(team_values){
var ref3 = firebase.database().ref().child("organization").child($sessionStorage.org_id).child("channels").child(team_values.channel_name).child("info").child("users");
ref3.child(user.uid).set($scope.FirstName+" "+$scope.LastName);
var ref4 = firebase.database().ref().child("organization").child($sessionStorage.org_id).child("user_team").child(team_values.team_name).child(user.uid);
ref4.set($scope.FirstName+" "+$scope.LastName);
});
firebase.auth().sendPasswordResetEmail(user.email);
$location.path('/user_list');
}).catch(function(error) {
console.log(error);
});
};
}]);
Whats needs to be done to remain in same admin session instead of a new one?

How to match item from two different databases based using angularjs

I need a bit of guidance figuring out how to make two similar values in angular js from two different tables. The tables am using are a user table and a school table. So what I need to do is based on the logged in user I am supposed to get a school name related to that user but currently am not sure how to go about this. Any assistance in guiding me on how to go about this would be greatly appreciated.
School Service Controller Code:
angular.module('starter').factory('Schools',['apiUrl','$resource', 'UserInfo', function(apiUrl,$resource, UserInfo){
var factory = $resource(apiUrl + '/schools/:schoolId',
{
schoolId: '#_id'
}, {
update: {
method: 'GET'
}
});
return factory;
}]);
Profile Controller Code Snippet:
angular.module('starter.controllers')
.controller('ProfileController', function($scope,$http,$state,Schools, $ionicPopup, apiUrl, UserInfo,$ionicLoading,$ionicHistory,Users,Authentication) {
$scope.apiUrl = apiUrl;
$scope.authentication = Authentication;
$scope.state = $state;
$scope.selected = {};
var user = Authentication.user.school;
$scope.find = function(queryParams){
$scope.place = [];
var user = $scope.authentication.user.school;
var school = Schools.query({_id: user.school})
var params = queryParams || {};
params._id = user;
Schools.query(params, function(response){
if (params._id === school){
// response.splice(0, $scope.place.lengh);
// for(var x = 0; x< response.lengh; x++){
// $scope.place.push(response[x]);
// }
$scope.place = response[0].name;
}
else{
$scope.place = response;
}
})
}
$scope.signOut = function(){
$ionicPopup.confirm({
title: "SIGN OUT",
template: '<p align="center">' + 'PLEASE CONFIRM IF YOU WANT TO SIGN OUT'+ '</p>',
buttons: [
{ text: "NO",
type: 'button button-outline button-assertive',
onTap:function(e){
return false;
}
},
{
text: "YES",
type:'button-positive',
onTap:function(e){
//now you can clear history or goto another state if you need
$ionicHistory.clearHistory();
$ionicHistory.nextViewOptions({ disableBack: true, historyRoot: true });
$state.go('signin');
return true;
}
}
]
});
};
});
My value for "$scope.find function" is returned properly but is the whole list of school names and details rather than the one which matches the user.
I think this is server side logic. When you pass logged in user to your api then do some database query based on that user in the server side and return json object with all the list of schools .
I finally figured a way to get the correct values based on the id reference of school in the user table. I had to use the angularjs forEach method to first query the data then filter it in a if statement to get the results I was looking for.
Solution:
$scope.find = function(){
var school = $scope.authentication.user.school;
$scope.schoolName = Schools.query(function(results) {
results.forEach(function(result) {
if (result._id === school) {
$scope.schoolName = result.name;
return $scope.schoolName;
}
});
});
}

facebook login using firebase in ionic

I am facing problem to get email and likes of user after facebook login using firebase into my ionic app.
Also after getting facebook display name and some other information in the user is not being redirected to the Dashboard page instead login page got refresh. Although i read different posts on stackoverflow and other sorces but i am stuck. Please help me to solve these two issues.
**1)**How to get email and likes of user
**2)**how to redirect user to dashboard soon after verified by facebook..
Here is the code
****Controller:****
$scope.loginFaceBook = function() {
///alert('fb Login firebase...');
var existingAuthData = Auth.$getAuth();
console.log("existingAuthData : ",existingAuthData);
//console.log("existingAuthData Email : ",existingAuthData.thirdPartyUserData.email);
Auth.$authWithOAuthRedirect("facebook").then(function(authData) {
alert('done 1');
// User successfully logged in
console.log(authData);
$location.path('app/Dash');
}, {
remember: "sessionOnly",
scope: "email,user_likes"
}).catch(function(error) {
if (error.code === "TRANSPORT_UNAVAILABLE") {
Auth.$authWithOAuthPopup("facebook").then(function(authData) {
// User successfully logged in. We can log to the console
// since we’re using a popup here
alert('done 2');
console.log(authData);
$location.path('app/Dash');
}, {
remember: "sessionOnly",
scope: "email,user_likes"
});
} else {
// Another error occurred
console.log(error);
alert('err');
}
});
Auth.$onAuth(function(authData) {
if (authData === null) {
console.log("Not logged in yet");
} else {
console.log("Logged in as", authData.uid);
console.log("Details",authData);
console.log("Name:",authData.facebook.displayName);
alert("Name:",authData.facebook.displayName);
console.log("gender:",authData.facebook.cachedUserProfile.gender);
console.log(" Email : ",authData.facebook.email);
$location.path('app/Dash');
}
$scope.authData = authData; // This will display the user's name in our view
});
};
**App.js**
// Ionic Starter App
// 'starter.controllers' is found in controllers.js
angular.module('starter', ['ionic', 'starter.controllers', 'ngCordovaOauth','firebase','ngFileUpload'])
.run(function($ionicPlatform) {
$ionicPlatform.ready(function() {
// Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
// for form inputs)
if (window.cordova && window.cordova.plugins.Keyboard) {
cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
cordova.plugins.Keyboard.disableScroll(true);
}
if (window.StatusBar) {
// org.apache.cordova.statusbar required
StatusBar.styleDefault();
}
});
})
.factory("Auth", function($firebaseAuth) {
var usersRef = new Firebase("https//*********.firebase***.****/****");
return $firebaseAuth(usersRef);
})
Please make a constant to use it everywhere in your App like that
.constant('facebookUrl', 'https://rjrestaurantapp.firebaseio.com');
Then in the controller inject this constant "facebookUrl & "$state" as shown below
.controller('loginCtrl', function($scope,facebookUrl,$state){
and then you only need to give name of the state where you want to redirect after facebook authentication..
var ref = new Firebase(facebookUrl);
$scope.fbLogin = function () {
ref.authWithOAuthPopup("facebook", function(error, authData) {
if (error) {
console.log("Login Failed!", error);
} else {
console.log("Authenticated successfully with payload:", authData);
$state.go('restaurant');
}
})
}})
and for email and likes you have to first make sure that these information is shown in the object of authData after successfull authentication ..
please read this doc carefully https://www.firebase.com/docs/web/guide/login/facebook.html

Clear rootscope ionic framework

Hi I'm doing a login for ionic app.....and I'm using rootscope like a global variable to use in all controller (LoginCtrl,SalirCtrl) When the user is log-in I save his info in a rootscope variable and show that info in SalirCtrl.
BUt when user log-out and other user log-in his info is not present in SalirCtrl.
Someone knows about that.
LoginCtrl
if($scope.datos=='true') {//if token is true. User is log-in
$rootScope.pNombre=data.persona.primerNombre;
$rootScope.sNombre=data.persona.segundoNombre;
$rootScope.pApellido=data.persona.primerApellido;
$rootScope.sApellido=data.persona.segundoApellido;
$state.go('tabs.perfil');
}
SalirCtrl
.controller('SalirCtrl', function($scope, $state, $ionicPopup, ServUsuario,$rootScope,$ionicHistory) {
//para bloquear el boton atras
$ionicHistory.nextViewOptions({
disableAnimate: true,
disableBack: true
});
//FIN para bloquear el boton atras
$scope.pNombre = $rootScope.pNombre;//save in a scope variable rootscope
$scope.sNombre = $rootScope.sNombre;
$scope.pApellido = $rootScope.pApellido;
$scope.sApellido = $rootScope.sApellido;
//METODO SALIR
$scope.salir = function() {
var confirmPopup = $ionicPopup.confirm({
title: 'Log-out',
template: '¿Log-out?'
});
confirmPopup.then(function(res) {
if(res) {
console.log('You are sure');
$state.go('login');
$scope.pNombre=" "; //When log-out is true. Variables equals empty
$scope.sNombre=" ";
$scope.pApellido=" ";
$scope.sApellido=" ";
} else {
console.log('You are not sure');
}
});
};
//FIN METODO SALIR
})
Finally I print that variables in perfil.html
{{pNombre}} {{sNombre}} {{pApellido}} {{sApellido}}
Thanks....!
My guess is that you're suffering from caching in the AngularJS UI-Router. In your route config, what happens when you do something like this?:
$stateProvider.state('myState', {
cache: false,
url : '/myUrl',
templateUrl : 'my-template.html'
})
By default Ionic caches the views as described here:
http://ionicframework.com/docs/api/directive/ionNavView/
When the views are cached your controllers don't reload during navigation. Let me know if that did the trick?
Best,
Your goal is to implement a User Service that can store user credentials and that can be accessed from all of your controllers. See an example implementation below:
angular.module('your-app').service('myUserService', myUserService);
function myUserService() {
var _identity = null;
return {
getUser: getUser,
setUser: setUser,
login: login,
logout: logout
...
};
function getUser() {
return _identity;
}
function setUser(user) {
_identity = user;
}
function login() {
//your login logic here
}
function logout() {
_identity = null;
//other logout logic
}
...
}

Event loop Angular. Some functions not running on app initialisation until a button is clicked? -FIREBASE

Background:
I have the following setup to authenticate retrieve my user and then retrieve his credentials. I am unclear on the event loop even after reading the documentation.
The Question:
The user is not displayed until I click a button? Every other kind of function runs on initialization like the alerts and stuff but why is my retrieve user function working until another button is pressed (pressing any button )?
Summary:
In order to retrieve the username for some reason I need to click something. I want the username to be retrieve on initialization .
crossfitApp.controller('globalIdCtrl', ["$scope",'$q','defautProfileData','$timeout', function ($scope,$q,defautProfileData,$timeout) {
$timeout(function() {
var dataRef = new Firebase("https://glowing-fire-5401.firebaseIO.com");
$scope.myFbvar =null;
$scope.authenticated={
currentUser: null,
avatarUrl: "",
emailAddress: "",
settings: "",
currentUserid: null,
};
function getProfile(userID){
myprofile= new Firebase("https://glowing-fire-5401.firebaseio.com/profiles/"+userID+"/username");
myprofile.once('value', function(nameSnapshot) {
$scope.authenticated.currentUser = nameSnapshot.val();
});
};
$scope.auth = new FirebaseSimpleLogin(dataRef, function(error, user) {
if (error) {
//Error
console.log ('error');
}
else if (user) {
//logged in
$scope.$apply(function(){getProfile(user.id);})
console.log('logged in');
$scope.authenticated.currentUserid = user.id ;//
}
else {
// user is logged out
console.log('logged out');
$scope.authenticated.currentUserid =null;
$scope.authenticated.currentUserid =null;
}
});
},100);
}]); //GlobaldCtrl
I would move most of your code to a service, and call the service from your controller, like this. I also included a deferred object in your login as I bet this is async
crossfittpApp.service('firebase',function($q) {
return {
getUser : function(authenticated) {
var dataRef = new Firebase("https://glowing-fire-5401.firebaseIO.com"),
myFbvar =null,
getProfile(userID) {
myprofile= new Firebase("https://glowing-fire-5401.firebaseio.com/profiles/"+userID+"/username");
myprofile.once('value', function(nameSnapshot) {
authenticated.currentUser = nameSnapshot.val();
});
},
deferredObj = $q.defer();
auth;
auth = new FirebaseSimpleLogin(dataRef, function(error, user) {
if (error) {
//Error
console.log ('error');
deferObj.reject();
}
else if (user) {
//logged in
getProfile(user.id);
console.log('logged in');
authenticated.currentUserid = user.id ;
deferObj.resolve(auth);
}
else {
// user is logged out
console.log('logged out');
authenticated.currentUserid =null;
deferObj.resolve();
}
}
return deferObj.promise;
}
}
});
crossfittpApp.controller('globalIdCtrl',function(firebase) {
$scope.authenticated = {
currentUser: null,
avatarUrl: "",
emailAddress: "",
settings: "",
currentUserid: null,
};
firebase.getUser(authenticated)
.then(function(_auth) {
$scope.auth = _auth;
},
function() {
//auth error here
});
});
You're not triggering Angular's HTML Compiler, so Angular doesn't know you've changed the JS variables.
Whenever you use an event like ng-click/ng-submit/etc, Angular fires $scope.$apply(), which checks for any changes to your $scope variables and applies them to the DOM, which is why it shows up after this.
You can correct this issue by alerting Angular that it needs to run $apply by using $timeout:
angular.controller('MyController', function($timeout) {
myprofile= new Firebase("https://glowing-fire-5401.firebaseio.com/profiles/"+userID+"/username");
myprofile.once('value', function(nameSnapshot) {
$timeout(function() {
authenticated.currentUser = nameSnapshot.val();
});
});
auth = new FirebaseSimpleLogin(dataRef, function(error, user) {
if (error) {
//Error
console.log ('error');
}
else if (user) {
$timeout(function() {
authenticated.currentUserid = user.id ;
});
}
else {
$timeout(function(){
authenticated.currentUserid =null;
});
}
});
});
You should utilize angularFire, which abstracts these complexities.
There are some more questions like this one here, here, and here.

Resources