Angular rootScope works then goes undefined on refresh - AngularFire - angularjs

Scenario: I assign some values for the user at login to my rootScope. Now I want to able to use those values so that every time the user post a meeting, it should be added under his information in Firebase db.
Issue: I do this well, when I login, and i post the meeting from the user. But then as soon as the page refreshes, rootScope.currentUser becomes undefined. How can I keep rootScope.currentUser from going undefined? My Controller and my factory are below:
my controller:
myApp.controller('MeetingsController', function($scope, $firebaseObject, $firebaseArray, $rootScope, FIREBASE_URL, SomeURL){
//rootScope.currentUser.$id works the first time i post then the second it doesn't
var ref = new Firebase(FIREBASE_URL + $rootScope.currentUser.$id + SomeURL);
var meetings = $firebaseObject(ref);
$scope.meetings = meetings;
$scope.addMeeting = function(){
ref.push({
name: $scope.meetingname,
date: Firebase.ServerValue.TIMESTAMP
});
};
});//controller for around me
My Factory:
myApp.factory('Authentification', function($firebase, $rootScope, $firebaseObject, $firebaseAuth, $routeParams, $location, FIREBASE_URL){
var ref = new Firebase(FIREBASE_URL);
var auth = $firebaseAuth(ref);
auth.$onAuth(function(authUser){
if(authUser){
var firebaseUsers = new Firebase(FIREBASE_URL+'/users/'+authUser.uid);
var user = $firebaseObject(firebaseUsers);
$rootScope.currentUser = user;
} else {
$rootScope.currentUser = '';
}
});
var myObject = {
login: function(user){
return auth.$authWithPassword({
email: user.email,
password: user.pswd
});
},
logout: function(user){
return auth.$unauth();
},
requireAuth: function() {
return auth.$requireAuth();
}
};
return myObject;
});
Route:
myApp.config( ['$routeProvider', function($routeProvider){
$routeProvider.
when('/login', {
templateUrl: 'views/login.html',
controller: 'RegistrationController'
}).
when('/register',{
templateUrl: 'views/register.html',
controller: 'RegistrationController'
}).
when('/aroundme', {
templateUrl: 'views/aroundme.html' ,
controller: 'MeetingsController',
resolve: {
currentAuth: function(Authentification){
return Authentification.requireAuth();
}
}
}).
otherwise({
redirectTo: '/'
});
}]);

The issue might be that you're assigning the $firebaseObject to the $rootScope before it has finished loading. To make sure that it has loaded before binding it to the $rootScope use $loaded():
auth.$onAuth(function(authUser){
if(authUser){
var firebaseUsers = new Firebase(FIREBASE_URL+'/users/'+authUser.uid);
var user = $firebaseObject(firebaseUsers);
user.$loaded()
.then(function(data) {
$rootScope.currentUser = data;
})
.catch(function(err) {
// Handle error
});
} else {
$rootScope.currentUser = '';
}
});
From the docs:
Note that the data will not be available immediately since retrieving it is an asynchronous operation. You can use the $loaded() promise to get notified when the data has loaded.

Related

angularjs redircet to login page if not login

