Javascript scope not updating global variable - javascript

I'm sitting in my js file trying to upload but for some reason, I don't understand entirely. My :: myUid isn't updating. Can anyone tell me how to fix it and maybe even why it's the case that myUid isn't updating?
var myUid = '33';
firebase.auth().signInAnonymously().catch(function(error) {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
// ...
});
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
// User is signed in.
var isAnonymous = user.isAnonymous;
window.myUid = user.uid;
// ...
} else {
// User is signed out.
// ...
}
// ...
});
function writeUserData() {
database.ref('users/').set({
profileID: myUid,
});
};
writeUserData();
Best regards, Sam

myUid value is updated only when the callback for onAuthStateChanged is executed asynchronously. By the time you invoke the writeUserData() function on your main execution flow, the above callback may not be have been completed yet.
So a better approach would be to get rid of the global variable and invoke the writeUserData function from the onAuthStateChanged callback, passing the user uid as a parameter.
function writeUserData(userUid) {
database.ref('users/').set({
profileID: userUid,
});
};
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
// User is signed in.
var isAnonymous = user.isAnonymous;
writeUserData(user.uid);
// ...
} else {
// User is signed out.
// ...
}
// ...
});

Related

Firebase anonymous auth is triggering both sides of a JS if statement

I have followed the Google reference documents but find that the firebase auth triggers both sides of the if statement.
calcbtn.addEventListener('click', e => {
//Auth
firebase.auth().signInAnonymously().catch(function(error) {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
console.log(`${errorCode}: ${errorMessage}`);
// ...
});
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
// User is signed in.
var isAnonymous = user.isAnonymous;
uid = user.uid;
console.log(`UserID: ${uid}`);
// ...
} else {
// User is signed out.
console.log('Error: User is not authenticated');
// ...
}
// ...
});
Returns both the userID and the Error: User is not authenticated?
Initially when you attach the onAuthStateChanged, no user will be signed in yet. So at that point your callback will be called with null.
Then the user sign in triggered by signInAnonymously() completes and another call is made to your callback with that user object.
This is normal operation for an auth state listener in Firebase: it will usually initially be called with null, and then with the actual user object.

Firebase javascript auth user displaying null even though user is signed in

I followed the Firebase docs for web development and I used the user.updateProfile method to add a display name to the user's profile. After signing in, I used console.log(user) and it worked but when I call updateProfile(), the value of user is null. Any solutions?
Here is the relevant code:
var button = document.getElementById("profile-button");
var username = document.getElementById("username-Box").value;
var user = firebase.auth().currentUser;
auth.onAuthStateChanged(user =>{
console.log(user);
})
function updateProfile(){
if (user != null){
user.updateProfile({
displayName : username
}).then(user => {
console.log("Updated Successfully");
window.location.href="chatpage.html";
}).catch(err =>{
console.log(err);
window.alert(err);
});
}else if(user == null){
console.log("No user signed in");
}
}
You need to wait for onAuthStateChanged to fire before assigning the user variable, otherwise the Auth object may be in an intermediate state. This is documented:
By using an observer, you ensure that the Auth object isn't in an intermediate state—such as initialization—when you get the current user. When you use signInWithRedirect, the onAuthStateChanged observer waits until getRedirectResult resolves before triggering.
You can also get the currently signed-in user by using the currentUser property. If a user isn't signed in, currentUser is null:
It's worth explicitly pointing out that the user variable you console.log in onAuthStateChanged is not the same user variable that's used in your updateProfile method. While the user maybe "logged in" when onAuthStateChanged fires, they are likely not logged in when you set your outer user variable. Therein lies your problem.
It's not clear from your code where updateProfile is called, but Peter Haddad's answer is likely the solution I would implement. However, note that with the code snippet supplied in that answer you'll also need to change your updateProfile method to accept a user parameter. Another approach would be to assign the user variable inside of onAuthStateChanged.
let user;
auth.onAuthStateChanged(u => user = u);
With that approach your updateProfile method should work as is. Just keep in mind that you may have a race condition depending on when you call updateProfile.
Since console.log(user) is returning the correct user, then inside the authstatechanged call the updateProfile:
auth.onAuthStateChanged(user =>{
console.log(user);
updateProfile(user);
})
Based on your snippet, I am assuming that updateProfile() is your onClick/onSubmit event handler for clicking your "update profile" button.
Because of this, your user is likely to have logged in by the time they press the button and therefore it is safe to use firebase.auth().currentUser in your event handler rather than maintain a user object in the global scope.
var eleButton = document.getElementById("profile-button");
var eleUsername = document.getElementById("username-Box");
function updateProfile() {
let user = firebase.auth().currentUser;
if (!user) {
alert('Please log in before clicking update profile!')
return;
}
// get current value of '#username-Box'
let username = eleUsername.value.trim();
if (!username) {
alert('Please enter a valid username!')
return;
}
user.updateProfile({
displayName : username
}).then(user => {
console.log("Updated Successfully");
window.location.href="chatpage.html";
}).catch(err =>{
console.log(err);
window.alert(err);
});
}
In your original code, you had the following:
var user = firebase.auth().currentUser; // <-- global-scope variable
auth.onAuthStateChanged(user =>{ // <-- function-scope variable
console.log(user);
})
When onAuthStateChanged fires, it does log the value of user, but it sets and logs it's own version of user, not the user variable in the global-scope.
If you wanted to update the global-scope version, you need to rename the variable used in your onAuthStateChanged handler so that it doesn't shadow the user global-scope variable.
var user = firebase.auth().currentUser; // <-- global-scope variable
auth.onAuthStateChanged(_user =>{ // <-- function-scope variable
user = _user;
console.log(user);
})

