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

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>}

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

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

Material UI Autocomplete component not showing values from react state

I am trying to get value from the state for materialUI's autocomplete component.
I am facing the following problem : -
Autocomplte working fine for selecting the value and with onChange function it saving it into the state too.
But when I refresh my page/ re-render it is not showing value on the textfeild(from saved state):
<Autocomplete
name={"TideLocation"}
disabled={p.disabled}
options={data_source}
getOptionLabel={option => option.text}
inputValue={this.state.tidelocation_searchtext}
onChange={_this.handleUpdateTideLocationField}
onNewRequest={_this.handleChangeTideLocation}
onBlur={_this.handleBlurTideLocationField}
onUpdateInput={_this.handleUpdateTideLocationField}
renderInput={(params) => (
<TextField className="autoCompleteTxt"{...params} label="Location" />
)}
/>
I tried with the debugger and found its getting value in this.state.tidelocation_searchtext
but failed to set it with params.
Thanks in advance !!
Ps: I tried with defaultValue and search text nothing worked for me
following is my ONchangeFunction
handleUpdateTideLocationField = (str, value) => {
debugger
this.setState({tidelocation_searchtext: value.text});
}
after selecting a value,following value saved in sate :
tidelocation_searchtext: "Auckland"
So I found the solution all by myself by doing research and several hit and try, following is the solution of my problem:
<Autocomplete
name={"TideLocation"}
disabled={p.disabled}
options={data_source.map(option=>option.text)}
defaultValue={this.state.tidelocation_searchtext}
onChange={_this.handleUpdateTideLocationField}
onNewRequest={_this.handleChangeTideLocation}
onBlur={_this.handleBlurTideLocationField}
onUpdateInput={_this.handleUpdateTideLocationField}
renderInput={(params) => (
<TextField className="autoCompleteTxt"{...params} label="Location" />
)}
/>
Basically I was doing the following things wrong :
1.There is no need of using input inputValue={this.state.tidelocation_searchtext}& getOptionLabel={option => option.text}
2.as my data is in object form I have to convert it into a string so default value can match this from the state value
options={data_source.map(option=>option.text)}
Thank you all for your valuable support and solution !!
Removing inputValue has worked for me, even when passing object as options.
Using: "#material-ui/core": "^4.12.3"
If data/state not saved externally f.e. in local storage then it will be lost on page refresh, always. It's normal - like RAM memory without power - it (page/app state) only exists in memory !!
It's like using using cookie to keep you logged in.
If you really need such functionality then use f.e. redux-persist
You are right, if object type options are passed, material-ui's AutoComplete component does not seem to reflect the value when mounted. (Perhaps a bug?)
I was able to get around this by passing the proper characters to inputValue.
#RebelCoder
Maybe you should have initialized tidelocation_searchtext.
For me it was coming from the dropdown z-index which was hidden by another css behaviour.
I added this in a css file :
/* Dropdown MUI Component Autocomplete*/
div[role="presentation"].MuiAutocomplete-popper {
z-index: 1000000;
}
And it appeared finally. A bit hacky, but I think it was caused by another library that had something of that kind.
Note that I added several css elements to the selector, because just using the class wasn't enough.

defaultValue doesn't change... dropdown react

I have a dropdown that get it's option from a fetch, and when I select and option another fetch is requested to save that into the DB, and then it return that into the state so the selected value is now in the state.
BUT!
my dropdown doesn't update the selected value, even though it updates correctly in the DB.
the dropdown:
<Form.Field className="dropdown">
<label>{answer.answerText}</label>
<Dropdown
key={ answer.name }
value={answer.value <!--THIS IS UPDATED AFTER SELECTION, BUT DOESN'T SHOW -->}
style={{paddingLeft: pad}}
onChange={(e) => this.blurHandler(e.target.textContent,answer)}
name={ answer.name }
disabled={answer.settings.disabled}
options={answer.dropdownOptions}
/>
</Form.Field>
The method that gets called.
blurHandler(e,answer) {
var answerValue = e;
var projectId = this.props.projectId;
this.props.updateAnswer('/api/update-answer',
answer.questionId,
projectId,
answer._id,
answerValue,
answer.settings.answerType
);
}
what updateAnswer does is just a fetch to save the value to the projects answer in the DB.
Your question title says defaultValue but you do not use that prop anywhere in your Dropdown component. When you are defining a value in your Dropdown component, or on any SUIR component, that means you must control all other input interactions yourself and you lose any of the out of the box state controls that come with SUIR components. There are definitely cases where you might want this.
I'd recommend changing your value prop to a defaultValue prop on your Dropdown and that should give you what you're expecting. The Dropdown will only initialize itself with that value but it will change in the UI the way you are expecting.

Categories

Resources