Remove an item form an array in react - javascript

I am making a Website OS in React.js, and I have a problem removing an item from an array in handleWindowRemove, it removes all other items.
This is the array code:
const [openedWindows, setOpenedWindows] = useState([
]);
const handleWindowAdd = () => {
setOpenedWindows([...openedWindows, { openedWindow: "" }]);
}
const handleWindowRemove = (index) => {
const list = [...openedWindows];
const i = openedWindows.indexOf(index);
list.shift(i, 1);
setOpenedWindows(list);
//alert(index);
}
Github Repository

Shift method is supposed to remove the first element of the array and does not take any arguments. You could use the splice method instead.
However, I find filter method works best here:
const handleWindowRemove = (index) => {
const updatedList = openedWindows.filter((el, idx) => idx !== index);
setOpenedWindows(updatedList);
}

I think you are looking for Array.prototype.splice.
Array.shift removes the first item of an array.
Here is a corrected example:
const [openedWindows, setOpenedWindows] = useState([
]);
const handleWindowAdd = () => {
setOpenedWindows([...openedWindows, { openedWindow: "" }]);
}
const handleWindowRemove = (index) => {
const list = [...openedWindows];
const i = openedWindows.indexOf(index);
list.splice(i, 1);
setOpenedWindows(list);
//alert(index);
}