Wait for firebase.auth initialization before reading another function

I am very new with firebase and javascript.
My project: Build a private messaging app. To do that, I want to define a sub collection in firestore for private messaging using the current user id and the destination user id.
Here is the function that allows this:
// generate the right SubCollection depending on current User and the User he tries to reach
function dmCollection(toUid) {
if (toUid === null) {
// If no destination user is definer, we set it to the below value
toUid = 'fixed_value';
};
const idPair = [firebase.auth().currentUser.uid, toUid].join('_').sort();
return firebase.firestore().collection('dms').doc(idPair).collection('messages');
};
My problem: I want to use the firebase.auth().currentUser.uid attribute, but it looks like the function is not waiting for firebase.auth initialization. How can I fix this problem?
Additional information:
I have two functions that are calling the first one (dmCollection):
// retrieve DMs
function messagesWith(uid) {
return dmCollection(uid).orderBy('sent', 'desc').get();
};
// send a DM
function sendDM(toUid, messageText) {
return dmCollection(toUid).add({
from: firebase.auth().currentUser.uid,
text: messageText,
sent: firebase.firestore.FieldValue.serverTimestamp(),
});
};
If I correctly understand your problem ("it looks like the function is not waiting for firebase.auth initialization"), you have two possible solutions:
Solution 1: Set an observer on the Auth object
As explained in the documentation, you can set an observer on the Auth object with the onAuthStateChanged() method:
By using an observer, you ensure that the Auth object isn't in an
intermediate state—such as initialization—when you get the current
user.
So you would modify your code as follows:
// retrieve DMs
function messagesWith(uid) {
return dmCollection(uid).orderBy('sent', 'desc').get();
};
// send a DM
function sendDM(toUid, messageText) {
return dmCollection(toUid).add({
from: firebase.auth().currentUser.uid,
text: messageText,
sent: firebase.firestore.FieldValue.serverTimestamp(),
});
};
// generate the right SubCollection depending on current User and the User he tries to reach
function dmCollection(toUid) {
if (toUid === null) {
// If no destination user is definer, we set it to the below value
toUid = 'fixed_value';
};
const idPair = [firebase.auth().currentUser.uid, toUid].join('_').sort();
return firebase.firestore().collection('dms').doc(idPair).collection('messages');
};
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
var messageText = '....';
sendDM(user.uid, messageText)
} else {
// No user is signed in.
}
});
Solution 2: Use the currentUser property
You could also "get the currently signed-in user by using the currentUser property" as explained in the same doc. "If a user isn't signed in, currentUser is null".
In this case you would do:
var user = firebase.auth().currentUser;
if (user) {
var messageText = '....';
sendDM(user.uid, messageText);
} else {
// No user is signed in.
// Ask the user to sign in, e.g. redirect to a sign in page
}
Which solution to choose?
It depends how you want to call the function(s) based on the user uid.
If you want to call the function(s) immediately after the user is signed in, use Solution 1.
If you want to call the function(s) at another specific moment (e.g. following a user action), use Solution 2.

