I have an array of objects in the below format.
let selectedCols =
[
{
"table" :
{
"id" : "bafc1af7-e2c5-ec11-a7b6-00224818a168",
"name" : "test1"
}
visible : true
trueCol : 1
},
{
"table" :
{
"id" : "cdep1af7-e4c5-ec11-a7b6-00224818a198",
"name" : "test2"
}
visible : true
trueCol : 2
}
]
I am creating a copy of the above object in my code and modifying its visible property in the copied object
let copyOfSelectedColsObj = JSON.parse(JSON.stringify(selectedCols ));
copyOfSelectedColsObj.forEach(column => column.visible = false);
Now i only want to copy the value of 'visible' property from copyOfSelectedColsObj back in to my original object wherever the id field is matching.How can i achieve this?
I am quite new to javascript and can't figure out this. Any help would be appreciated
You can use forEach again to iterate over the original array (selectedCols) and when it finds an element with the same id as the current element in the target array (copyOfSelectedColsObj), replace the visible property.
let selectedCols = [{table:{id:"bafc1af7-e2c5-ec11-a7b6-00224818a168",name:"test1"},visible:true,trueCol:1},{table:{id:"cdep1af7-e4c5-ec11-a7b6-00224818a198",name:"test2"},visible:true,trueCol:2}];
let copyOfSelectedColsObj = JSON.parse(JSON.stringify(selectedCols));
const overwrite = () => {
selectedCols.forEach(column => {
// Get the current element id
const tableId = column?.table?.id;
// If the current element id does not exist, no processing is required
if (tableId) {
// Find element matching element id from target array
const filtered = selectedCols.filter(c => c?.table?.id == tableId);
// When the element is found, replace the visible property
if (filtered.length > 0) {
column['visible'] = filtered[0]['visible'];
}
}
return column;
});
}
// Replace all visible with false
copyOfSelectedColsObj.forEach(column => column.visible = false);
overwrite();
console.log('Replace all visible with false', copyOfSelectedColsObj);
// Replace one of the visible with true
copyOfSelectedColsObj[0]['visible'] = true;
overwrite();
console.log('Replace one of the visible with true', copyOfSelectedColsObj);
selectedCols.forEach((column,i) => {
if(column.table.id===copyOfSelectedColsObj[i].table.id) {
column.visible = copyOfSelectedColsObj[i].visible;
}
})
You said wherever the id field is matching, since copied object is replica of original object, don't you think every id would match hence you can set all visible properties to false.
I will suggest to loop one array inside another loop, but only for small arrays.
something like this:
let newSelectedCols = selectedCols.map((i) => {
return {
...i,
visible: copyOfSelectedColsObj.find(
(j) => j.table.id === i.table.id
)?.visible,
};
});
The map will iterate over the original and for each element it will look for the item with the same table.id and (if exists) it will copy the "visible" value.
Related
I have a dynamic list of items a user adds. I want to avoid duplicating when a user adds an item already present in the list. My list looks like
itemList = [ {itemId:1, name:"x", quantity:5}, {itemId:4, name:"y", quantity:2}]
so now if a user adds item x with quantity 2 i want the object with item x to update the quantity to 7 rather than adding a whole new object.
I am using find() method to get the item already present and storing it to a variable, itemObj is the item the user recently added.
let alrItem = state.itemList.find(
(e) => e.itemId === itemObj.itemId
);
let newItem = alrItem;
newItem.quantity += itemObj.quantity;
How do I merge this newItem to the itemList so that it just updates the quantity of that specific item?
What you are doing is finding the object in the itemList array and then mutating the state directly. State should not be mutated directly.
Instead of using .find() method, use the .map() method to iterate over the array and update the quantity of the item that matches with the id of the new item.
let updatedItemList = state.itemList.map((item) => {
if (item.itemId === itemObj.itemId) {
return { ...item, quantity: item.quantity + itemObj.quantity };
}
return item;
});
// update the state
setItemList(updatedItemList);
Note that above code will not do anything if the item isn't already present in the itemList. Ideally, you should also handle the case where the new item isn't already present in the itemList. In this case, you should just add the new item in the itemList.
To handle this case, all you need is a extra variable that can be used to know whether the if condition inside the .map() method evaluated to true or not.
let exists = false;
let updatedItemList = state.itemList.map((item) => {
if (item.itemId === itemObj.itemId) {
exists = true;
return { ...item, quantity: item.quantity + itemObj.quantity };
}
return item;
});
// if the item isn't present in the list, add it in the "updatedItemList"
if (!exists) {
updatedItemList.push(itemObj);
}
// update the state
setItemList(updatedItemList);
let itemList = [ {itemId:1, name:"x", quantity:5}, {itemId:4, name:"y", quantity:2}]
let itemObj = {itemId:1, name:"x", quantity:2}
const target = itemList.find(element =>
element.itemId === itemObj.itemId
);
if (target) {
target.quantity = target.quantity + itemObj.quantity;
} else {
itemList.push(itemObj);
}
console.log('itemList: ' + JSON.stringify(itemList));
OUTPUT:
itemList: [{"itemId":1,"name":"x","quantity":7},{"itemId":4,"name":"y","quantity":2}]
I have the following line:
<button className={`actionBoxButton ${props.moves[0].moveName !== "FirstPassMove" && props.moves[0].moveName !== "PassMove" ? "actionBoxButtonGrey" : ''}`}
What it does is to check if the object "moves" has the value "FirstPassMove" for the key moveName. If so, I want it so switch to another style. This is working well.
But what I want to achieve is, to not only check the element 0 of the object, but all the objects and check if there is a moveName "FirstPassMove" in any element of the object.
It is written in React 16.12
Thanks!
You can simplify your jsx by defining a separate function for dynamic className like this:
const check = () => {
let className_ = "";
// if this.props.moves is an array, use of instead of in
for(let i in this.props.moves) {
if((this.props.moves[i].moveName !== "FirstPassMove") && (this.props.moves[i].moveName !== "PassMove")) {
className_ = "actionBoxButtonGrey";
}
}
return className_;
}
<button className={this.check()}>button</button>
props.moves.includes('FirstPassMove')
Assuming your props.moves is an array it will return true or false if this string is inside the props.moves array
If you want to add className in case at least one of your moves has FirstPassMove or PassMove name you should use Array.prototype.some()
const hasPass = moves.some(({ moveName }) => (
moveName === "FirstPassMove" ||
moveName === "PassMove"
));
I am guessing you want to check that all the moves satisfy the constraint, in which case, you can use Array.prototype.every to ensure every move satisfies the constraint. If you only need some moves to satisfy the constraint, you may use Array.prototype.some instead.
// For example
const props = {
moves: [
{ moveName: 'FirstPassMove' },
{ moveName: 'PassMove' },
{ moveName: 'PassMove' },
{ moveName: 'OtherPassMove' },
]
};
function isValidMove({ moveName }) {
return moveName !== "FirstPassMove"
&& moveName !== "PassMove";
}
function getActionBoxButtonClassName(hasColor) {
return `actionBoxButton ${hasColor ? "actionBoxButtonGrey" : ''}`;
}
console.log([
getActionBoxButtonClassName(props.moves.every(isValidMove)),
getActionBoxButtonClassName(props.moves.some(isValidMove))
]);
Here my code and what i tried :
filterPrestationsByServiceSelected(arrayOfServices) {
console.log(arrayOfServices); // ['Repassage', 'Couture']
this.filteredPrestationsByService = this.filteredPrestations.filter(item => item.service.name.includes(arrayOfServices.values()));
},
I want to filter all items of this.filteredPrestations where the service name contains values of the arrayOfServices.
Anyone have an idea of what i can do ?
Thank's !
Remove .values() it returns an iterator which you don't need
filterPrestationsByServiceSelected(arrayOfServices) {
console.log(arrayOfServices); // ['Repassage', 'Couture']
this.filteredPrestationsByService = this.filteredPrestations.filter(item => item.service.name.includes(arrayOfServices));
}
You have to compare the items of a list with another. So you would have to have a compare each element of one data structure with another. Since you are comparing arrays you should do that way:
filterPrestationsByServiceSelected(arrayOfServices) {
console.log(arrayOfServices); // ['Repassage', 'Couture']
this.filteredPrestationsByService = this.filteredPrestations.filter(item => arrayOfServices.find(e => e === item.service.name))
},
That way you could compare the elements one by one.
Can you try this code. I think this code will work.
filterPrestationsByServiceSelected(arrayOfServices) {
console.log(arrayOfServices); // ['Repassage', 'Couture']
this.filteredPrestationsByService = this.filteredPrestations.filter(item => arrayOfServices.includes(item.service.name));
},
I have a problem of find a value in an array inside another array, and use the result to setState()
This is the initialState:
this.state =
{
initialStudents:[
{name:"str1",tags;["str","str",...],...},
{name:"str2",tags;["str","str",...],...},
...
],
students: [
{name:"str1",tags;["str","str",...],...},
{name:"str2",tags;["str","str",...],...},
...
]
}
The code i use to find the tags:
findTag = (tags, target) => {
tags.filter(tag => {
return tag.toLowerCase().search(target.toLowerCase()) !== >-1;
});
};
filterTag = e => {
let updatedList = this.state.initialStudents;
updatedList = updatedList.filter(student => {
return this.findTag(student.tags, e.target.value);
});
this.setState({ students: updatedList });
};
The filterTag does not update the students state
To solve your problem, I made a few edits and put them all in this working codesandbox example.
First, I changed your findTag function to something like this:
// pass in the tags from the student, and the target tag you're searching for.
// -> return true if 1 or more matching tag, false otherwise
findTag = (tags, targetTag) => {
// make sure you return something!
return tags.filter(tag => {
// check if current tag in arr matches target tag (case insensitive)
return tag.toLowerCase() === targetTag.toLowerCase();
}).length > 0; // check if there's 1 or more matching tag
};
Next, I updated the filterTag function in a few ways:
Immutably copy this.state.initialStudents into the local updatedList array. This is necessary so you don't mess up the current state before running this.setState!
Pass the value of the input via this.state.filterTag instead of e.target.value. This way, you'd update the filter when you click the button instead of on every time you press a key.
Here's how these changes look:
filterTag = e => {
// immutably copy initial student data
let updatedList = this.state.initialStudents
.map(student => ({
name: student.name,
tags: [...student.tags]
}))
// remove students w/out filter tag
.filter(student => {
return this.findTag(student.tags, this.state.filterTag);
});
// update state with new student list
this.setState({ students: updatedList });
};
A few other improvements I made:
Instead of manually setting data in initialStudents and students, I made them immutably copy the same data set from the const initialStudents data set. This could be done in the componentDidMount lifecycle method if you're fetching students from a database.
I fixed your student object declarations - you put tags;["str"...] which is invalid - the semicolon ; should be a normal colon :
I changed some "str" values to "str2" to make them unique between students
Let me know if you have questions about the codesandbox or anything else :D Hope it helps!
I have an array of object something like below
Object[0]
canUpload:false
canBeRemoved:true
type:Object
allowMultiple:false
deleted:false
key:"testValue"
Object[1]
canUpload:true
canBeRemoved:true
type:Object
allowMultiple:false
deleted:false
key:"testValue2"
I want to remove an elements from array which contains key:testValue
var myValues = this.testData.data3;
if(!this.testData.canDownload){
myValues= myValues.filter(function(value){
if(!value.canUpload)
return value.type.key==='testValue';
else return false;
});
But its not removing .Whats the right way to do it?
Here is the full code .I can see myValues array of size 2 .If i print myValues after if block its empty.
Code pen:http://codepen.io/developer301985/pen/woGBNg
If your want to filter your array on the basis of two conditions:
canUpload attr is false
type.key is equal to 'testValue'
so you may want to return false in case of canUpload is true to be as follow:
myValues= myValues.filter(function(value) {
if(!value.canUpload)
return value.type.key === 'testValue';
else return false;
});
Otherwise, you just want to filter on type.key is equal to 'testValue', so it will be as follow:
myValues= myValues.filter(function(value) {
return value.type.key === 'testValue';
});
Note, if the callback function you passed into filter returns true, the element will be kept rather than removed. So in your case, you should return false when the value is testValue.
If I understand you correctly, you want to remove item with value.canUpload==false AND type.key === 'testValue'. Then the negate is value.canUpload || value.type.key !== 'testValue'
var myValues = this.testData.data3;
if (!this.testData.canDownload) {
myValues = myValues.filter(function(value) {
return value.canUpload || value.type.key !== 'testValue';
});
}
Let me know whether it works :)