I am adding the new task using following javascript code:
function addTask(name, important){
alert(important);
const newTask = {id: "todo" + nanoid(), name:name, completed:false, important:important, checked:false};
setTasks([...tasks, newTask]);
console.log(setTasks)
}
Now, I would like to add the last task on the first place of the application. May I ask please how to make it possible?
setTasks([newTask, ...tasks]);
Is the cleanest way to add items in front, however later on it may prove inconsistent (after saving into db for example and retrieving the list from db), personally I would use array.sort() method and sort the array by creation date or / and by "important" key. This way, no matter how you push an item into array, they will be always in correct / needed order.
Related
I have the following test data
1: {
match: "Game 1",
scorer: ["foo","bar"] //this could also be an object
}
My question is how do I correctly append new value to an array without overwriting it? My idea was to retrieve existing data then spread it like so [...currentData, "bob"]. Is there a better alternative?
const addScorer = (matchId) => {
return update(ref(db, path), {
scorer: ["bob"]
})
}
There is no atomic operation to add an item to an array directly in the database. This means you'll need to:
Read the array into your application code
Append the item to the array
Write the entire array back to the database
This is one of the many reasons why Firebase recommends against using arrays for lists of data, but instead has a push() operation that circumvents most problems. For more on this, see the link to the document that Nilesh included in their comment, or read this article on Best Practices: Arrays in Firebase.
So I'm working on a personal project to learn react-native and Firestore.
I have a DB like this:
And I want my code to add a new battery in the array batteries.
The elements in the array are just a map{string, string}
The problem is that when I update the array with a new brand that's work but if I want to update it with the same brand again have,
so having by the end
batteries[0]: {'brand': 'cestmoi'}
batteries[1]: {'brand': 'cestmoi'}
The DB doesn't update, doesn't have any error or so.
I don't understand why and I followed their tutorial. Here is my code:
async function addData(collection, doc, value) {
console.log(`Add data ${value.brand}`)
try {
const result = await firestore()
.collection(collection)
.doc(doc)
.set({
batteries: firestore.FieldValue.arrayUnion(value)
})
console.log(result);
return result;
} catch (error) {
return error;
}
}
I use try-catch by habit but I don't know if the then...catch is better or not.
As already #windowsill mentioned in his answer, there is no way you can add duplicate elements in an array using client-side code. If your application requires that, then you have to read the entire array, add the duplicates and then write the document back to Firestore.
However, if you want to update an existing element in an array of objects (maps) then you have to use arrayUnion with the entire object. If you want to understand the mechanism better, you can read the following article which is called:
How to update an array of objects in Firestore?
arrayUnion says that it "adds elements to an array but only elements not already present". Maybe it does a stringify or something to check equality and therefore doesn't add the new element. I think you'll have to 1. get the current list, 2. add your element, 3. set the batteries field to the updated list.
I'm creating a To-Do list app, pretty basic and I copied the idea from Youtube (still learning JS). So, each time you add a new To-Do it's stored (just the text you typed and whether it's done or not) in an array and the HTML element is added, everything's good until here.
The problem begins when I try to delete that element from the array. Each item (To-do) has an ID which is basically the index where it's stored in the array, so I coded array.splice(item.id, 1) and It works great if you delete the items patiently one by one, but if you click the delete button faster the items deleted in the array doesn't match, it's like the index passed messes up. I was wondering if I could make like a wait until the current delete() function ends or something like that. Btw the list container has an eventListener and if the delete button of any item was clicked it runs the delete() function passing the item by e.target.parentElement (which is the item container).
I want the array for a localeStorage. Thanks!
First time posting and English isn't my first language, sorry for any mistake.
Great question. So .splice() is indeed the Array method you want to call, but it doesn't quite use the syntax you're expecting.
First of all, I'm going to point you to the MDN docs: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice
MDN is managed by Mozilla, and is an authoritative source on most things javascript-in-the-browser. If you're just getting started with javascript, that resource will be invaluable. The MDN documentation is some of the best written technical documentation out there, and is largely written so that people with minimal experience in the language can understand them.
That being said, let's go over what Array.splice is actually doing.
So you have an array of todos:
const todos = [] // Array of to-dos
You want to delete one of the the todos, and you have access to the id. I'm going to assume your Todos have a shape similar to this:
const todo = {
id: 1 // number
name: 'my todo' // string
description: 'my todo description' // string
}
In order to delete an element from this array, given the id of the item you're deleting, you would actually need to do the following:
1) Find the location in the array of the todo that has the id you are looking for.
2) Splice that element out of the array using the index you just found.
Let's see how to do that:
function removeItemFromTodos(itemId, todos) {
// find the index of the todo with the id you are looking for
const indexOfTodoToDelete = todos.findIndex((todoInArray) => todoInArray.id === itemId));
// remove that todo:
todos.splice(indexOfTodoToDelete, 1) // delete the todo
}
Okay, so let's unpack that:
First, the findIndex method loops over the array. It will start at index 0, and work up until it reaches the end of the array. If the item it is currently looking at has an id that matches the id we are looking for, then the function will immediately return the index of that todo's location in the array, and stop searching in the array.
Once you have the index, you can delete the item. The splice function takes in the location that you want to start cutting elements as the first argument, and the number of elements you want to cut as the second argument. The splice method returns the elements that were deleted. So it is actually mutating the array in place, and not making a copy of it in memory to perform its operation.
Let me know if this solution doesn't work for you or if it isn't clear!
I have a firestore firebase database , in which I have a collection users
there is an array in the collection and in the array there is a map
in map there is a field qty.. I want to increment that qty value..
using increment doesnt help as the qty is inside a array index
db.collection("users").doc(checkId).update({
myCart: firebase.firestore.FieldValue.arrayUnion({
qty: firebase.firestore.FieldValue.increment(1),
}),
this is the error Output =>
Uncaught (in promise) FirebaseError: Function FieldValue.arrayUnion() called with invalid data. FieldValue.increment() can only be used with update() and set()
My answer below won't work, given that the qty is in an array. The only way to update an item in an array is to read the entire document, update the item in the array, and then write the entire array with the updated item back to the document.
An alternative would be to use a map instead of an array, and then update the qty using the approach outlined in my (old, and non-working) answer below 👇
You need to specify the full path to the field you're trying to update. So I think in your case, that'll be:
db.collection("users").doc(checkId).update({
"myCart.0.qty": firebase.firestore.FieldValue.increment(1)
}),
The field you want to update is embedded in an array. In this case, you can't use FieldValue.increment(), since it's not possible to call out an array element as a named field value.
What you'll have to do instead is read the entire document, modify the field in memory to contain what you want, and update the field back into the document. Also consider using a transaction for this if you need to update to be atomic.
(If the field wasn't part of an array, you could use FieldValue.increment().)
As of today (29-04-2020)... this is tested by me.
Suppose my data structure is like this:
collection: Users
Any document: say jdfhjksdhfw
It has a map like below
map name: UserPageVisits
map fields: field1,field2,field3 etc
Now we can increment the number field in the map like below:
mapname.field1 etc...
That is use the dot operator to access the fields inside the map just like you would do to an object of javascript.
JAVA Code (Android), update the field using transactions so they can complete atomically.
transaction.update(<documentreference object>,"UserPageVisits.field1",FieldValue.increment(1));
I have just pushed a version of my app which uses this concept and it's working.
Kudos !!
My Best Regards
Previous answers helped me as well, but dont forget about the "merge" property!!! Otherwise it will overwrite your entire array, losing other fields.
var myIndex = 0;
const userRef = db.collection('users').doc(checkId);
return userRef.update({
'myCart.${myIndex}.qty': admin.firestore.FieldValue.increment(1)
}, {
merge: true
});
I'm making a sortable table. The table data is from an array of objects. I need to be able to sort the array based on the properties
an object looks like this:
{
"AbsenceReservationID": 7220,
"Name": "DGM",
"Code": "ARBEIDSONGEVAL WP",
"RequestState": "Goedgekeurd",
"From": "2017-03-21T00:00:00+01:00",
}
I'm using lodash, so I can easily sort my array using the following syntax:
asc:
myArr = _.sortBy(myArr , "Name");
desc:
myArr = _.sortBy(myArr , "Name").reverse;
However I'm stuck at the last sorting method. I need to be able to undo the sort but I can't figure out a good way to do this. Here's how it would work:
1st click - sort asc
2nd click - sort desc
3rd click - remove sorting
on this property
I think the hard part is when the user sorts on mutliple properties, so for example
How can I achieve this removal of a property sort?
You basically have three choices:
Don't offer the "unsorted" option
Remember the original order (perhaps by adding a property for it), and for the "unsorted" option, sort on that property
For instance, you can add an originalIndex property:
_.forEach(myArr, function(e, i) { e.originalIndex = i; });
Then myArr = _.sortBy(myArr, "originalIndex"); will get the original order back.
Keep the original array somewhere (since _.sortBy creates a copy), and use the original array again when you want the "unsorted" version
You can use to create an original copy:
var oldArr = myArr.slice(); // gives you a new copy.
You can use oldArr after sorting.
Where are you getting the data from initially? (service)
If it is coming from a service call - would recommend simply re-calling that service and setting the data equal to the data retrieved again.
If you don't want to make a call to the service again, simply create two objects in JS sortingData and unsortedData. Then when you use the lodash method, simply apply it only to the sortingData array. On the third click, do
sortingData = unsortedData;
Where are you getting the data from initially? (manually created)
The same approach of having two objects applies here. Once the data has been created, before you allow sorting to be done, set the unsortedData to the data that you have generated. e.g.
unsortedData = data;