Firebase custom login fails (JavaScript)

I'm trying to get started with firebase and now with the security part of it. I'm trying to keep it as simple as possible in order to get started, using guides and code snippets from the Firebase website.
In order to keep it simple I have a webpage containing a password (id "Code") and user input field (id "Door"). How do I check if the password entered in field "Code" is equal to the password that is already stored in node https://mydatabase.firebaseio.com/loapp_users/BAAJ/password, BAAJ being a userid of one of the users stored in node loapp_users, all with a child node "password"?
The code below doesn't seem to do the trick.
$(document).ready(function(){
// Monitoring User Authentication State
// Use the onAuth() method to listen for changes in user authentication state
// Create a callback which logs the current auth state
function authDataCallback(authData) {
if (authData) {
console.log("User " + authData.uid + " is logged in with " + authData.provider);
} else {
console.log("User is logged out");
}
}
// Register the callback to be fired every time auth state changes
var ref = new Firebase("https://mydatabase.firebaseio.com");
ref.onAuth(authDataCallback);
$("#logout").click(
function logout() {
ref.unauth();
ref.offAuth(authDataCallback);
}
);
// LOGIN
// The code to authenticate a user varies by provider and transport method, but they all have similar signatures and
// accept a callback function. Use it to handle errors and process the results of a successful login.
// Create a callback to handle the result of the authentication
function authHandler(error, authData) {
if (error) {
console.log("Login Failed!", error);
} else {
console.log("Authenticated successfully with payload:", authData);
}
};
$("#login").click(
function() {
var usersRef = new Firebase("https://mydatabase.firebaseio.com/loapp_users");
// Authenticate users with a custom Firebase token
var _user = $("#Door").val();
var _level = "docent";
var _password = $("#Code").val();
var userRef = usersRef.child(_user);
// Attach an asynchronous callback to read the data at our user reference
userRef.on("value", function(snapshot) {
console.log(snapshot.val());
if (snapshot.val().child("password").text() == _password) {
ref.authWithCustomToken("eyJ0e....etc...mlhdCI6MTQyOTM4Mzc0M30.Vn1QF7cRC6nml8HB9NAzpQXJgq5lDrAie-zIHxtOmFk", authHandler);
} else {
console.log("Gebruikersnaam en code komen niet overeen")
}
}, function (errorObject) {
console.log("The read failed: " + errorObject.code);
});
}
);
});
snapshot.val().child("password").text()
should instead be:
snaphot.val().password
Then it works.

how to get current user on firebase

I would like to know how how to get the current user. I am making a function where the user is creating a group and would like to add the user making the group to it at the same time. I can make the group fine, that was simple enough. But I do not know how to get to the user object outside of the simple login object.
I'm sorry if there are several topics stating this already, but I have been looking for hours and have not been able to find anything that explains it. Any help would be appreciated.
The currently logged in user is returned from Simple Login's callback. This callback runs when your user authenticates, or if your user is already authenticated, it runs at the time of page load.
Take this code form the simple login docs:
var myRef = new Firebase("https://<your-firebase>.firebaseio.com");
var authClient = new FirebaseSimpleLogin(myRef, function(error, user) {
if (error) {
// an error occurred while attempting login
console.log(error);
} else if (user) {
// user authenticated with Firebase
console.log("User ID: " + user.uid + ", Provider: " + user.provider);
} else {
// user is logged out
}
});
The user object is exposed in the callback. It's only in scope during the execution of that callback, so if you want to use it outside, store it in a variable for reuse later like this:
var currentUser = {};
var myRef = new Firebase("https://<your-firebase>.firebaseio.com");
var authClient = new FirebaseSimpleLogin(myRef, function(error, user) {
if (error) {
// an error occurred while attempting login
console.log(error);
} else if (user) {
// user authenticated with Firebase
currentUser = user;
} else {
// user is logged out
}
});
...
// Later on in your code (that runs some time after that login callback fires)
console.log("User ID: " + currentUser.uid + ", Provider: " + currentUser.provider);

Categories