I am using Laravel angularjs
I am using this package https://github.com/andbet39/tokenAuth
it's working fine but my problem is without login i can go to any page also once i reload the page user name is disabled
I don't know what is the problem here
app.js
var app = angular.module('todoApp', ['ui.router', 'satellizer'])
.config(function($stateProvider, $urlRouterProvider, $authProvider,$provide) {
$authProvider.loginUrl = '/api/authenticate';
$urlRouterProvider.otherwise('/login');
$stateProvider
.state('login', {
url: '/login',
templateUrl: '/js/tpl/login.html',
controller: 'AuthController'
})
.state('register', {
url: '/register',
templateUrl: '/js/tpl/register.html',
controller: 'AuthController'
})
.state('todo', {
url: '/todo',
templateUrl: '/js/tpl/todo.html',
controller: 'TodoController'
});
function redirectWhenLoggedOut($q, $injector) {
return {
responseError: function (rejection) {
var $state = $injector.get('$state');
var rejectionReasons = ['token_not_provided', 'token_expired', 'token_absent', 'token_invalid'];
angular.forEach(rejectionReasons, function (value, key) {
if (rejection.data.error === value) {
localStorage.removeItem('user');
$state.go('login');
}
});
return $q.reject(rejection);
}
}
}
$provide.factory('redirectWhenLoggedOut', redirectWhenLoggedOut);
});
TodoController.js
app.controller('TodoController', function($state,$http,$rootScope, $scope,$auth) {
$scope.todos=[];
$scope.newTodo={};
$scope.init = function (){
$http.get('/api/todo').success(function(data){
$scope.todos=data;
})
};
$scope.save = function(){
$http.post('/api/todo',$scope.newTodo).success(function (data) {
$scope.todos.push(data);
$scope.newTodo={};
});
};
$scope.update = function(index){
$http.put('/api/todo/'+ $scope.todos[index].id,$scope.todos[index]);
};
$scope.delete = function(index){
$http.delete('/api/todo/'+ $scope.todos[index].id).success(function(){
$scope.todos.splice(index,1);
});
};
$scope.logout = function() {
$auth.logout().then(function() {
localStorage.removeItem('user');
$rootScope.authenticated = false;
$rootScope.currentUser = null;
});
}
$scope.init();
});
AuthController.js
app.controller('AuthController', function($auth, $state,$http,$rootScope, $scope) {
$scope.email='';
$scope.password='';
$scope.newUser={};
$scope.loginError=false;
$scope.loginErrorText='';
$scope.login = function() {
var credentials = {
email: $scope.email,
password: $scope.password
}
$auth.login(credentials).then(function() {
return $http.get('api/authenticate/user');
}, function(error) {
$scope.loginError = true;
$scope.loginErrorText = error.data.error;
}).then(function(response) {
// var user = JSON.stringify(response.data.user);
// localStorage.setItem('user', user);
$rootScope.authenticated = true;
$rootScope.currentUser = response.data.user;
$scope.loginError = false;
$scope.loginErrorText = '';
$state.go('todo');
});
}
$scope.register = function () {
$http.post('/api/register',$scope.newUser)
.success(function(data){
$scope.email=$scope.newUser.email;
$scope.password=$scope.newUser.password;
$scope.login();
})
};
});
I want to redirect to login page if authandicate is falied
How to fix this ?
In angularjs 1.4+ there is no
$http.get('/api/todo').success(function(data){
$scope.todos=data;
})
What you should do instead
$http.get('/api/todo').then(function(data){
$scope.todos=data;
})
And same with this $http.post which you have below.
Also after refreshing page rootScope is deleted and that is why nickname is blank after refresh.
You probably want to store nickname in localStorage or async promise based localForage.
If you chose async localForage on login you can emit custom event with rootScope and execute some function on this event which gather nickname from localForage. You might want to execute this function in some external controller which would wrap all app so when you assign $scope.nick you will have access to it across entire app. Same with $scope.auth = true, you will be able to build your app basing on this boolean for logged in using ng-if directive.
Inject $location to your controller as function parameter and try to redirect like so
$location.path('/todo' );
or
$location.url(YOUR_URL);
Also I don't really understand why you are doing two backend call for login, one inside another. You probably should do one $http.post which would return token in response. Then you could fix and simplify your function code to
$scope.login = function() {
var credentials = {
email: $scope.email,
password: $scope.password
}
$auth.login(credentials).then(function(response) {
$rootScope.authenticated = true;
$rootScope.currentUser = response.data.user;
$scope.loginError = false;
$scope.loginErrorText = '';
}, function(error) {
$scope.loginError = true;
$scope.loginErrorText = error.data.error;
$location.path('/todo' );
});
}
However I don't know your code from $auth service.
Remember to inject $location service.
redirectWhenLoggedOut seems to be an http interceptor.
I think the idea is that you redirect when the http call was not successful. So you need to add an http interceptor that catches the http error and redirects to the login page.
$httpProvider.interceptors.push('redirectWhenLoggedOut');
Don't forget to inject the $httpProvider;

$scope value does not udate - Angularfire

