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

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 <>
...
</>;
};

Related

Why is onKeyDown not working in React.js?

So I'm trying to build a sudoku app with React and I've separated everything into 4 components. It basically goes like this App -> Board -> Row -> Cell where the cell is the smallest unit. Now every cell is a <div> tag for which I used tabIndex="0" to navigate with the keys and enter values in the cell.
I render all my cells by using .map() to go through an array of data. Initially, I didn't specify a key property for every element of my array and everything was working fine. Every cell I had was working perfectly whenever I pressed a key. However, as soon as I specify a key property of the cell it seems like my handler function for onKeyDown isn't working at all. I'm completely baffled, if anyone has any insights I would appreciate it.
Just to specify, I'm using uuid() to generate a unique key but every other method I've tried doesn't work as well. It seems to be some relationship between the key property and the onKeyDown event.
This is what I return as a cell: <div id={props.id} tabIndex="0" className={className} onKeyDown={(e)=> {handleKeyDown(e)}}> {value} </div>
And this is how I map through a row to render cells: const cells = rowContent.map((cell, cellIndex) => { return <Cell key={uuid()} solution={props.solution} activeSquare={props.activeSquare} value={cell === "." ? null : cell} id={startNum+cellIndex+1} selected={selected} /> })

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

Multiple Row Edit Functionality in React

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

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);

Material-ui autocomplete not changing its value based on value prop

I had to generate multiple rows, where each row has a dropdown (Autocomplete) that was searchable through API, and other fields too. All is working perfectly, except when I delete a row from the middle somewhere, just the autocomplete component displays the same value as earlier, however, I get correct data in my state.
So if I had an array with the following items.
And now if I delete Row 2 which is Brite – (500 g), I get this display on the screen.
However, all other items of the rows are correctly displayed, so I'm assuming there is nothing wrong with my logic of handling the array, but due to autocomplete showing wrong value(however it holds the correct object passed into its value prop), it seems that all items have suddenly changed their Qty and prices, and the last item was deleted (instead of 2nd one).
If I sum up the problem, although the component was re-rendered based on new array in the state, that was obtained after deleting a row, autocomplete still displays its previous value which is nowhere is the data now.
<Autocomplete
options={skuItems}
getOptionLabel={option => option.name}
renderInput={params => (
<TextField {...params} label="SKU" variant="outlined" />
)}
value={selectedSkuItems[index]}
onChange={(e, val) => orderItemHandleChange(e, val, index)}
onInputChange={skuSearch}
/> (edited)
The issue resides where you have the map function. The key must be something unique. If it involves the index, is bad. Because you remove items by index and then another item takes that indexes place, and a proper rewrite of the DOM is failing.
As seen bellow:
collection.map((value, index) => { <div key={something unique}> </div>}

Categories

Resources