Multiple Row Edit Functionality in React - javascript

I am trying to implement an edit row functionality in a react grid. I have attached 2 links. Link 1 is the GIF which shows the functionality that I have implemented using the below code.(For privacy reasons I cannot publish the actual code)
Link 2 is the functionality I am trying to achieve! How shall I do that?
return (
<>
<p>Sample Row Field</p>
{editId === Id && editRow === true ? (
<select options={options} handleChange={handleChange} />
) : (
existingRowValue
)}
</>
);
Link 1 - The Functionality I have (Individual Row)
https://i.stack.imgur.com/JJEL5.gif
Link 2 - The Functionality I want (Multiple Rows)
https://i.stack.imgur.com/w7ppb.gif

I'd assume editId is a local state variable, same for editRow
So what you'd need to do is change editId into a state called editIds as an array (because you want to edit multiple rows, not just one), and replace editId === Id with editIds.includes(Id)
onEditClick: should add the rowId into this state, like setEditIds(...editIds, rowId)
onSave/CancelClick: should remove the id from the state, like: setEditIds(editIds.filter((id) => id !== rowId))

I think following code sample will give you an idea of how you can achieve this when you move your editId to a local component state.
https://codesandbox.io/embed/hardcore-sid-pythne?fontsize=14&hidenavigation=1&theme=dark

Related

changing selected state of fetched item from API

I have an API that returns me arrays. I implemented the code to search 3 of them like this:
{response !== undefined &&
search !== "" &&
response.InsuranceServiceList.filter((insurance) =>
insurance.Name.replace(/ي/g, "ی", /ا/, "آ").includes(search)
)
.slice(0, 3)
.map((filtered, i) => (
<EachInsurance
filtered={filtered}
key={i}
styles={scss}
DatePresence={DatePresence}
IdInsurance={IdInsurance}
TimePresence={TimePresence}
/>
))}
whenever user types something in search box, 3 of these matching arrays will get rendered.
but I have two problems with selecting them.
this is each insurance component:
<Container
className={styles.eachInsurance}
style={{
borderRight: `${selectInsurance ? "20px" : "1px"} solid #fcc4de`,
}}
>
<div
onClick={() => {
setSelectInsurance((prev) => !prev);
setCount(0);
}}
>
<p className={styles.NameService}>{filtered.Name.replace(/ي/g, "ی")}</p>
</div>
</Container>
whenever user clicks on element. it will have pinkish border with the width of 20px.
the problem is, when I type another thing to search another item. it shows that Item selected.
just like the clicked div is still there but the content inside of it has changed.
how can I prevent this problem?
I thought it would render a new div per each array. but it wasn't.
the second problem is search itself. if you delete what you've write completely (emptying search bar). everything you have selected before will get removed and you will need to reselect it again.
I want to prevent this too.
You need to pass the id from your back end to your front end. then add a border based on the ids you pass to the selectInsurance, in that way you will know if the element change the border will be gone.
I think for your second problem you can add a new state that will reserve the whole object of the insurance and you first render from that array so every time you re-render your search array your selected insurance array will stay the same so they will remain in your page

Pass Row ID to a custom component in MUI Datagrid Pro

I am trying to add an indeterminate state to row checkboxes based on selection status of other checkboxes inside a detail panel. To do this I am creating a custom checkbox component and doing some logic to see if indeterminate should be true, the only problem is the checkbox needs access to the row id it is associated with to do that check. Thus far I've found nothing to pass anything other than the given CheckboxProps given by MUI, which contains no row information. There is something called componentsProps where I can pass other props to a component, but I've yet to find a way to pass the particular row id to its associated checkbox. Does anyone know of a solution to this?
.
.
.
const customCheckbox = (props: CheckboxProps) => {
return <Checkbox {...props} indeterminate={someArray.includes(theRowIdThisCheckboxIsUsedIn)} />
};
<DataGridPro
{...data}
components={{
BaseCheckbox: customCheckbox,
}}
/>
hi when you use custom checkbox component you cant use onSelectionModelChange to give you rows id you must write their logic too

Why is my JSX rendering a <tr> when it shouldn't?