If you are dealing with a list of array elements, using an index for
identifying an element to perform some operation, especially delete
is not recommended at all.
Since you are passing 'index' as an argument for 'handleWindowRemove', I am assuming you are using 'index' as a key while rendering the list of elements. Whenever you perform an delete operation on element using "splice" or any other method using 'index', it will result in change of index of other elements present in Array too. If you are using index as key while rendering list of array elements, everytime you delete an item in Array using index, index of remaning elements will change and cause re-rendering of almost all the elements present in array. This is not the recommended approach since it will re-render the elements that are not modified.
Better approach would be having 'id' properties for all the objects of Array. In this approach, 'id' can be used as a key while rendering and also as an identifier while deleting the object from the array. Due to this, other window objects won't be affected. Hence re-rendering of unmodified objects will not happen.
const openedWindows = [{'id': # identifier, 'windowObject': ...}]

Related

JavaScript Objects filtering out specific property names

I am creating a filter for a diagram. Whenever a filter is clicked it should remove that category from the diagram. The api call returns an object with names. let’s say the object returns 40 items and I want to filter 5 out by name. What is the best way to approach this?.
I tried to manually type the property names into an array and run the .filter on my object like below. However it returns the entire object unfiltered.
filterDiagram() {
Const array = [“all the names of the properties I want to filter out”]
carbonates = array.forEach(x) => {console.log(x)}
Const filterCat = data.filter (io =>
io.name !== carbonates)
}
Let's say, the array consists of all the names/categories you want to take out.
const toBetakenOut = ['fruits','salts', 'etc' ]
// Please make sure they are not 1 string but rather comma-separated values.
You can filter the API data by using the filter function on the data,to remove objects with names that are within toBetakenOut.
const filterCat = data.filter (io => !toBetakenOut.includes(io.name))
function filterDiagram(){
const dontWantsArray = [/*all of the things you dont want*/];
// Outputs an array of keys
const filteredKeys = Object.keys(yourJSObject)
.filter(key => !dontWantsArray.includes(key));
// After you found the keys you can get the values to another array by keys
const filteredValues = filteredKeys.map(key => yourJSObject[key]);
}

How to add and update objects into array of objects?

I am trying to dynamically add an object to an array of objects, I have been trying to Destructuring the main object but it adds a number to the end of the parent array. This is what I have:
const [data, setData] = useState ([
{
_id:1,
firstName:'Leo',
lastName:'Miller',
telephone:'+569273829',
mail:'leo.miller#gmail.com',
work:[
{_id:1, startWorkDate:'01/01/2015', endWorkDate:'01/02/2017', work:'description...'},
{_id:2, startWorkDate:'01/01/2018', endWorkDate:'01/02/2020', work:'description...'}
]
}];
I generate dynamically this object:
const value = {_id:3, startWorkDate:'01/01/2018', endWorkDate:'01/02/2020', work:'description...'}
I need to add it into data.work and after that update only the description of work._id[3]
I try with this function
const addNewWork = (value) => {
let copyData = [...data, data[0].workExperience.push(value)]
return setData(copyData)
}
but for some reason doesn't add correctly the object. Help please!
You have an array and not an object. Your statement
let copyData = [...data, data[0].workExperience.push(value)]
is doing two things:
mutating the state by doing push(). Which is not the react way.
creating a new array. Also adding a new item to the array, but that is the new length of data[0].workExperience.
The return value of Array.prototoype.push is:
The new length property of the object upon which the method was called.
What you have to do is:
Make a copy of the array. Can use ... (spread operator) here.
Make a copy of the array object you want (first index). Try to add the object to its specific property workExperience.
const addNewWork = (value) => {
let newData = [...data];
let newWorkExperienceArray =
[...data[0].workExperience,value];
let newDataFirstObject = {...data[0], workExperience : newWorkExperienceArray};
newData[0] = newDataFirstObject;
return setData(newData)
}
You can also update the property. I didn't find the relevant code in your question as to what I have to update so I didn't update anything in the third workExperience object.
EDIT: It seems in your code the property name is work and not workExperience. Please confirm. The above code uses workExperience, you can replace it by work if that is the case
You can do this with this simple function:
const addNewWork = (value) => {
let updatedObj = data[0];
updatedObj.work.push(value)
// updates your object each time
let copyData = [updatedObj]
// adds a new object for each call
// let copyData = [...data, updatedObj]
return setData(copyData)
}
Now it updates the object in your state. If you want to add a new object for each call just uncomment let copyData = [...data, updatedObj] and comment out let copyData = [updatedObj]
When you set state for array your setter is a quite bite different
setData(prevData => [...prevData, newItem]) // to add a single item to array
setData(prevData => newArray) // to replace entire array

A shorter/cleaner way to add item to beginning of array, while also removing the last?

I added pagination to a project I'm working on, which uses React and Redux.
When I create a new item, I want it appended to the current list, while also removing the last item in the list; as each page has a limit to how many items to display.
The solution I came up with is something like this.
Basically, I want to add 1 to the array, but also remove 3; so the new array will be [1,2].
EDIT: sorry, but if this was a redux reducer, where I have to do everything in one line, how would I accomplish that?
const add = 1;
const state = [2,3];
const update = [add, ...state.filter((num, idx) =>{
return idx !== state.length - 1
})]
reducer sample:
return {
...state,
items: [add, ...state.filter((num, idx) =>{
return idx !== state.length - 1
})]
}
I might be overthinking it, and I have a feeling there is a much much cleaner way to write this..
What I also don't like is that I'm not even using the first argument in filter. It's just there so I can access the index..
You can use slice(). The negative ending index works backwards from end of array
const add = 1;
const state = [2,3]
const res = [add, ...state.slice(0,-1)]
console.log(res)
To remove the last element of an array use array pop method and to add an element to first position use array unshift method.
const add = 1;
const state = [2, 3];
state.pop();
state.unshift(add);
console.log(state);

filter an array of objects based on key/value and remove it from array

In the following function I push and object to the accountsToDelete array, I need to then remove the matching object from the accountsToAdd array. I am guessing I would have to use a combination of IndexOf, Filter, Reduce but I am still a little rough in understanding how to accomplish this. This is the current function:
accountDelete(id, name) {
const accountsToAdd = this.userForm.value.accountsToAdd;
const accountsToDelete = this.userForm.value.accountsToDelete;
this.userForm.value.accountsToDelete.push(
{
id: id,
name: name
}
);
}
You can simply use the filter function. By this you can say, that in the accountToAdd all entries should be filtered, which id fits the to deleted account.
An example:
// Initialize both lists.
let accountsToAdd = []
let accountsToDelete = []
// Preparation by adding a account to the first list.
const account = { id: 1, name: 'Max' }
accountsToAdd.push(account)
// Mark account to be removed.
accountsToDelete.push(account)
accountsToAdd = accountsToAdd.filter(acc => acc.id !== account.id)
// Verify result.
console.log(accountsToAdd)
console.log(accountsToDelete)
Note:
Your both lists are defined as constant. By this you can't use the reassignment.

How to remove an object from an array in Immutable?

Given a state like this:
state = {
things: [
{ id: 'a1', name: 'thing 1' },
{ id: 'a2', name: 'thing 2' },
],
};
How can I create a new state where ID "a1" is removed? It's easy enough to push new items:
return state.set(state.get('things').push(newThing));
But I can't figure out how to search for and remove an object by its id property. I tried this:
return state.set('tracks',
state.get('tracks').delete(
state.get('tracks').findIndex(x => x.get('id') === 'a2')
)
)
But it seems messy, plus it only works if the item is found, because if findIndex returns -1, that's a valid value for delete.
You can use Array#filter.
return state.set('things', state.get('things').filter(o => o.get('id') !== 'a1'));
When you are using filter it iterates all cycle -> one effective way is finding index => slice and using splitter ...
const index = state.findIndex(data => data.id === action.id);
return [...state.slice(0, index), ...state.slice(index + 1)];
Alternatively, as you are "searching and then deleting"...
var itemIndex = this.state.get("tracks").findIndex(x => x.get('id') === 'a2');
return itemIndex > -1 ? this.state.deleteIn(["tracks", itemIndex]) : this.state;
This will ensure the state is not mutated when there are no changes.
Found this thread while looking for a solution to a similar task.
Solved it with update method:
return state.update('things', (things) => things.filter((t) => t.id !== action.things.id))
any idea/comment which one is better/preferred?
You can do that even without immutable.js with following function.
function arrayFilter(array, filter) {
let ret = array
let removed = 0
for (let index = 0; index < array.length; index++) {
const passed = filter(array[index], index, array)
if (!passed) {
ret = [...ret.slice(0, index - removed), ...ret.slice(index - removed + 1)]
removed++
}
}
return ret
}
ImmutableJS working with nested arrays
Immutablejs is great but at the same time makes things more complicated in some edge cases, particularly when working with nested arrays.
Sometimes it is easier to take it back to JS in a general sense for this particular issue.
// 1. get a copy of the list into normal JavaScript
const myList = state.getIn(['root', 'someMap', 'myList']).toJS()
// 2. remove item in list using normal JavaScript and/or anything else
myList.splice(deleteIndex, 1)
// 3. return the new state based on mutated myList
return state
.mergeDeep({ root: { someMap: { myList: undefined } }})
.mergeDeep({ root: { someMap: { myList } }})
Unfortunately, step 3 is necessary to specifically set to undefined because if you simply set myList directly as an array value, ImmutableJS will do a comparison of values between the current list and only modify them creating strange behavior.
The justification for this is to simplify the mental overhead. I do not recommend doing this in a loop, rather manipulate the pure JS array in a loop if you must but should be prior to step 3.

Categories

Resources