I have a react app that pulls data from firebase. It adds data to the array fine. But cannot be accessed. calling the index returns undefined and length of array is 0. but when you print the array the console shows there is an element inside. Whats going on?
componentWillMount() {
itemsRef.on('value', (snapshot) => {
let items = snapshot.val();
let keys = Object.keys(items);
for(var i = 0; i < keys.length; i += 1) {
let k = keys[i];
let name = items[k].name;
let start = items[k].start;
this.state.timers.push( {
name: name,
start: start
} );
}
});
console.log(this.state.timers); // shows an array with stuff in it
this.setState({timers: this.state.timers}); // timers dont get added
// you cant even access elements in the array.
// ex: this.state.timers[0] returns undefined, but the console shows that it exists when the whole array is printed.
}
You shouldn't mutate directly your state like you do in the `this.state.timers.push({})``
You should do something like that:
itemsRef.on('value', (snapshot) => {
const items = snapshot.val();
this.setState({
timers: [
...this.state.timers,
...Object
.keys(items)
.map(key => {
const { name, start } = items[key];
return { name, start };
}),
],
});
});
You shouldn't push directly to the state. Instead you should to something like this:
ES6 variant
const timers = [...this.state.timers];
timers.push({ name, start });
this.setState({ timers })
Related
I am having a problem with sessionStorage; in particular, I want the id of the ads to be saved in the session where the user puts the like on that particular favorite article.
However, I note that the array of objects that is returned contains the ids starting with single quotes, as shown below:
['', '1', '7']
but I want '1' to be shown to me directly.
While if I go into the sessionStorage I notice that like is shown as:
,1,7
ie with the leading comma, but I want it to start with the number directly.
How can I fix this?
function likeAnnunci(){
let likeBtn = document.querySelectorAll('.like');
likeBtn.forEach(btn => {
btn.addEventListener('click', function(){
let id = btn.getAttribute('ann-id');
//sessionStorage.setItem('like', [])
let storage = sessionStorage.getItem('like').split(',');
//console.log(storage);
if(storage.includes(id)){
storage = storage.filter(id_a => id_a != id);
} else {
storage.push(id);
}
sessionStorage.setItem('like', storage)
console.log(sessionStorage.getItem('like').split(','));
btn.classList.toggle('fas');
btn.classList.toggle('far');
btn.classList.toggle('tx-main');
})
})
};
function setLike(id){
if(sessionStorage.getItem('like')){
let storage = sessionStorage.getItem('like').split(',');
if(storage.includes(id.toString())){
return `fas`
} else {
return `far`
}
} else {
sessionStorage.setItem('like', '');
return`far`;
}
}
The main issue you're having is that you're splitting on a , instead of using JSON.parse().
Also, you've got some other code issues and logical errors.
Solution:
function likeAnnunci() {
const likeBtn = document.querySelectorAll('.like');
likeBtn.forEach((btn) => {
btn.addEventListener('click', function () {
let id = btn.getAttribute('ann-id');
//sessionStorage.setItem('like', [])
let storage = JSON.parse(sessionStorage.getItem('like') || '[]');
//console.log(storage);
if (!storage.includes(id)) {
storage.push(id);
}
sessionStorage.setItem('like', JSON.stringify(storage));
console.log(JSON.parse(sessionStorage.getItem('like')));
btn.classList.toggle('fas');
btn.classList.toggle('far');
btn.classList.toggle('tx-main');
});
});
}
More modular and optimal solution:
const likeBtns = document.querySelectorAll('.like');
// If there is no previous array stored, initialize it as an empty array
const initLikesStore = () => {
if (!sessionStorage.getItem('likes')) sessionStorage.setItem('likes', JSON.stringify([]));
};
// Get the item from sessionStorage and parse it into an array
const grabLikesStore = () => JSON.parse(sessionStorage.getItem('likes'));
// Set a new value for the likesStore, automatically serializing the value into a string
const setLikesStore = (array) => sessionStorage.setItem('likes', JSON.stringify(array));
// Pass in a value.
const addToLikesStore = (value) => {
// Grab the current likes state
const pulled = grabStorage();
// If the value is already there, do nothing
if (pulled.includes(value)) return;
// Otherwise, add the value and set the new array
// of the likesStore
storage.push(value);
setLikesStore(pulled);
};
const likeAnnunci = (e) => {
// Grab the ID from the button clicked
const id = e.target.getAttribute('ann-id');
// Pass the ID to be handled by the logic in the
// function above.
addToLikesStore(id);
console.log(grabLikesStore());
btn.classList.toggle('fas');
btn.classList.toggle('far');
btn.classList.toggle('tx-main');
};
// When the dom content loads, initialize the likesStore and
// add all the button event listeners
window.addEventListener('DOMContentLoaded', () => {
initLikesStore();
likeBtns.forEach((btn) => btn.addEventListener('click', likeAnnunci));
});
I am new in programming. I am trying to update cart items. On instance of click "OK" in modal, the One_item object is updated. Then this object is passed on to Cart_Item array, which contains the total items.
I tried to write the logic in Listval() function in the Menu component. The One_Item is updated properly.
But the if condition at the bottom of the Listval(), is adding , but not updating. Also the first click gives an empty object.
Please see the sandbox:
https://codesandbox.io/s/hardcore-stallman-98o58
Relevant function to look into:
Listval() {
let ll = "$" + this.state.listvalue.replace(/[^0-9]/g, "");
let ll2 = this.state.listvalue.replace(/\d+/g, "");
let ll3 = ll2.replace(/\$/g, "");
let ll4 = ll.replace(/\$/g, "");
let ll5 = this.state.Select_Quantity;
let ll6 = parseFloat(ll4) * ll5;
let ll7 = this.state.Total_Item || [];
ll7.push(ll3);
ll7 = [...new Set(ll7)];
this.setState(
{
Select_Price: ll,
Select_Item: ll3,
Select_Item_TotalPrice: ll6,
Total_Item: ll7
},
() => {
// CHANGE: Use callback function to send data to the parent component
this.props.updateTotalItems(this.state.Total_Item.length);
}
);
// append new object This is where problem starts, the new object pushes at second click
if (this.state.Item !== this.state.Select_Item) {
let xx = {
Price: ll,
Item: ll3,
Quantity: this.state.Select_Quantity,
Total_Item_Price: ll6
};
// const Cart_Item = Object.assign(xx, this.state.Cart_Item);
let yy = this.state.Cart_Item || [];
yy.push(xx);
this.setState({ Cart_Item: yy });
}
//else try to update object based on property value
// This is not working at all. it keeps on adding objects instead of updating
else {
for (var i in this.state.Cart_Item) {
if (this.state.Cart_Item[i].value === this.state.Select_Item) {
this.state.Cart_Item[i].Price = ll;
this.state.Cart_Item[i].Item = ll3;
this.state.Cart_Item[i].Quantity = this.state.Select_Quantity;
this.state.Cart_Item[i].Total_Item_Price = ll6;
// }
break; //Stop this loop, we found it!
}
}
// i tried below logic as well but it didnt work
// this.setState({
// Cart_Item:this.state.Cart_Item.filter(v => v.this.state.Select_Item.includes(this.state.Item))
// .concat([ xx ])
// });
}
console.log(this.state.Cart_Item);
}
I am trying to find index of array using lodash locationbar. but my react console showing some warnings. can be resolve?
let wishListData = wishList.result;
let j = 0; const jMax = wishListData.length;
for (; j < jMax; j++) {
var index = _.findIndex(products.result, function (product) {
return product.id === wishListData[j]['pid']
});
if (index !== -1) {
products.result[index]['isWishList'] = true;
}
}
Iterate over wishList.result with forEach instead of a for loop, and you'll avoid the warning:
wishListData.forEach(({ pid }) => {
const index = _.findIndex(products.result, ({ id }) => id === pid);
if (index !== -1) {
products.result[index].isWishList = true;
}
});
Note that this is a linter warning, not a Javascript error. Your code works, the linter just considers it to be confusing - better to use array methods instead of loops when possible.
Also, feel free to remove the _ library and just use built-in Javascript methods instead, if you want:
wishListData.forEach(({ pid }) => {
const product = products.result.find(({ id }) => id === pid);
if (product) {
product.isWishList = true;
}
});
Or, for an O(N) solution instead of an O(N^2) solution, figure out all pids first, then iterate over the products:
const pids = new Set(wishListData.map(({ pid }) => pid));
products.result.forEach((product) => {
if (pids.has(product.id)) {
product.isWishList = true;
}
});
You can try something like this as well:
Instead of mutating product in products.result[index]['isWishList'] = true;, you should create new object to minimize side-effect.
Also, instead of looping on wishListData, you can create a list of PIDs and just check index. If this list is created outside, you can create list of PIDs outside as well. That will reduce processing it every time
const wishListPID = wishList.result.map((x) => x.pid);
const result = products.result.map((product) => {
const isWishList = wishListPID.indexOf(product.id) !== -1;
return { ...product, isWishList }
});
I have problems to sort a list of objects in React-native by a time value. I can't find the answer online. Do you have any suggestions?
My console log in chrome of original object:
Firebase database structure
JSON.stringify(myObject) output:
myObject={"-LAqmXKSdVVH6wirFa-g":
{"desc":"fdf","price":"rrrr","receiveHelp":true,"subject":"Single Variable
Calculus","time":1524558865757,"title":"Test1"},"-LAqmZlBFGoygfTsGQ0e":
{"desc":"dsfdsfd3","price":"333","receiveHelp":true,"subject":"Single
Variable Calculus","time":1524558875724,"title":"Test2"},"-
LAqmcipUjlwLWTrRCw4":
{"desc":"werwerwe55","price":"44","receiveHelp":true,"subject":"Single
Variable Calculus","time":1524558891956,"title":"Test3"},"-
LArMeYfHG6QMg_Frn9A":
{"desc":"3","price":"3","receiveHelp":true,"subject":"Single Variable
Calculus","time":1524568598762,"title":"Annons 1"},"-LArMjg5MkF5cMPZd_Fz":
{"desc":"2222","price":"2","receiveHelp":true,"subject":"Single Variable
Calculus","time":1524568619782,"title":"Annons2"},"-LArNM-3Ij60XmSOBwvr":
{"desc":"22","price":"","receiveHelp":true,"subject":"Single Variable
Calculus","time":1524568780803,"title":"Hej1"},"-LArNPugIfX1pPVZJ11e":
{"desc":"f","price":"2","receiveHelp":true,"subject":"Single Variable
Calculus","time":1524568796844,"title":"Hej2f"}}
What I have tried so far:
firebase.database().ref('/users').once('value').then((snapshot) => {
const ads = snapshot.val();
let myObject = {};
Object.keys(ads).map((objectKey) => {
const value = ads[objectKey];
myObject = Object.assign(value.ads, myObject);
});
//Here i want to sort myObject by time and get the latest first
console.log(myObject)
You first need to combine ads or all users into one array and then sort
let sortedAdds = Object.keys(usersData)
.reduce((prev, userId) => {
let ads = usersData[userId].ads;
ads = Object.keys(ads).map(key => {
return { ...ads[key], id: key };
});
return prev.concat(ads);
}, [])
.sort((a, b) => (a.time - b.time));
([obj1, obj2]).sort((tm1, tm2) => {
if (tm1.time > tm2.time) {
return 1;
}
if (tm1.time < tm2.time) {
return -1;
}
return 0;
})
You could, instead of sorting in your front-end, use the sorting capabilities of the Firebase database by doing:
var ref = database.ref('users/' + adId + '/ads').orderByChild('time');
If you then loop over the results of this query, the ads will be ordered according to the time
ref.once('value', function(snapshot) {
snapshot.forEach(function(childSnapshot) {
var childData = childSnapshot.val();
console.log(childData);
});
});
Edit: if you want to have the "latest gets first" which I understand as "the most recent should be the first", you should then store the time*(-1) instead of time (time being the milliseconds since the unix epoch, as show in your question)
I want to get the nested child objects like in the images but it is returning null. I want values of price and quantity and show them in table.
Check this database image
here.
Code
var countRef = firebase.database().ref('Orders/' + listid);
countRef.on('value', snapshot => {
var b = snapshot.child("price").val();
var c = snapshot.child("quantity").val();
console.log(c);
});
You are pointing to the wrong path that's why you are getting null. Here is what the Firebase docs say:
If there is no data, the snapshot returned is null.
I can't see your entire database structure from the image but try to double check the path and here is my best guess:
var foodItems = firebase.database().ref(`Orders/'${listid}/foodItems`)
foodItems.on('value', snapshot => {
// the snapshot should return the foodItems array
snapshot.forEach((obj) => {
console.log(obj.price)
console.log(obj.quantity)
})
})
If your listid is and exist key, then you mistyped the path: fooditems so try this;
var countRef = firebase.database().ref('Orders/' + listid);
countRef.on('value', snapshot => {
if (snapshot.exists()) {
var b = snapshot.child("fooditems/price").val();
var c = snapshot.child("fooditems/quantity").val();
console.log(c);
}
});