Get firebase snapshot value outside of function - javascript

I want to send some generated data to the to a specific object child.
var user = firebase.auth().currentUser;
var key = user.uid;
// Set path for created user to be UID
var createProfileRef = firebase.database().ref("profiles/" + key);
var info;
createProfileRef.on("value", function(snapshot) {
var getData = snapshot.val();
info = Object.keys(getData)[0];
});
// Save Plan to logged inn user
var sendData = firebase.database().ref("profiles/" + key + "/" + info + sendDate);
savePlan(sendFat, sendProtein, sendCarbohydrate);
function savePlan(sendFat, sendProtein, sendCarbohydrate) {
var addData = sendData.push();
addData.set({
Macros_Fat: sendFat,
Macros_Protein: sendProtein,
Macros_Carbohydrate: sendCarbohydrate,
});
The only thing I need for this to work is to get the value of the variable "info". I just can't get it to get transferred outside of the function it is declared in...
If I place the function savePlan inside the snapshot it works, but it generated around 1000 keys constantly until I exit the application.

The easiest way you can do that is by setting the variable value in localStorage in the firebase function itself and get it outside the function from localStorage.
Here's the code:
// in firebase function
localStorage.setItem('info',info)
//outside the firebase function
localStorage.getItem('info');

Related

Can someone explain where the "messages" key comes from?

I am following a tutorial and I understood everything up until everything beyond where I declared the let variable.
function submitMessage(event) {
event.preventDefault();
const email = document.getElementById("email").value;
const fullName = document.getElementById("fullName").value;
const feedbackType = document.getElementById("feedbackType").value;
const comment = document.getElementById("comment").value;
const messageObject = {
email,
fullName,
feedbackType,
comment
};
let currentMessages = [];
if (window.sessionStorage.getItem("messages")) {
currentMessages =
JSON.parse(
window.sessionStorage.getItem("messages")
);
}
currentMessages.push(messageObject);
window.sessionStorage.setItem(
"messages",
JSON.stringify(currentMessages)
);
}
You're setting the "messages" key for the session storage here:
window.sessionStorage.setItem(
"messages", // arbitrary key name
JSON.stringify(currentMessages) // value to store for this key
);
let currentMessage is an empty array that will hold messageObject variable expressed few row before.
After currentMessage there is a step that setup a session store that we going to call "messages".
The window.sessionStorage function is used to save some data inside the browser, in our case currentMessage. In this way if your refreshed the browser page you will able to get the last data save in window.sessionStorage.
So in the first step this function try to get messages object from the session storage that we have e called messages.
Then, one fetched it will push the currentMessage inside it with setItem, so after you reload the browser you will be able to retrieve the array passing through the session storage getItem and to get this value it need to search inside some key and the key is messages, in other word the key in the session storage that can hold our array.

object of data specific to current logged in user

The goal is the user can save up to 7 field vals in obj userA, logout, log back in and the saved vals are there, retrievable. Specific to each user.
I am trying to create an object i.e. userA and update it, as the
user saves each field value (i.e. BaseMap: basemapSaved), save
the updated state in local storage, then retrieve saved state using
local storage. So, when the user logs out, then logs back in, their
saved data is still there specific to their username.
Below is my most recent attempt (full js): Any pointers? Am I going about this all wrong?
UPDATED ATTEMPT BELOW WITH BOUNTY.
I am simply trying to save an object of data and a field within it (i.e. userA.BaseMap.basemapSaved;) with local storage, on click.
I later want to parse that saved object in local storage, get that field, and update my API object i.e. object.data.field (userA.BaseMap.basemapSaved;) with the value saved and gathered. I can do this pro grammatically pretty easy, but the idea is to save the state per user, so they can log out, then log back in and have their selection saved.
// Here I am trying to initialize the variables
var currentUser;
var basemapSaved;
var userA[key] = {};
// This function I am getting the logged in username, I want to set this as the object key in userA i.e. userA[key]
function checkUser() {
var node = document.querySelectorAll("span.username")[0];
currentUser = node.textContent;
var key = currentUser;
console.log("current user is:" + key);
}
// This is just a handler to wait to my basemap gallery loads before trying to save
var basemapMod = document.getElementsByClassName("basemap")[0];
basemapMod.addEventListener('click', ()=>{
setTimeout(
function() {
BaseMapSaver();
}, 2000);
});
function BaseMapSaver() {
savebtnBM.addEventListener('click', ()=>{
checkUser();
// This is where I get the data from my API to save, gathers fine
basemapSaved = app.widget.Manager.Gallery.activeBasemap.Item.id;
// Below I am trying to set it, at first without the object key but would like to use the key
var saveMap = localStorage.setItem('userA', JSON.stringify(userA));
console.log(userA);
});
}
// Home button
var defaultViewHbtn = document.getElementById("home");
defaultViewHbtn.addEventListener('click', ()=>{
checkUser();
// Here I try to parse the value from local storage object
const userAParseValue = JSON.parse(localStorage.getItem('userA'));
// Errors with Uncaught TypeError: Cannot read property 'BaseMap' of undefined
userBaseMap = userAParseValue.userA.BaseMap.basemapSaved;
console.log(userBaseMap);
app.widget.Manager.Gallery.activeBasemap.Item.id = {
portalItem: {
id: userA.BaseMap.basemapSaved // this is where I want to load saved value from local storage object
}
};
});
It Should work check addEventListener function:-
Hbtn.addEventListener('click', ()=>{
checkUser();
const userAParseValue = JSON.parse(localStorage.getItem('userA'));
userBaseMap = userAParseValue.userA.BaseMap.basemapSaved;
console.log(userBaseMap);
myApp.widgets.bigData.Gallery.map = {
Item: {
id: userA.BaseMap.basemapSaved
}
};
});
You can use localStorage and the approach you're trying to make work, but you'll end up with localStorage having a separate object for each user. If that's OK then you use localStorage after load to check if a user is logged in and then load the users' data. Then update the data to the localStorage when the values change. You may check inline comments for details:
HTML if there is a user logged in:
<h3>User <span class="username"><?php echo $user; ?></span> is logged in</h3>
<form method="post">
<input type="hidden" name="action" value="logout"/>
<button type="submit">Logout</button>
</form>
<hr/>
<div>
<h2>User counter: <span id="counter"></span></h2>
<div>
<button id="inc-counter">Increase</button>
<button id="dec-counter">Decrease</button>
</div>
</div>
Javascript to handle localStorage:
// Get user stored on page HTML
const user = document.querySelector("span.username");
// Something to update/alter using user data and/or user input
const counter = document.querySelector("#counter");
const incCounter = document.querySelector("#inc-counter");
const decCounter = document.querySelector("#dec-counter");
if(user) { // If there is a user logged in
// Get the username
const username = user.textContent;
// Get the localStorage the belongs to that user (using username for key)
let storageUser = JSON.parse(localStorage.getItem(username) || 'null');
// Use default user object if the user has no previous settings stored
let currentUser = storageUser || {
BaseMap: {
counter: 0
}
};
// Display the user data
function displayCounter() {
const BaseMap = 'BaseMap' in currentUser ? currentUser.BaseMap : {};
let userCounter = 'counter' in BaseMap ? BaseMap.counter : 0;
counter.textContent = userCounter;
}
// Alter the user data and save it to localStorage user settings object
function alterCounter(addToCounter) {
// Check if BaseMap object exists or default
const BaseMap = 'BaseMap' in currentUser ? currentUser.BaseMap : {};
// Check if data exists or default
let userCounter = 'counter' in BaseMap ? BaseMap.counter : 0;
// Alter user data according to user input
userCounter += addToCounter;
// Change user settings object
currentUser['BaseMap']['counter'] = userCounter;
// Save user settings object
localStorage.setItem(username, JSON.stringify(currentUser));
// Display altered user data
displayCounter();
}
// Initialize by display retrieved/default data
displayCounter();
// Add event listeners to user inputs
incCounter.addEventListener('click', () => alterCounter(1));
decCounter.addEventListener('click', () => alterCounter(-1));
}
You can check an online example that I've made at the link below:
https://zikro.gr/dbg/so/60010743/ (Users userA, userB both with password 1234 can be used for demonstration)
That will work and retrieve/save user data to the localStorage using username for each user. Keep in mind that this method will only save the user settings for a specific browser location. If you want to have user settings when the user logs in from anywhere, then you should go with the traditional workaround which is based on server session, but it's not so flexible when it comes to user settings because you'll have to update each data/setting using server requests each time the user makes a change which it's possible but it requires server + client implementation.
A combination of both server side settings storage + server session + client localStorage would be the best approach to this situation.
here is my answer
<html>
<body>
<span class="border username">121</span>
<div class="border basemap">Base Map</div>
<div class="border saveBtn">Save</div>
<div id="home" class="border">Home</div>
<style>
.border{
border: solid gray 1px;
border-radius: 2px;
text-align: center;
background: #eee;
margin: 5px;
width: 100px;
}
</style>
<script type="text/javascript">
// Here I am trying to initialize the variables
var key = 1;
var currentUser;
var basemapSaved;
var userA = {
BaseMap: {
id: 1234
}
};
var app = {
widget: {
Manager: {
Gallery: {
activeBasemap: {
Item: {
id: {
portalItem: {
id: 1234 // this is where I want to load saved value from local storage object
}
}
}
}
}
}
}
};
// This function I am getting the logged in username, I want to set this as the object key in userA i.e. userA[key]
function checkUser() {
var node = document.querySelectorAll("span.username")[0];
currentUser = node.textContent;
var key = currentUser;
console.log("current user is:" + key);
}
// This is just a handler to wait to my basemap gallery loads before trying to save
var basemapMod = document.getElementsByClassName("basemap")[0];
basemapMod.addEventListener('click', ()=>{
console.log("basemapMod click");
setTimeout(
function() {
BaseMapSaver();
}, 2000);
});
function BaseMapSaver() {
var savebtnBM = document.getElementsByClassName("saveBtn")[0];
savebtnBM.addEventListener('click', ()=>{
console.log("savebtnBM click");
checkUser();
// This is where I get the data from my API to save, gathers fine
basemapSaved = app.widget.Manager.Gallery.activeBasemap.Item.id.portalItem.id;
/** saving users, instead of userA */
const userAParseValue = JSON.parse(localStorage.getItem('users'));
userA.BaseMap.basemapSaved = basemapSaved;
const finalUsers = {...userAParseValue, userA}
// Below I am trying to set it, at first without the object key but would like to use the key
var saveMap = localStorage.setItem('users', JSON.stringify(finalUsers));
console.log(userA);
});
}
// Home button
var defaultViewHbtn = document.getElementById("home");
defaultViewHbtn.addEventListener('click', ()=>{
console.log("defaultViewHbtn click");
checkUser();
// Here I try to parse the value from local storage object
const userAParseValue = JSON.parse(localStorage.getItem('users'));
// Errors with Uncaught TypeError: Cannot read property 'BaseMap' of undefined
userBaseMap = userAParseValue.userA.BaseMap.basemapSaved;
console.log(userBaseMap);
app.widget.Manager.Gallery.activeBasemap.Item.id = {
portalItem: {
id: userA.BaseMap.basemapSaved // this is where I want to load saved value from local storage object
}
};
});
</script>
</body>
</html>
I changed a few structures which were not coherent. Saving and loading them was causing discrepancies. I also suggest storing all users in a single object and accessing the data from userMap because multiple users can use same browser.
Based on the two requirements that you have defined in your original question, this should do what you ask.
The goal is the user can save up to 7 field vals in obj userA, logout, log back in and the saved vals are there, retrievable. Specific to each user.
I am trying to create an object i.e. userA and update it, as the user saves each field value (i.e. BaseMap: basemapSaved), save the updated state in local storage, then retrieve saved state using local storage. So, when the user logs out, then logs back in, their saved data is still there specific to their username.
// retrieve user from localstorage. defaults to {}
// This looks to retrieve the user from local storage by username.
// Returns a `userObj` an object with two properties.
// `username` - the name of the user
// `user` - the stored object that was retrieved from local storage.
// defaults to {} if nothing in user storage
// Not a good strategy btw, a lot of us share the same names :)
function getUser(username) {
let user = localStorage.getItem(username) || {};
try {
user = JSON.parse(user);
} catch (e) {
user = {};
}
return { username, user }
}
// Store user object in localstorage
// Store a user in local storage, keyed by their username
function setUser(username, user) {
localStorage.setItem(username, JSON.stringify(user));
}
// set a key/ value on user object in localstorage
// Don't allow anymore than 7 properties to be stored on the user object
function setUserProperty(userObj, key, value) {
let { username, user } = userObj;
if (Object.keys(user).length > 7) {
throw new Error('user properties exceeds 7')
}
user[key] = value;
setUser(username, user);
}
// modified to return a user from local storage or {}
function checkUser() {
var node = document.querySelectorAll("span.username")[0];
const currentUser = node.textContent;
return getUser(currentUser);
}
// This is just a handler to wait to my basemap gallery loads before trying to save
var basemapMod = document.getElementsByClassName("basemap")[0];
basemapMod.addEventListener('click', () => {
setTimeout(
function() {
BaseMapSaver();
}, 2000);
});
// Fyi Capitals indicate constructors - not functions!
function BaseMapSaver() {
savebtnBM.addEventListener('click', () => {
const userObj = checkUser(); // get the user from localstorage
const basemapSaved = app.widget.Manager.Gallery.activeBasemap.Item.id;
setUserProperty(userObj, 'basemap', basemapSaved) // store the basemap on the user object in local storage with the key 'basemap'
console.log(JSON.stringify(userObj));
});
}
var defaultViewHbtn = document.getElementById("home");
defaultViewHbtn.addEventListener('click', () => {
// get user from localstorage
const { user } = checkUser();
const userBaseMap = user.basemap
// if we have a store basemap
if (userBaseMap) {
app.widget.Manager.Gallery.activeBasemap.Item.id = {
portalItem: {
id: userBaseMap // load it
}
};
}
});
There are many ways to handle this depending upon your use case. You have specifically mentioned LocalStorage hence everyone is suggesting the same but cookies will fit your bill as well as long as you handle the expiry time properly for them.
Local Storage
Make an Object of fields you will like to store for that user
let obj = {'keyname' : value, 'keyname' : value};
//store it - mapping it with user
localStorage.setItem('userID', JSON.stringify(obj));
//retrieve and use on login success
let ret_obj= localStorage.getItem('userID');
Cookies
You can set an arbitrary expiration time and then you again have choice of choosing just one variable or store it as a JSON itself.
document.cookie = "userName=Robert; expires=Fri, 31 Dec 9999 23:59:59 GMT";
*Cookies will hold limited amount of data, as in not huge data (Which I don't think is the use case here because I checked your jsfiddle example, you are basically trying to store some data)
If you want to store JSON data in cookies check this out Click Here
*Why am I suggesting cookies? Many enterprises already do something similar for example even post logging out when you visit a website
they will display your name and ask you to sign-in, it is just a
personalisation addition.

Referencing firebase database with a variable and string concatenation

As you can see below i'm trying to read a list of data from the database and then loop over the result, in javascript. The function runs whenever i open/refresh the page:
firebase.database().ref("Users/" + uid + "/rooms").on("value", function(snapshot) {
snapshot.forEach(function(e) {
var element = e.val();
var roomId = element.Id;
});
});
However, that string concatenation to specify the User Id doesn't work for some reason. When i replace it with the user Id directly like this:
firebase.database().ref("Users/GR3JFsMrKOjCrLhDNFMaq72COd07/rooms").on.....
that works fine. But of course i want to use the variable which contains the Id of the current user.
The uid variable is assigned a value in the onAuthStateChanged when checking if the user is signed in:
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
// User is signed in.
uid = user.uid;
If I add a console.log like this:
firebase.database().ref("Users/" + uid + "/rooms").on("value", function(snapshot) {
console.log(snapshot.parent);
snapshot.forEach(function(e) {
the output with the first code example (using uid variable) is: undefined.
If i specify the User Id directly it is: room-id-1 (the result i want).
How do i make the string concatenation work? Or is this the wrong way of specifying the path of the current user?
It is extremely unlikely that the problem is in the string concatenation itself. It is much more likely that uid simple doesn't have a value yet when you start reading from the database.
To make sure the uid is available, put the reading of the data into the auth state listener like this:
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
uid = user.uid;
console.log("uid="+uid);
firebase.database().ref("Users/" + uid + "/rooms").on("value", function(snapshot) {
snapshot.forEach(function(e) {
var element = e.val();
var roomId = element.Id;
console.log("roodId="+roomId);
});
});
}
})

Modify specific information in Firebase Database Realtime collection with JavaScript

I have a problem and I want to modify some information not all, for example I want to modify only the address and the nit (see image) but in doing so I delete the other fields, how could I modify it without eliminating the rest?
image
My code:
var uid = firebase.auth().currentUser.uid;
var modi = {
nombre: "Hello",
direccion: "Address"
}
var updates = {};
updates['/Users/' + uid] = modi;
firebase.database().ref().update(updates);
Thank, you!
Do you have access to that User object data?
If so, basically merge the updates into that and then save to Firebase. E.g.
// if we already have some reference to User data object
var updates = {...userObject, ...modi};
firebase.database().ref('/Users/' + uid).update(updates);
else you can always fetch that object, then do the merge and update procedure above. E.g.
// modi defined above
return firebase.database().ref('/Users/' + uid)
.once('value')
.then(function(snapshot) {
var user = snapshot.val()
updates = {...user, ...modi}
firebase.database().ref('/Users/' + uid).update(updates);
});

Writing data to completely separate locations simultaneously using update()

In my firebase app when a new user signs up I add their initial data like displayname, emai , photourl to the database under the top level users node. This works fine.
Now when a user post a status, I want to upload the the post to top level statuses node where all user statuses are kept. And simultaneously I want to upload the post to current user's posts node i.e users/currentuser/posts.
I am following the methods shown on official firebase site here.
The problem is when I hit the post button nothing happens and no data is posted to the database
My function that gets invoked when the post button is clicked:
function postStatus(){
var ref = firebase.database().ref("allstatuses");
var user = firebase.auth().currentUser;
var newStatusRef = ref.push();
var newStatusKey = newStatusRef.key();
var statusData = {
status: postInput.val(),
likes: 0,
dislikes: 0
};
var updateUserStatus = {};
updateUserStatus["users/" + user.uid + "/" + newStatusKey] = statusData;
updateUserStatus["allstatuses/" + newStatusKey] = statusData;
if(user){
firebase.database().ref().update(updateUserStatus);
}else{
alert("please login");
}
}
What am I doing wrong?
According to the API reference link it is key not key()
Change this
var newStatusKey = newStatusRef.key();
to
var newStatusKey = newStatusRef.key;

Categories