I am getting an error retrieving current user id from my factory/service. Removing this firebase.auth().currentUser.uid seems to work.Am I missing something?Is it possible to get user id from factory?
.factory("dataFire", ["$firebaseArray", "$firebaseAuth", "$firebaseObject", function($firebaseArray, $firebaseAuth, $firebaseObject){
var ref = firebase.database().ref("users/" + firebase.auth().currentUser.uid);
var user = $firebaseObject(ref);
return {
user: user
} }])
jsfiddle link
https://jsfiddle.net/ken19net/m8qkdrpu/37/
Your code that attach the listener to the database, runs before the user is signed in. Since there is no current user at that point firebase.auth().currentUser.uid will throw the following error:
VM603 angular.min.js:118 TypeError: Cannot read property 'uid' of null
In future questions please include the error message, as it would've saved us both some time.
The solution is to attach the listener after the user has been authenticated:
app.controller("appCtrl", function($scope, $firebaseAuth, myService) {
$scope.signIn = function() {
$firebaseAuth().$signInAnonymously().then(function(user) {
var ref = firebase.database().ref("test/" + firebase.auth().currentUser.uid);
});
};
});
Note that running your code like above will create a new anonymous user account every time the user loads the page. If that is not what you want, use an auth state listener:
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
var ref = firebase.database().ref("test/" + firebase.auth().currentUser.uid);
}
});
See the documentation on getting the currently signed in user.
I might of had a similar problem. This might help.
if (firebase.auth().currentUser !== null) {
console.log("user id: " + firebase.auth().currentUser.uid);
var ref = firebase.database().ref().child("users/" + firebase.auth().currentUser.uid);
var syncUserObject = $firebaseObject(ref);
syncUserObject.$bindTo($scope, "data");
} else {
console.log("No user currently logged in");
}
if all else fails then just JSON.stringify(Object ,null, 2);
Related
This is a controller where I am getting some data from firebase and updating my scope, then I want to do some more stuff once that scope is updated:
.controller('loginCtrl', ['$scope','$firebaseAuth','$firebaseObject','$location',
'localStorageService','$q',
function($scope,$firebaseAuth,$firebaseObject,$location,
localStorageService,$q) {
// Called
$scope.googleAuth = function(){
var auth = $firebaseAuth();
auth.$signInWithPopup("google").then(function(firebaseUser){
// Google approved
// Step 1. Get user profile
getProfile(firebaseUser);
}).catch(function(error){
console.log("Authentication failed:",error);
$scope.errorMsg = "Something went wrong. Please try again."
});
}
// Watchers
$scope.$on('profile',function(){
console.info("REACH");
if($scope.profile == null){ // User doesn't exist
console.info("profile null");
if(isAssigned(firebaseUser) != null){
// Redirect to create a profile page
} else {
// Do not let them in TODO: adjust the text
$scope.erorrMsg = "It seems you don't have a profile. Please contact us on ----------- to get a profile";
}
} else {
// Step 2. Get user parent info
// getParent($scope.profile.current_centre_id,$scope.profile.refer_id);
console.info("Getting parent");
getParent('-KeVj_sr-uCY3zx0kbb6','-KeVpUA4OIK4msNIl0gQ');
}
});
// After getting parent info
$scope.$on('parent',function(){
localStorageService.set('currentUser',{
profile: $scope.profile,
parent: $scope.parent
});
});
var getProfile = function(firebaseUser){
var email = firebaseUser.user.email;
var ref = firebase.database().ref();
// Getting profile
$scope.profile = $firebaseObject(ref.child('profiles').orderByChild('email').equalTo('dev.beezbutt#gmail.com'));
}
var getParent = function(centre_id,parent_id){
$scope.parent = $firebaseObject(ref.child('parents/'+centre_id+'/'+parent_id));
}
var isAssigned = function(firebaseUser){
// TODO
return false;
}
}]);
$scope.$on('profile') & $scope.$on('parent') are not being triggered, and I'm not sure why or what am I missing.
I know that $scope.profile is being set because I'm printing it in html.
Instead of $scope.$on, use $scope.$watch to watch the scope variables.
$scope.$watch("scope_variable_name", function(newVal, oldVal){
// Add your code here
});
I am developping a web app with Ionic 1 and AngularJS 1.
In my factory (UserFact) :
.factory('UserFact', function() {
var user = [];
return {
'setUser': function(user) {
this.user = user;
console.log('(2) User set: ' + this.user);
console.log('(3) User id is now: ' + this.user.uid);
},
'updateSport': function(sportid, registered) {
console.log('Update sport: ' + sportid + ' --> ' + registered);
console.log('(4) For user uid: ' + this.user.uid);
var ref = firebase.database().ref('users/' + this.user.uid + '/sports/');
// sync down from server
var list = [];
ref.on('value', function(snap) { list = snap.val(); });
if(registered) {
list.splice(0, 0, {id: sportid});
} else {
}
ref.set(list);
}
};
})
In my controller :
function ($scope, $stateParams, $state, DatabaseFact, UserFact) {
// variables
$scope.sports = [];
$scope.sports = DatabaseFact.getSports();
// functions
$scope.updateSport = UserFact.updateSport;
// execution
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
UserFact.setUser(user);
console.log('(1) Ctrl user uid: ' + user.uid);
}
});
}
According to the console: logs (1), (2) and (3) display a userid form my db but (4) is always undefined...
Any idea?
Thanks
UPDATE:
Manuel, sorry, I think I had missed the point of your question. You are correct, using a factory/service, is the correct way to store the state of your application. From the above, I do not see a reason for your code not work. The user must be getting re-assigned elsewhere for you to be seeing undefined in (4), if you are not seeing the same in (3). For simplicity sake, I removed references to firebase and created a working demo: https://plnkr.co/edit/vaN7ySche8GgRQmZgFsa?p=preview
While the demo may not solve your problem, I hope it illustrates that the factory variable (user) is persisted in memory and usable across multiple factory method calls.
ORIGINAL ANSWER (MISSED THE POINT) BELOW:
Update the state change handler to save the user on the controller scope:
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
$scope.user = user;
UserFact.setUser(user);
console.log('(1) Ctrl user uid: ' + user.uid);
}
});
Then, in the template, invoke the updateSport method, using the user scope variable:
updateSport(user, true);
or
updateSport(user, false);
You need to pass the arguments while calling updateSport in controller,
$scope.updateSport = UserFact.updateSport(userid,registered);
This question already has an answer here:
How come Angular doesn't update with scope here?
(1 answer)
Closed 6 years ago.
I have a Firebase function inside an angular controller. There is a button that when clicked takes the selected option and the type input and stores them into the user's object like so:
{
selected-option : input-value
}
This works perfectly, but only works when the view is changed. In my case both airlines already have data so this function displays an $ionicPopup.
After the view has changed once the functionality is absolutely perfect. This is obviously a problem and I assume it is an $apply or $digest issue.
Here is my controller code (Supected location marked by "ISSUE RIGHT HERE"):
.controller('ProgramCtrl', ['$scope', '$state', '$firebaseArray', 'facebook', '$ionicPopup', '$ionicLoading',
function($scope, $state, $firebaseArray, facebook, $ionicPopup, $ionicLoading) {
$scope.goBack = function() {
$state.go('app.home');
}
$scope.show = function() {
$ionicLoading.show({
template: 'Loading...'
});
};
$scope.hide = function(){
$ionicLoading.hide();
};
// Get who is logged in
$scope.user = facebook.get();
// Array of airlines
var airRef = ref.child("airlines");
$scope.airlines = $firebaseArray(airRef);
$scope.selectedAir = {};
$scope.miles = {};
$scope.revealInput = function(num) {
// Jquery variables
$milesPoints = $(".milesPoints");
$saveTicket = $(".saveTicket");
// Will fade in visibility depending on num passed into function
switch(num) {
case 1:
$saveTicket.prop("disabled", false);
$saveTicket.fadeTo(400, 1);
break;
default:
break;
}
}
// Add program to user
$scope.addProgram = function () {
// Connect to Firebase
Firebase.goOnline();
// Check for facebook user
if(jQuery.isEmptyObject($scope.user)) {
// Get Firebase user
var authData = ref.getAuth();
var theUser = ref.child("users").child(authData.uid);
var selected = {};
// Access user miles data
// $scope.show();
// ISSUE RIGHT HERE
theUser.child("miles").child($scope.selectedAir.name.$id).once("value", function(snapshot) {
// Update scopes
var exist = snapshot.exists();
// Check if object id exists, if so notify user
if(!exist) {
// Save and update program to user object
selected[$scope.selectedAir.name.$id] = $scope.miles.num;
theUser.child("miles").update(selected);
//$scope.hide();
$state.go("app.saved");
} else {
// Popup alert
var alertPopup = $ionicPopup.alert({
title: 'Oops!',
template: "You already created this airline! Go to the 'Add Ticket' page to add more points."
});
alertPopup.then(function(res) {
console.log("You already created this airline! Go to the 'Add Ticket' page to add more points.");
});
}
})
} else {
var theUser = ref.child("users").child($scope.user.id);
var selected = {};
$scope.show();
theUser.child("miles").child($scope.selectedAir.name.$id).once("value", function(snapshot) {
var exist = snapshot.exists();
if(!exist) {
selected[$scope.selectedAir.name.$id] = $scope.miles.num;
theUser.child("miles").update(selected);
$scope.hide();
$state.go("app.saved");
} else {
var alertPopup = $ionicPopup.alert({
title: 'Oops!',
template: "You already created this airline! Go to the 'Add Ticket' page to add more points."
});
alertPopup.then(function(res) {
console.log("You already created this airline! Go to the 'Add Ticket' page to add more points.");
});
}
})
}
}
}])
Thanks for the help and I can provide more code or screenshots if needed.
The issue is in this piece of code:
theUser.child("miles").child($scope.selectedAir.name.$id).once("value", function(snapshot) {
$timout(function() {
var exist = snapshot.exists();
// Check if object id exists, if so notify user
if(!exist) {
// Save and update program to user object
selected[$scope.selectedAir.name.$id] = $scope.miles.num;
theUser.child("miles").update(selected);
//$scope.hide();
$state.go("app.saved");
} else {
// Popup alert
var alertPopup = $ionicPopup.alert({
title: 'Oops!',
template: "You already created this airline! Go to the 'Add Ticket' page to add more points."
});
alertPopup.then(function(res) {
console.log("You already created this airline! Go to the 'Add Ticket' page to add more points.");
});
}
});
})
When you call once(), it starts loading data from Firebase. Since this may take some time, you pass in a callback function that is invoked when the data is available. But by the time the callback function is invoked, AngularJS is not expecting updates to the $scope anymore.
The solution is to wrap the code into a $timeout(), which ensures it gets executed when AngularJS is ready to handle scope changes again:
theUser.child("miles").child($scope.selectedAir.name.$id).once("value", function(snapshot) {
// Update scopes
var exist = snapshot.exists();
// Check if object id exists, if so notify user
if(!exist) {
// Save and update program to user object
selected[$scope.selectedAir.name.$id] = $scope.miles.num;
theUser.child("miles").update(selected);
//$scope.hide();
$state.go("app.saved");
} else {
// Popup alert
var alertPopup = $ionicPopup.alert({
title: 'Oops!',
template: "You already created this airline! Go to the 'Add Ticket' page to add more points."
});
alertPopup.then(function(res) {
console.log("You already created this airline! Go to the 'Add Ticket' page to add more points.");
});
}
})
Note that this problem wouldn't happen if you used AngularFire's $firebaseObject() and $firebaseArray() primitives, since those automatically notify AngularJS of scope changes.
We get this question a lot. Here's a recent one: Taking long to load
I've run into multiple TypeErrors with the Thinkster.io AngularJS Tutorial: Learn to build Modern Webapps Chapter 7. Creating your own user data using firebase since the tutorial is now outdated after AngularFire was upgraded to v0.8.0. Specifically the .$child() and .$on() methods have been taken out. Here is the change log
https://github.com/firebase/angularfire/releases/tag/v0.8.0
After getting help solving my initial TypeError issues during registering a new user, I began to see 2 new TypeErrors show up when I submit a post and when I try to delete a post. Once again the culprits are the outdated .$child() and .$on() methods.
Submitting a Post > TypeError: undefined is not a function
After submitting a post I see the following TypeError show up in the console
This TypeError points to the post.js service
TypeError: undefined is not a function
at http://localhost:9000/scripts/services/post.js:16:11
which is line 16, column 11 at the beginning of the $child method call. Also, note the second .&child() following the first. That will result in another TypeError.
return posts.$add(post).then(function(ref) {
var postId = ref.name();
user.$child('posts').$child(postId).$set(postId);
return postId;
});
I will mention that even though I get this TypeError, I'm still able to successfully create a post and I see it in the Forge and in the app's post list.
Deleting a Post > TypeError: undefined is not a function
When I try to delete a post that I just created I get another TypeError related to the now deprecated .$on() method.
TypeError: undefined is not a function
at Object.Post [as delete] (http://localhost:9000/scripts/services/post.js:27:10)
at Scope.$scope.deletePost (http://localhost:9000/scripts/controllers/posts.js:10:14)
which points to the .$on() in this code in the post.js service
delete: function(postId) {
if(User.signedIn()) {
var post = Post.find(postId);
post.$on('loaded', function(){
var user = User.findByUsername(post.owner);
posts.$remove(postId).then(function(){
user.$child('posts').$remove(postId);
});
});
}
}
I realize that I will have to do something like
post.$loaded(function(result) {Chapter 7. Creating your own user data using firebase
// something related to finding user of post
// remove post from posts collection
// but of course we can't use .$child()
});
but the problem is that when a JS beginner like me comes along faced with the AngularFire change logs and API, I just get lost and overwhelmed to the point of shut down. Any guidance is greatly appreciated as always.
FILES
post.js service
'use strict';
app.factory('Post', function($firebase, FIREBASE_URL, User){
var ref = new Firebase(FIREBASE_URL + 'posts');
var posts = $firebase(ref).$asArray();
var Post = {
all: posts,
create: function(post) {
if(User.signedIn()) {
var user = User.getCurrent();
post.owner = user.username;
return posts.$add(post).then(function(ref) {
var postId = ref.name();
user.$child('posts').$child(postId).$set(postId);
return postId;
});
}
},
find: function(postId) {
return $firebase(ref.child(postId)).$asObject();
},
delete: function(postId) {
if(User.signedIn()) {
var post = Post.find(postId);
post.$on('loaded', function(){
var user = User.findByUsername(post.owner);
posts.$remove(postId).then(function(){
user.$child('posts').$remove(postId);
});
});
}
}
};
return Post;
});
post.js controller
'use strict';
app.controller('PostsCtrl', function($scope, $location, Post) {
$scope.posts = Post.all;
$scope.post = {url: 'http://', title: ''};
$scope.deletePost = function(post) {
Post.delete(post);
};
});
I was fed up, so I took a easy approach (just to get trough the tutorial). I created userRef (this should come from the User object imo):
modulename.factory("Post", function ($firebase, FIREBASE_URL, User) {
//rest code
var userRef = new Firebase(FIREBASE_URL + "users");
var Post = {
create: function(){
//rest of the code
return posts.$add(post).then(function (ref) {
var postId = ref.name();
userRef.child(user.$id).child("posts").child(postId).set(postId);
return postId;
});
}
}
});
This is just one approach, when I was searching for a good solution, I saw some more example codes. I hope it helps a little bit.
I'm trying to maintain session after page refresh in angularjs using java. I have seen many examples but, i didn't find proper solution which exactly I'm looking for.
Please find below login snippet code, when i click on login button it is calling loginUser()function in LoginController
When i do page refresh it is going to LoginController but it is not going inside loginUser()function.
According to my knowledge until we call function, it doesn't goes inside of it.
When I do refresh how can i call back loginUser() function.
please help me out from these. Appreciated..Many thanks.
LoginController.js
function LoginController($scope, $http, $location, $rootScope,
userService, SessionIdService) {
$scope.user = {};
$scope.user.username = '';
$scope.user.password = '';
$rootScope.loginUser = function(username, password) {
$scope.resetError();
$http.post('/user/main/login/' + username, password).success(
function(login) {
if (login.sessionId === null) {
$scope.setError(login.status);
return;
} else {
$rootScope.userlogin = login.uname;
userService.setUserName(login.uname);
SessionIdService.setSessionId(login.sessionId);
$location.path("/home");
}
}).error(function() {
$scope.setError('Invalid user/password combination');
});
};
$scope.resetError = function() {
$scope.error = false;
$scope.errorMessage = '';
};
$scope.setError = function(message) {
$scope.error = true;
$scope.errorMessage = message;
$rootScope.sees = '';
$rootScope.userlogin = '';
};
};
app.js
app.run(function($rootScope, $location, SessionIdService) {
$rootScope.$on("$routeChangeStart", function(event, next, current) {
console.log("Routechanged... ");
if (SessionIdService.getSessionId == "true") {
if (next.templateUrl == "scripts/views/homescreen.html") {
$location.path("/home");
} else {
$location.path("/screen");
}
}
});
});
login.html
<input name="textfield" type="text" ng-model="user.username"/>
<input name="textfield" type="password" ng-model="user.password"/>
<button type="button" ng-lick="loginUser(user.username,user.password)">Login</button>
It is not clear to me why you want to call loginUser after page refresh. Isn't the user already logged in? I think what you want is to call the success function inside the loginIser. In that case, you need to embed that data as a global JS variable inside your Java template, and pass that to your controller somehow.
You probably want these to be run after refresh:
$rootScope.userlogin = login.uname;
userService.setUserName(login.uname);
SessionIdService.setSessionId(login.sessionId);
$location.path("/home");
So, in your Java template, do something like:
<script>window.UNAME = {% this comes from your database %};window.SESSIONID={% similar %}</script>
Then, call that function somehow with window.UNAME as input. (or in your controller, check for the existence of window.UNAME and call it immediately. Something like:
window.UNAME && function (name, sessionId) {
$rootScope.userlogin = uname;
userService.setUserName(uname);
SessionIdService.setSessionId(sessionId);
$location.path("/home");
) {
}(window.UNAME, window.SESSION_ID)
Some other recommendations (unrelated to your main problem probably):
First of, change $rootScope.loginUser = function(username, password) { to
$rootScope.loginUser = function() {
var username = $scope.user.username;
var password = $scope.user.password
since you already have access to username and password there. So, change ng-click="loginUser()".
Second, SessionIdService.getSessionId == "true" seems off, check should probably be just SessionIdService.getSessionId