I have a table that fills its rows and <td> tags on its own. It does this fine as shown below:
The table is generated by mapping through an array.
{objInnerValues[shopIndex].map((thing, outerIndex) => (
// Ternary operator to stop creating rows from element 0
(outerIndex === 0) ? console.log("outerIndex WAS 0") : (outerIndex %2 === 0) ?
Object.values(thing).map((innerThing, innerIndex) => (
<>
{/* Tooltip popup for item blurb */}
<HtmlTooltip title={
//a tooltip component, from MUI. Gets a string to display
}
>
{/* Table rows for each record */}
<TableRow
//style definitions, then an id for the row...
id = {"rowID-"+thing[0][0]}
>
{AR_RowRefs.push("rowID-"+thing[0][0])}
{/* Indidivual td elements to display each item in a row*/}
<SuperTD NoHoverTD>
{//Items name}
</SuperTD>
<SuperTD NoHoverSmallTxtTD>
{//category the item belongs to}
<Button>
//a visibility button, part of what I'm trying to work on
</Button>
</SuperTD>
<SuperTD NoHoverSmallTxtTD>
{
//Get weight of item from array and format it
}
</SuperTD>
<SuperTD NoHoverSmallTxtTD>
{
//Get price from array and format it
}
</SuperTD>
{/* Checkbox for if item is available */}
<SuperTD>
<input type="checkbox" defaultChecked={innerThing[6]}/>
</SuperTD>
{/* Checkbox for if item is limited */}
<SuperTD>
<input type="checkbox" defaultChecked={innerThing[7]}/>
</SuperTD>
</TableRow>
</HtmlTooltip>
</>
Above my return block I have an array I want to use to store the ID of each table row that is generated. I have a function (fired from an onClick of each visibility button).
I wrote this in my return block, inside the array map:
{AR_RowRefs.push("rowID-"+thing[0][0])}
However, when I save this and it renders, it creates an extra column of data:
I thought that an extra <td> would only render if I put tags around it. This is just a JSX snippet so is there any particular reason its creating its own <td>? Can I still have this snippet push ids to an array without rendering an extra element?
I thought that an extra <td> would only render if I put tags around it. This is just a JSX snippet so is there any particular reason its creating its own <td>?
The browser is attempting to recover from your error of putting a number (which gets converted to a string) as a child of a tr.
Can I still have this snippet push ids to an array without rendering an extra element?
The quick and dirty approach (which I haven't tested) would be to change the expression so it doesn't evaluate as a number.
{void AR_RowRefs.push("rowID-"+thing[0][0])}
The sensible approach would be to split your data manipulation logic and your display logic.
Object.values(thing).map((innerThing, innerIndex) => {
AR_RowRefs.push("rowID-"+thing[0][0]);
return <>
...
</>;
};

Populating a button array with dynamic button text only work if one button

I learn React and JavaScript and now I have this problem
Here's a Codesandbox
What happens is like this:
In the Codesandbox at FileEditor.jsx: I mock it like this:
// Mocking the tag list just to test it
const tagMock = ['11111']; // THIS WORKS WITH ONLY ONE ITEM
// Mocking the tag list just to test it
//const tagMock = ["11111", "22222", "33333"]; // THIS DOES NOT WORK WITH MULTIPLE ITEMS
The tagMock that works in the first one with only one array value.
The tagMock that does not work is the one with 3 values.
(when you star sandbox the tagMock with only one array value is use, please change to tagMock with 3 array values to see the error)
If you look further down in FileEditor.jsx you see where tagMock is use like this:
{tagMock.map((tag) => (
<div className="tagInput">
<button
className="btn btn-warning btn-sm"
disabled={false}
key={tag}
type="button"
// onClick={() => remove(skill)}
>
<TagName tag={tag} />
</button>
</div>
))}
Every button created in this map loop have it's own <TagName tag={tag} />
The TagName is a component that is connected to the Redux Store and there
it selected (using reselect), the store tags and then return the tag name only.
The button name text is by so dynamically set like this:
In the image above, the "name2" button text is set" .
The problem is that this does not work if more then 1 button like this:
//const tagMock = ["11111", "22222", "33333"]; // THIS DOES NOT WORK WITH MULTIPLE ITEMS
The error I get is the name is not defend in the tagName.jsx file.
Why does this happen? I understand it's some form of component duplications issue that the map loop can't create the tagName Component as it should, but I can't figure it out.
ok I solved it,
WRONG:
state.global.tags.find(tag => tag.id > ownProps.tag);
RIGHT:
state.global.tags.find(tag => tag.id === ownProps.tag);

transfer data from components in react

I have 2 components. In one component I render map of table rows =>
this is place, where tDs.map is rendered
this.state.dataOld.map(it =>(
<>
<tr onClick={()=>{it.selected_=!it.selected_;this.forceUpdate()}} value={it} key={it.id}>
{this.tDs.map(fnc => fnc(it,this.hide,this))}
</tr>
</>))
dataOld is array of 2 objects
tDs is array like
function(it,hide,a){return !hide.id ? <td>{it.id}</td> : null},
function(it,hide,a){return !hide.category3 ? <td>{it.category3}</td> : null},
function(it,hide,a){return !hide.edit ? <td>
<Button onClick={() => a.setState({edit:!a.state.edit,element:it})}>
</Button>
</td> : null}
the thing i interested in is a.setState({edit:!a.state.edit,element:it})}
I render another component inside of first
<Edit isOpen={this.state.edit} editBack={this.editBack} th={this} element={this.state.element}/>
I transfer my this.state.element to Edit, inside Edit component I'm doing something like this:
elem = {};
componentDidUpdate(){
this.elem = this.props.element
console.log(this.elem)
}
...
<Input onChange={ e => {this.elem.packagingType = e.target.value; console.log(e.target.value)} } ... />
so, the problem is: I transfer this.state.element to Edit component, then in Edit component I make new variable elem and make it be equal to this.props.elem I transferred
the problem starting here, the first, (original, natural) this.state.element is changing, but I dont change dataOld, I dont change any element that has been rendered, I really dont undestand, how it works here.
My guess was about this place
<Edit isOpen={this.state.edit} editBack={this.editBack} th={this} element={this.state.element}/>
I think that when I'm doing element={this.state.element} I somehow connect this 2 things and when I change element inside of Edit, the natural this.state.element is changing too.
Codesandbox example:
https://codesandbox.io/embed/7wk8689op6?fontsize=14
when you press a button near every row, then change data and press cancel, the original data is changing, I dont understand why
I think I understood the question.
When I put an object to the Edit component, and then change an object inside of component, the original object is changing too because I didn't make a new version of this object, but I gave to Edit a link to this object.

Categories

Resources