I'm having a problem with my code. $scope value is not updating after $createUserWithEmailAndPassword. but if i do alert($scope.message), I can see the alert. Where am i going wrong?
I'm using all the updated files from firebase and Angularfire.
My app.js
`
var spaapp = angular.module('spaapp', ['ngRoute', 'firebase']);
spaapp.config(['$routeProvider', function ($routeProvider) {
$routeProvider.
when('/login', {
templateUrl: 'login.html',
controller: 'spaController'
}).
when('/register', {
templateUrl: 'register.html',
controller: 'spaController'
}).
when('/success', {
templateUrl: 'success.html',
controller: 'spaController'
}).
otherwise({
redirectTo: '/Main'
});
}]);
'
My Controller
spaapp.factory("Auth", ["$firebaseAuth",
function($firebaseAuth) {
return $firebaseAuth();
}
]);
spaapp.controller('spaController', ['$scope','$rootScope', 'Auth',function ($scope,$rootScope,Auth) {
// $scope.authObj=firebaseAuth();
//var auth = Auth;
$scope.login = function () {
}
$scope.register = function () {
var email = $scope.user.email;
var password = $scope.user.password;
Auth.$createUserWithEmailAndPassword(email, password).then(function(regUser){
$scope.message="Hi" + regUser.uid;
console.log("Signed in as:" + regUser.uid );
}).catch(
function(error) {
var errorCode = error.code;
var errorMessage = error.message;
console.log(error.message);
$scope.message = error.message;
});
};
}]);
Any help is appreciated.
Thanks
You can refresh angular's $scope by calling $apply() on $scope
Example:
spaapp.factory("Auth", ["$firebaseAuth",
function($firebaseAuth) {
return $firebaseAuth();
}
]);
spaapp.controller('spaController', ['$scope','$rootScope', 'Auth',function ($scope,$rootScope,Auth) {
// $scope.authObj=firebaseAuth();
//var auth = Auth;
$scope.login = function () {
}
$scope.register = function () {
var email = $scope.user.email;
var password = $scope.user.password;
Auth.$createUserWithEmailAndPassword(email, password).then(function(regUser){
$scope.message="Hi" + regUser.uid;
console.log("Signed in as:" + regUser.uid );
}).catch(
function(error) {
var errorCode = error.code;
var errorMessage = error.message;
console.log(error.message);
$scope.message = error.message;
$scope.$apply() // HERE
});
};
}]);
More about angular's digest loop at:
http://jimhoskins.com/2012/12/17/angularjs-and-apply.html

Passing Service data from module config to Controller from $routeProvider?

I am really new to angular and have been reading a number of tutorials etc and have the following problem:
search-module.js
var Search = angular.module('SearchApp',["ngCookies","ngRoute"]);
Search.run(function ($http, $cookies) {
$http.defaults.headers.common['X-CSRFToken'] = $cookies['csrftoken'];
});
Search.config(function($routeProvider){
$routeProvider
.when('/', {
controller:'searchCtrl',
resolve: {
inv_items: function (InventoryService){
return InventoryService.get('red');
}
}
})
.otherwise({
redirectTo: '/'
})
});
data-service.js
Search.factory('InventoryService', function ($http, $q) {
var api_url = "api/inventory/";
return {
get: function (inventory) {
var url = api_url + inventory;
var defer = $q.defer();
$http({method: 'GET', url: url}).
success(function (data, status, headers, config){
defer.resolver(data);
})
.error(function (data,status, headers, config){
defer.reject(status);
});
return defer.promise;
}
}
});
search-controller.js
Search.controller('searchCtrl', function($scope){
$scope.selected = 'have';
$scope.setSection = function(section){
$scope.selected = section;
};
$scope.isSelected = function(section){
return $scope.selected == section;
};
});
Like I mentioned previously I am really new to angular just picked it up yesterday. Basically from what I have written I understand that when the URL is '/' then the service will be initiated and the controller will be called? What I want to know is why cant I use inv_items in my controller? I get the following error.
Do I need to pass some sort of global to the controller which will contain inv_items or am I missing some important piece of knowledge?
Thanks!
The resolve variable 'inv_items' isn't automatically added to your scope of 'searchCtrl'.
Search.controller('searchCtrl', function($scope, inv_items){ //Add this
$scope.inv_items = inv_items; //And this
$scope.selected = 'have';
$scope.setSection = function(section){
$scope.selected = section;
};
$scope.isSelected = function(section){
return $scope.selected == section;
};
});
Granted that the rest of the code works, your 'inv_items' should now be available in that scope.

View loads before $scope values are assigned

I've come to this problem were my view loads before $scope params are assigned and this is caused by $http service call taking some time before response is achived.
This leaves me with dropdown boxes being unsync with url params on page reload...
Is there anyway to reload these $scope params or wait til they get values before rendering the view? I would like the easiest solution to this as Im yet farily new to angularjs.
Just give me a hint if more info is needed!
Here's some of the code...
Route
angular.module('app', ['ngRoute', 'app.controller', 'app.service', 'app.filter'])
.config(['$routeProvider', function($routeProvider) {
$routeProvider
.when('/order/:id', {
templateUrl: '../../App_AngularJs/partials/specificOrder.htm',
controller: 'orderController',
reloadOnSearch: true
})
.when('/orderitem/:id', {
templateUrl: '../../App_AngularJs/partials/orderItem/orderItem.htm',
controller: 'orderItemController',
reloadOnSearch: true
})
.when('/', {
templateUrl: '../../App_AngularJs/partials/searchOrder.htm',
controller: 'ordersController',
reloadOnSearch: false
//Use some resolve here!? How!?
});
}
Controller
var orderContrl = angular.module('app.controller', ['angularTreeview', 'ui.bootstrap'])
.controller('ordersController', [
'$scope', '$routeParams', '$location', '$filter', '$modal', '$log', 'orderService',
function ($scope, $routeParams, $location, $filter, $modal, $log, orderService) {
init();
function init() {
$scope.searchtext = $routeParams.search || '';
$scope.page = $routeParams.page || 1;
$scope.take = $routeParams.take || 10;
$scope.status = $routeParams.status || -1;
$scope.group = $routeParams.group || -1;
$scope.type = $routeParams.type || -1;
$scope.category = $routeParams.category || -1;
$scope.selectedOrganisation = "Knoc LK";
getOrders(true);
getFilters(true);
}
function getFilters(reloadPage) {
orderService.queryOrderAllDropdown()
.then(function (response) {
$scope.orderGroup = response.OrderGroups;
$scope.orderStatus = response.OrderStatus;
$scope.orderType = response.OrderTypes;
$scope.orderPackageCategory = response.ProductPackageCategories;
$scope.orderAllCategory = response.ProductItemCategories;
//Sets type and shows different categories depending on type chosen
getCategory();
//Trying to reassign the values but still nothing...
if (reloadPage) {
angular.forEach($scope.orderStatus, function (value) {
if ($routeParams.status == value.ID)
$scope.status = value.ID;
});
//Trying to reassign the values but still nothing...
$scope.group = $scope.group;
}
},
function (errorMessage) {
$scope.error = errorMessage;
});
}
Service
angular.module('app.service', [])
.service('orderService', ['$http', '$q', function ($http, $q) {
this.queryOrderAllDropdown = function () {
var deferred = $q.defer();
$http({
type: 'GET',
url: 'GenericHandlers/HttpOrderService.ashx',
method: 'GetOrderAllDropdown',
headers: { 'Content-Type': 'text/plain' }
}).success(function (data) {
deferred.resolve(data);
}).error(function () {
deferred.reject("An error occured while fetching data");
});
return deferred.promise;
},
You need to use a Resolver to fetch the data from the backend. Adding a "resolve" to the $routeProvider will fetch the data before the controller takes control. Check out this blog post for a similar example.

AngularJS Service Passing Data Between Controllers

When using an AngularJS service to try and pass data between two controllers, my second controller always receives undefined when trying to access data from the service. I am guessing this is because the first service does a $window.location.href and I'm thinking this is clearing out the data in the service? Is there a way for me to change the URL to a new location and keep the data persisted in the service for the second controller? When I run the code below the alert in the second controller is always undefined.
app.js (Where Service is Defined)
var app = angular.module('SetTrackerApp', ['$strap.directives', 'ngCookies']);
app.config(function ($routeProvider)
{
$routeProvider
.when('/app', {templateUrl: 'partials/addset.html', controller:'SetController'})
.when('/profile', {templateUrl: 'partials/profile.html', controller:'ProfileController'})
.otherwise({templateUrl: '/partials/addset.html', controller:'SetController'});
});
app.factory('userService', function() {
var userData = [
{yearSetCount: 0}
];
return {
user:function() {
return userData;
},
setEmail: function(email) {
userData.email = email;
},
getEmail: function() {
return userData.email;
},
setSetCount: function(setCount) {
userData.yearSetCount = setCount;
},
getSetCount: function() {
return userData.yearSetCount;
}
};
});
logincontroller.js: (Controller 1 which sets value in service)
app.controller('LoginController', function ($scope, $http, $window, userService) {
$scope.login = function() {
$http({
method : 'POST',
url : '/login',
data : $scope.user
}).success(function (data) {
userService.setEmail("foobar");
$window.location.href = '/app'
}).error(function(data) {
$scope.login.error = true;
$scope.error = data;
});
}
});
appcontroller.js (Second controller trying to read value from service)
app.controller('AppController', function($scope, $http, userService) {
$scope.init = function() {
alert("In init userId: " userService.getEmail());
}
});
Define your service like this
app.service('userService', function() {
this.userData = {yearSetCount: 0};
this.user = function() {
return this.userData;
};
this.setEmail = function(email) {
this.userData.email = email;
};
this.getEmail = function() {
return this.userData.email;
};
this.setSetCount = function(setCount) {
this.userData.yearSetCount = setCount;
};
this.getSetCount = function() {
return this.userData.yearSetCount;
};
});
Check out Duncan's answer here:
AngularJS - what are the major differences in the different ways to declare a service in angular?

Resources