I have an array in my state called columnToFilterOut. Let's say this is my array in my state: columnToFilterOut = ["first_col", "second_col", "third_col"]
I also have another array in state called rows that contains a list of dicts where there is a key called id that is corresponding to the values in columnToFilterOut. Here is an example of rows:
rows: [
{
id: "first_col",
numeric: false,
disablePadding: true,
label: "1"
},
{
id: "second_col",
numeric: true,
disablePadding: false,
label: "2"
},
{
id: "third_col",
numeric: true,
disablePadding: false,
label: "3"
},
{
id: "fourth_col",
numeric: true,
disablePadding: false,
label: "4"
}
]
As you can see, there is an extra element in there. The extra value is the one with id = "fourth_col". I want to delete all elements to make sure that both arrays match up.
Here is my delete function:
removeFromRowsById(id) {
console.log("IN REMOVE FUNCTION");
const filteredValues = this.state.rows.filter((_, i) => i["id"] !== id);
this.setState({ rows: filteredValues });
}
So I pass in an id and it should remove the value with the given id. Inside my render function, I use it like this:
Object.keys(rows).map(
(key, index) =>
!(columnToFilterOut.indexOf(rows[index]["id"]) > -1) //meaning the value doesn't exist inside of columnToFilterOut
? this.removeFromRowsById.bind(this, rows[index]["id"])
: console.log("Not deleting")
);
This isn't working. The value in the rows array is never removed. I print it to make sure. I also notice that my print statement inside of removeFromRowsById never logs to the console as though the function never actually gets called. Any help is great. Thanks!
try to change your this.state.rows.filter, to be like below. and see if it works
removeFromRowsById(id) {
console.log("IN REMOVE FUNCTION");
// 1. the original code should be === not !==, because you want to delete when the id matches.
// 2. the "i" should be on first parameter not second
const filteredValues = this.state.rows.filter((i, _) => i["id"] === id);
this.setState({ rows: filteredValues });
}
I changed the removeFromRowsById to look like this:
removeFromRowsById = index => {
console.log("IN REMOVE FUNCTION");
const newList = [...this.state.rows1];
newList.splice(index, 1);
this.setState(state => ({
rows1: newList
}));
};
And I call it regularly in the render function (without the binding). I think you needed to use the arrow function which fixed the issue and I revamped the way it deletes from the list in case what #vdj4y said was true
Related
I have this variable in my environment.ts:
featureToggle: {"feature1": true, "feature2: false}
In a service of mine, I want to give these values to a component with a getAll-method, just like:
getAll() {
return environment.featureToggle;
}
In a component I'm having an array and call the servicemethod in my ngOnInit, where I assign the values to my array. Through *ngFor im iterating through the array.
Then I get an ERROR NG0901 IterableDiffers.find.
Yes, it might be, because it is an Object Array, so I would have to convert it in my service first to a normal Array, or assign the values to an interface to work with it?
like
interface FeatureInterface {
feature: string,
isActive: boolean;
}
But I can't even .map through my environments variable nor does forEach work. I also tried Object.keys(environment.featureToggle). Is there any way to access and iterate my properties in my environment.ts and work with them in any component?
Component:
features: FeatureInterface[] = [];
ngOnInit(): void {
this.features = this.featureToggleService.getAllFeatures()
Html:
<div *ngFor="let item of features">
{{item.feature}}
...
Check this out!
let featureToggle = { "feature1": true, "feature2": false, "feature3": true};
const result = Object.entries(featureToggle).filter((e) => e[1]).map((i) => i[0]);
console.log(result);
UPDATE 1:
Based on the requirement(as mentioned in the comments), try this:
let featureToggle = { "feature1": true, "feature2": false, "feature3": true };
const result = Object.entries(featureToggle).map((i) => {
return {
feature: i[0],
isAvailable: i[1]
}
});
console.log(result);
[ { feature: 'feature1', isAvailable: true },
{ feature: 'feature2', isAvailable: false },
{ feature: 'feature3', isAvailable: true } ]
Here I am trying to modify my data over the iteration and send some result to API call.
The API Call receives a request with a structured data format which is
{ list: [{ id: "1", name: "Hello" }, ... ] }
Somehow I managed to call the API with single data ( const params in my current code, it only accepts single data).
But now it has to be done with multiple data something like this:
{ list: [{ id: "1", name: "Hello" }, { id: "22", name: "Ed" }, { id: "36", name: "Jason" } ... ] }
Here is my current code
const [table, setTalbe] = useState(..); // assume, we have some table data here
const processNow = () => {
let id = 0;
let name = '';
// if table length is greater than 1, we go for the loop.
if (table.length >= 1) {
table.map(data => {
id = data.userId;
name = data.userName;
});
//insert table data to params, here I want to add whole table data into "list"
//the final result of this list should be something like this
//ex ) list: [{ id: '123', name: 'Josh' }, { id: '125', name: 'Sue' }, { id: '2222', name: 'Paker' } ...],
// but how??
const params: any = {
list: [
{
id: id,
name: name
},
],
};
//send PUT reqeust with params
axios
.put(
'/api/v1/tosent',
params,
)
.then(res => {
console.log('The response', res);
})
.catch(err => {
console.log('The error: ', err);
});
}
};
but I'm stuck with it, please help me to finish this code to work properly.
need your kind advice.
Array.prototype.map returns a new array with the function you pass applied to every element. You should study the MDN documentation on map to understand its use.
Your current code does nothing with the map return value:
table.map(data => {
id = data.userId;
name = data.userName;
});
You probably assumed .map would mutate the data, as in change it in place. Instead, the whole operation returns a new array.
It looks like you want to do:
const list = table.map(data => {
return {
id: data.userId,
name: data.userName
}
});
This is applying a function to every element in the array that will map each element to a new object, matching your question, with an id and name key. Then it looks like you want to pass the returned value of map (which we named list above) to your call:
const params: any = {
list: list
};
In React's this.state I have a property called formErrors containing the following dynamic array of objects.
[
{fieldName: 'title', valid: false},
{fieldName: 'description', valid: true},
{fieldName: 'cityId', valid: false},
{fieldName: 'hostDescription', valid: false},
]
Let's say I would need to update state's object having the fieldName cityId to the valid value of true.
What's the easiest or most common way to solve this?
I'm OK to use any of the libraries immutability-helper, immutable-js etc or ES6. I've tried and googled this for over 4 hours, and still cannot wrap my head around it. Would be extremely grateful for some help.
You can use map to iterate the data and check for the fieldName, if fieldName is cityId then you need to change the value and return a new object otherwise just return the same object.
Write it like this:
var data = [
{fieldName: 'title', valid: false},
{fieldName: 'description', valid: true},
{fieldName: 'cityId', valid: false},
{fieldName: 'hostDescription', valid: false},
]
var newData = data.map(el => {
if(el.fieldName == 'cityId')
return Object.assign({}, el, {valid:true})
return el
});
this.setState({ data: newData });
Here is a sample example - ES6
The left is the code, and the right is the output
Here is the code below
const data = [
{ fieldName: 'title', valid: false },
{ fieldName: 'description', valid: true },
{ fieldName: 'cityId', valid: false }, // old data
{ fieldName: 'hostDescription', valid: false },
]
const newData = data.map(obj => {
if(obj.fieldName === 'cityId') // check if fieldName equals to cityId
return {
...obj,
valid: true,
description: 'You can also add more values here' // Example of data extra fields
}
return obj
});
const result = { data: newData };
console.log(result);
this.setState({ data: newData });
Hope this helps,
Happy Coding!
How about immutability-helper? Works very well. You're looking for the $merge command I think.
#FellowStranger: I have one (and only one) section of my redux state that is an array of objects. I use the index in the reducer to update the correct entry:
case EMIT_DATA_TYPE_SELECT_CHANGE:
return state.map( (sigmap, index) => {
if ( index !== action.payload.index ) {
return sigmap;
} else {
return update(sigmap, {$merge: {
data_type: action.payload.value
}})
}
})
Frankly, this is kind of greasy, and I intend to change that part of my state object, but it does work... It doesn't sound like you're using redux but the tactic should be similar.
Instead of storing your values in an array, I strongly suggest using an object instead so you can easily specify which element you want to update. In the example below the key is the fieldName but it can be any unique identifier:
var fields = {
title: {
valid: false
},
description: {
valid: true
}
}
then you can use immutability-helper's update function:
var newFields = update(fields, {title: {valid: {$set: true}}})
I'm trying to use lodash's find method to determine an index based on one attribute. In my case this is pet name. After that I need to change the adopted value to true using setState. The problem is however; I do not understand how to combine setState and _.find()
As of right now I have this written. My main issue is figuring out how to finish this.
adopt(petName) {
this.setState(() => {
let pet = _.find(this.state.pets, ['name', petName]);
return {
adopted: true
};
});
}
This does nothing at the moment as it is wrong, but I don't know how to go from there!
In React you usually don't want to mutate the state. To do so, you need to recreate the pets array, and the adopted item.
You can use _.findIndex() (or vanilla JS Array.findIndex()) to find the index of the item. Then slice the array before and after it, and use spread to create a new array in the state, with the "updated" item:
adopt(petName) {
this.setState(state => {
const petIndex = _.findIndex(this.state.pets, ['name', petName]); // find the index of the pet in the state
return [
...state.slice(0, petIndex), // add the items before the pet
{ ...state[petIndex], adopted: true }, // add the "updated" pet object
...state.slice(petIndex + 1) // add the items after the pet
];
});
}
You can also use Array.map() (or lodash's _.map()):
adopt(petName) {
this.setState(state => state.map(pet => pet.name === petName ? ({ // if this is the petName, return a new object. If not return the current object
...pet,
adopted: true
}) : pet));
}
Change your adopt function to
adopt = petName => {
let pets = this.state.pets;
for (const pet of pets) {
if (!pet.adopted && pet.name === petName) {
pet.adopted = true;
}
}
this.setState({
pets
});
};
// sample pets array
let pets = [
{
name: "dog",
adopted: false
},
{
name: "cat",
adopted: false
}
]
I want to remove an element from my array when click on a specific row.
When I click on an element it does nothing or the last row gets deleted.
I tried to remove the element like this:
ondeleterow(e: any) {
const array = [...this.state.fields.columns]; // make a separate copy of the array
const index = array.indexOf(e.target.id);
if (index !== -1) {
array.splice(index, 1);
this.setState({ fields: { columns: array }});
}
}
My array/json object looks like this:
[ {index: 0, name: "person 1", age: 12},
{index: 1, name: "person 2", age: 19},
{index: 2, name: "person 3", age: 34},
]
My result should be when I click on a row with ID=1 the row with index: 1 gets deleted from my state array.
I can't give them an Id because when I submit the json structure then does not get accepted.
I feel like your Array.splice might be causing the issue here (because even though you created a new array, the objects in the array are still passed by reference).
I would recommend a completely different method of doing this operation which I've found to be far cleaner and robust.
First you have to add a unique id field to each row. (this is good practice in react anyway, instead of using index for keys).
ondeleterow(id: string) {
return (e: any) => {
const array = this.state.fields.column.filter(item => item.id != id)
this.setState({ fields: { columns: array }});
}
}
and when you're mapping over your rows, you can simply add the function to the onClick like this
<Row key={item.id} onClick={ondeleterow(item.id)} />
Never use splice in react especially with state. They directly mutate the data. Use non mutating operations like slice.
Your code should as follows
ondeleterow(e: any) {
const array = [...this.state.fields.columns]; // make a separate copy of the array
const index = array.indexOf(e.target.id);
if (index !== -1) {
array.splice(index, 1);
this.setState({ fields: {
columns: [ ...array.slice(0, index), ...array.slice(index + 1, array.length) ]
}});
}
}
You can use Array.filter. This will allow you to create a new array with only the items you want based on a certain criteria. In this case, you want an array with items that have a different ID that the one you want to remove. So it will look like this
// Actual processing
const filterByIndex = (arr, idx) => arr.filter(x => x.index !== idx);
// Your data
const json = [{
index: 0,
name: "person 1",
age: 12
},
{
index: 1,
name: "person 2",
age: 19
},
{
index: 2,
name: "person 3",
age: 34
},
];
// Printing the result
console.log(filterByIndex(json, 1));
In your React app
ondeleterow(e: any) {
const columns = this.state.fields.columns.filter(x => x.index !== e.target.id);
this.setState({ fields: { columns }});
}
Try this
onDeleteRow(e) {
const afterRemoval = this.setState.fields.columns.filter(item => item.index != e.target.id);
this.setState(prevState => ({ fields: { ...prevState.fields, columns: afterRemoval } }));
}
The other solution above sets the fields field directly, It may work but will cause problem if fields has some other attribute other than columns (those attributes will get removed)