I was wondering about how to replace the item if it already exists inside state array and I got a great solution
https://codesandbox.io/s/4xl24j7r69
It works fine but my problem is I can't add a new item if the item doesn't exist inside the array I got an error Cannot convert undefined or null to object
Like this:
add = () => {
let newUser1 = {
"userId": 1,
"id": 3, // this is new id which is doesn't exist in this.state.data
"title": "Two New",
"body": "new data"
}
this.setState(prevState => {
let newData = prevState.data;
let user = newData.find(d => d.id === newUser1.id);
Object.assign(user, newUser1);
return { data: newData };
})
};
You're not adding the newUser to the data on state.
add = () => {
let newUser1 = {
"userId": 1,
"id": 4,
"title": "Two New",
"body": "new data"
}
this.setState(prevState => {
const user = prevState.data.find(d => d.id === newUser1.id);
if (!!user) {
//Casting user to a boolean, if find did return a truthy value you add it to the data with map
Object.assign(user, newUser);
const newData = prevState.data.map(d => d.id === user.id ? user : d);
return { data: newData }
} else {
return { data: prevState.data.concat(newUser1)};
}
})
};
Related
i have a issue, i have two inputs then and i can't permit the user save this edit if the two values is equals.
my state who contains a data from db
const [doctorRegisters, setDoctorResgisters] = useState<any>([]);
inside this array i contain this
[{"__typename": "DoctorMedicalRegister", "counsil": "CRM", "id": "141", "isMainRegister": true, "register": "1234567/RS"}, {"__typename": "DoctorMedicalRegister", "counsil": "CRM", "id": "153", "isMainRegister": false, "register": "1234567/RS"}]
and i need compare two register who if is equal, i cant permit user save he save just is different
here is a code who i try fix this
const isEquals = () => {
doctorRegisters.map((item: any) => {
if (item.register) {
doctorRegisters.map((item2: any) => {
if (item2.register) {
if (item.register === item2.register) {
console.log('iguais')
}
}
});
}
});
};
but this work only for dont edited values i need verify when this value is changed in input in this case i only verify in db this values is equals
here is my handle change
const handleEditRegisterCrm = (crm: string, id: number) => {
setDoctorResgisters(
doctorRegisters.map((item: any) => {
if (item && Number(item.id) == id) {
item.register = `${crm}/${item.register?.split('/')[1] || ''}`;
}
return item;
}),
);
};
You could do something like:
const handleEditRegisterCrm = (crm: string, id: number) => {
if (!doctorRegisters.some((doctorRegister) => doctorRegister.register.includes(registerToCompare)) {
setDoctorRegisters(
doctorRegisters.map((item: any) => {
if (item && Number(item.id) == id) {
item.register = `${crm}/${item.register?.split('/')[1] || ''}`;
}
return item;
}),
);
}
};
Remember you should keep track of the registerToCompare in order to find if it's already inserted in the doctorRegisters list. I'm assuming you can obtain that value from the your handleChange function.
I have an array of objects
[
{
"0": {
"title": "Jessica Simpson",
"id": "324352342323432",
"url": "image-url.jpg",
"colourScheme": "",
"type": "",
"enabledUnits": ""
},
"1": {
"title": "Bill Murray",
"id": "5qocDvdm9XETFz33p725IG",
"url": "image-url.jpg",
"colourScheme": "",
"type": "",
"enabledUnits": ""
},
}
]
I'm attempting to add update the colourScheme value inside the object via an onChange event handler.
OnChangeHandler
const createOnChangeHandler = (floorPlan: FloorPlan, property: 'colourScheme' | 'type') => (
e: React.ChangeEvent<HTMLInputElement>
) => {
console.log(( e.target.value ))
const itemList = floorPlans.concat();
const index = itemList.findIndex((i) => i.id === floorPlan.id);
itemList.splice(index, 1, {...floorPlans, [property]: e.target.value});
};
But it's being added outside the object. For example... notice "colourScheme": "Black" is outside.
{
"0": {
"title": "Angeline Espaze",
"id": "5qocDvdm9XETFz33p725IG",
"url": "image-url.jpg",
"colourScheme": "",
"type": "",
"enabledUnits": ""
},
"colourScheme": "Black"
}
]
Where i would like
[
{
"0": {
"title": "Angeline Espaze",
"id": "5qocDvdm9XETFz33p725IG",
"url": "image-url.jpg",
"colourScheme": "Black",
"type": "",
"enabledUnits": ""
},
}
]
I think the issue is with itemList.splice? inside the onChange
The problem is:
You're spreading the wrong thing into the new object, and
You're not calling a state setter.
I wouldn't use splice for this at all, you can do the object update while copying the array rather than afterward. Instead (see comments):
const createOnChangeHandler = (floorPlan: FloorPlan, property: 'colourScheme' | 'type') => (
e: React.ChangeEvent<HTMLInputElement>
) => {
const {value} = e.target;
// Call the state setter; because we're updating state based on existing state, it's
// best to use the callback version
setFloorPlans(floorPlans => {
// Return a new array with a replaced object
return floorPlans.map(entry => {
if (entry.id === floorPlan.id) {
// Create a replacement object
return {...entry, [property]: value};
}
return entry; // No change to this object
});
});
};
That's assuming you're using hooks. If you're using a class component, use this.setState instead:
const createOnChangeHandler = (floorPlan: FloorPlan, property: 'colourScheme' | 'type') => (
e: React.ChangeEvent<HTMLInputElement>
) => {
const {value} = e.target;
// Call the state setter; because we're updating state based on existing state, it's
// best to use the callback version
this.setState(({floorPlans}) => {
// Return a new array with a replaced object
return {floorPlans: floorPlans.map(entry => {
if (entry.id === floorPlan.id) {
// Create a replacement object
return {...entry, [property]: value};
}
return entry; // No change to this object
}});
});
};
Try below code.
const createOnChangeHandler = (floorPlan: FloorPlan, property: 'colourScheme' |
'type') => ( e: React.ChangeEvent<HTMLInputElement>) => {
let lclfloorPlans = [...floorPlans];
lclfloorPlans.forEach(item => {
for (var key in item) {
if (item[key].id === floorPlan.id) {
item[key][property] = e.target.value;
break;
}
}
});
setFloorPlans(lclfloorPlans); // assign to your state value
};
I have the following object with multiple arrays. I'm trying to filter to get the id to remove the item in onClick. What I've tried is this far, but the error filters.
The error message is filter is not a function
The filters is where save state the object below
Function handleRemoveItem
const handleDeleteFilter = (itemId: string) => {
const entries = Object.entries(filters).map((s) =>
s[1].map((e: any) => filters.filter(() => e.id !== itemId))
)
}
Object called Filters
{
"services": [
{
"id": "1b975589-7111-46a4-b433-d0e3c0d7c08c",
"name": "PIX"
},
{
"id": "91d4637e-a17f-4b31-8675-c041fe06e2ad",
"name": "Rendimentos"
}
],
"accountTypes": [
{
"id": "1f34205b-2e5a-430e-982c-5673cbdb3a68",
"name": "Conta digital"
}
],
"channels": [
{
"id": "875f8350-073e-4a20-be20-38482a86892b",
"name": "Chat"
}
]
}
Button onClick
<div
id={filter.id}
key={index}
onClick={() => handleDeleteFilter(filter.id)}
>
<span>Remove</span>
</div>
Here is a simple procedural approach.
const keys = Object.keys(filters);
for (let i=0; i < keys.length; i++) {
const filterArray = filters[keys[i]];
for (let j=0; j<filterArray.length; j++) {
if (filterArray[j].id === itemId) {
delete filters[keys[i]];
}
}
}
The reason for your error is that the filters object is not an array, but an object and thus does not have a .filter method.
The way to fix the syntax error would be by taking Object.entries() of filters as you do in the precious line;
const handleDeleteFilter = (itemId: string) => {
const entries = Object.entries(filters).map((s) =>
s[1].map((e: any) => Object.entries(filters).filter(() => e.id !== itemId))
)
}
However, i don't think this is the best or most readable approach for you.You state your goal as "trying to filter to get the id to remove the item in onClick". If you want to remove the object with id equal to itemId from any / all of the arrays in the filters object (services, accountTypes, channels), then try something more on the lines of;
type IFilter = {id: string, name: string};
type IFilters = { services: IFilter[], accounTypes: IFilter[], channels: IFilter[] }
// Remove an #id from a #filter
const removeId = (filter: IFilter[], id: string): IFilter[] => filter.filter(entry => entry.id.includes(id));
// Remove #id from all #filters
const removeItemFromFilterObj = (id: string, filters: IFilters): IFilters => ({
services: removeId(filters.services, id),
accounTypes: removeId(filters.accounTypes, id),
channels: removeId(filters.channels, id);
});
Here is my initial code that works flawlessly.
const objNotes = [
{},
{
title: "Be better",
body: "Do better"
},
{
title: "You are what you eat",
body: "Eat well and responsibly"
},
{
title: "Look good",
body: "Work good"
}
];
const findNote = (notes, noteTitle) => {
const index = notes.findIndex((note, index) => {
return note.title === noteTitle;
});
return notes[index];
};
const action = findNote(objNotes, "Look good");
console.log(action);
When I attach the method .toLowerCase like down below I get:
TypeError: Cannot read property 'toLowerCase' of undefined
and I don't understand why.
const findNote = (notes, noteTitle) => {
const index = notes.findIndex((note, index) => {
return note.title.toLowerCase() === noteTitle.toLowerCase();
});
return notes[index];
};
Your first object does not have the property title, trying to toLowerCase() that is throwing the error.
You can check if the property in object exists or not before using toLowerCase():
const objNotes = [
{},
{
title: "Be better",
body: "Do better"
},
{
title: "You are what you eat",
body: "Eat well and responsibly"
},
{
title: "Look good",
body: "Work good"
}
];
const findNote = (notes, noteTitle) => {
const index = notes.findIndex((note, index) => {
return note.title == undefined? '' : note.title.toLowerCase() === noteTitle.toLowerCase();
});
return notes[index];
};
const action = findNote(objNotes, "Look good");
console.log(action);
Use Array.find() when you want the item and not the index of the item.
To prevent the error when you call a string method on an undefined value, you can use short-circuit evaluation note.title !== undefined && .... Assuming the note.title is always a string if not undefined, an undefined value would return false immediately, and if it's not undefined the rest of the expression (the comparison) would be evaluated:
const objNotes = [{},{"title":"Be better","body":"Do better"},{"title":"You are what you eat","body":"Eat well and responsibly"},{"title":"Look good","body":"Work good"}];
const findNote = (notes, noteTitle) =>
notes.find((note, index) => // use Array.find()
note.title !== undefined && // the title is not undefined
note.title.toLowerCase() === noteTitle.toLowerCase() // compare the strings
);
const action = findNote(objNotes, "Look good");
console.log(action);
I am trying to use a filter in javascript to search on an array.
Following is my array:-
"customerStatusInfoList": [
{
"customerId": 1110000012,
"caseStatus": "pending",
"customerName": "Robert",
"dateOfRequest": "2018-12-15 00:00:00.0"
},
{
"customerId": 1110000004,
"auditorName": "DcbAdmin",
"caseStatus": "pending",
"customerName": "Sam",
"dateOfRequest": "2018-12-14 12:40:04.0"
}
]
And I am using the following function to filter the array:-
filterTable = event => {
console.log("event.target.value", event.target.value);
console.log("rows", this.state.rows);
if (event.target.value !== "") {
let newRow = this.state.rows.filter(items => {
console.log("item.name", items.customerName);
if (items.customerName!== null)
return items.customerName
.toLowerCase()
.includes(event.target.value.toLowerCase());
});
this.setState({ rows: newRow, query: event.target.value });
} else {
console.log("Query string is empty ", event.target.value);
let newRow = this.state.custList;
console.log("new row :", newRow);
this.setState({ query: event.target.value, rows: newRow });
}
};
I am able to filter on the customerName but when I try to filter using customerId or any other parameter I get customerId.includes is not a function.
But it works on customerName.
How can I filter on the entire table using JavaScript filter?
Any help or suggestion is appreciated. Thank you.
customerId is an integer - you need to cast to string, e.g.:
return `${items.customerId}`
.toLowerCase()
.includes(event.target.value.toLowerCase());
btw, items is a confusing name for the variable - it's a single item
also, you can simplify things a bit by decomposing the item, i.e.:
let newRow = this.state.rows.filter(({customerId, customerName}) =>
`${customerName || ''}`
.toLowerCase()
.includes(event.target.value.toLowerCase())
);
to include any row that matches customerId, customerName, or auditorName:
let newRow = this.state.rows.filter(({customerId, customerName, auditorName}) =>
[customerId, customerName, auditorName].some(field =>
`${field || ''}`
.toLowerCase()
.includes(event.target.value.toLowerCase()))
);
I added a test for type in here.
filterTable = event => {
console.log("event.target.value", event.target.value);
console.log("rows", this.state.rows);
if (event.target.value) {
let newRow = this.state.rows.filter(items => {
console.log("item.name", items.customerName);
if(typeof event.target.value == 'string') {
if (items.customerName!== null)
return items.customerName
.toLowerCase()
.includes(event.target.value.toLowerCase());
} else if(typeof event.target.value === 'number' {
return items.cusomterId === event.target.value);
}
});
this.setState({ rows: newRow, query: event.target.value });
} else {
console.log("Query string is empty ", event.target.value);
let newRow = this.state.custList;
console.log("new row :", newRow);
this.setState({ query: event.target.value, rows: newRow });
}
};
Hi I have added some pure javascipt logic which you can embed in your react component as per your need .
Here you can replace the targetName and targetValue comming from the state values of the component.
Having switch case will allow you to add different logic for different kind of fields.
const data = {
"customerStatusInfoList": [
{
"customerId": 1110000012,
"caseStatus": "pending",
"customerName": "Robert",
"dateOfRequest": "2018-12-15 00:00:00.0"
},
{
"customerId": 1110000004,
"auditorName": "DcbAdmin",
"caseStatus": "pending",
"customerName": "Sam",
"dateOfRequest": "2018-12-14 12:40:04.0"
}
]
}
const targetName = 'customerId';
const targetValue = 1110000004;
callback = (value, index, array) => {
switch (targetName) {
case "customerName":
return value.customerName === targetValue;
case "customerId":
return value.customerId === targetValue;
default:
return value.customerName === targetValue;
}
}
let result = data.customerStatusInfoList.filter(callback, this);