Using HTMLFormElement.reset() with Downshift and react-hook-form - javascript

I'm using DownshiftJS to create an Autocomplete component using the useCombobox hook. It's all going well and testing with react-hook-form. Unfortunately, I've hit a problem where the reset function available within react-hook-form, which fires the HTMLFormElement.reset() method, does not trigger any state/input change within the Downshift component.
This means that when a user selects an item from the list (which triggers an event in the Autocomplete), clicks the reset button and then clicks the input again, the list is filtered to just the previously selected item. This is because the selected item is stored within a selectedItem internal state.
How can I get the reset method to trigger a change within Autocomplete component and clear the selectedItem state?
I've isolated the issue here.

You can use React.useEffect to detect if the user hits the reset button and reset the selected items accordingly in your Autocomplete component
const [inputItems, setInputItems] = useState(options);
const {
inputValue,
...
} = useCombobox({
items: inputItems,
...
});
React.useEffect(() => {
if (!inputValue) {
// user resets value. Reset selected option
setInputItems(options);
}
}, [inputValue, options, setInputItems]);
Live Demo

Related

Next.Js - useState is resetting dropdown values

I am creating a shopping page. I am keeping a JSON to store the product details. I have created the product as a component and using it in the shopping page. For each product I am keeping a drop down to select the quantity (0-5, default value is 0).
Whenever a drop down value change happens, I am making a call back to the parent which is the product page where I am updating the total count. I am using useState hook to update the total. The issue is that when I call the setState, the drop down is not showing the selected value, but the default one (My strong guess is that the drop downs are getting reset. When I remove the setState call, the drop downs work fine).
I am using react-dropdown for implementing drop down.
Parent Component:
const [total,setCartTotal] = useState(0)
const calculateTotalCartValue = (count) => {
setCartTotal(total+count)
}
// Adding the child Component
<Cartitem
parentCallback={calculateTotalCartValue}
/>
Child Component:
const calculateTotal = (event) => {
console.log(event) // This is properly printing the selected drop down details
parentCallback(2) // for testing I am passing value 2
}
// Drop down
<Dropdown
options={options} // I have a list of options
value={defaultOption}
onChange={calculateTotal}
/>

ReactJS - update component (generated from a list) in the same div

It's a basic question but I searched for a guide without success...
I want to have a list of dropdowns and inputs and each dropdown will change the input next to it.
var list = [{ name: "foo1"}, {name: "foo2"}];
return (
{list.map( (name) => {
return (<div>
<dropdown data={someData}
onChange={(ev) => {
if(ev.value == 'clearIt')
<CHANGE THE NEAR INPUT VALUE>
}
}/>
<input value={name.name} />
</div>)
})});
I don't want to use DOM nor ref cause I understood that it's better to avoid it.
Any suggestions?
Or maybe the ref is the only option?
Thanks
So you can achieve this by doing the following steps:
Create a new component and move the dropdown and input to this new component.
Add state to your component by following this example:
https://reactjs.org/docs/state-and-lifecycle.html#adding-local-state-to-a-class
Add an event listener onChange to the dropdown with an event handler which can update the state you created in the first step. (Remember to bind the handler in the constructor.
Add the new component within the div element of this example you gave and pass the relevant data you need to the new component you created.
This should allow you to update only the input next to the dropdown. Also it allows you to have different data for each dropdown you created.

How do I programatically fill input field value with React?

I have a modal with some input fields. I can easily pass the data automatically with the user typing an input, using onChange function in the input field, as
<Input onChange={this.props.store.handleCategoryChange} type="text" />
and .. (Using a mobx store, irellevant though)
#observable categoryValue;
#action handleCategoryChange = (e, data) => {
this.categoryValue = data.value;
e.preventDefault();
};
However, I want to add a function where the user can pre-fill this with information elsewhere in the application. I have the data to pre-fill the input fields with, but I can't figure out how do actually input it programatically, without the user doing it?
I need to invoke the above handleCategoryChange function. But my variable would be equal to data.value .. Which presents a problem! Invoking this function by myself isn't possible, because I won't have the event e nor a value called data.value as I will "just" pass in a variable by itself.
What's the right way to programatically fill an input field automatically in React, using variables elsewhere? I need to invoke the onChange function somehow, but the input values will be different..
Use controlled component for this situation, define a value property of input element like this:
<Input value={variable_name} ....
Whenever you will update that variable, automatically that value will get populated in input element.
Now you can populate some default value by assigning a value to variable_name and user can update that value by onChange function.
As per DOC:
An input form element whose value is controlled by React in this way
is called a "controlled component".
Pass in the value property for input:
<input type="text" value={this.state.value} onChange={(e) => {this.setState({value: e.target.value })}/>
you can use the controlled component and pass the value to it.
<input type="text" value{this.state.value}
onChange={()=> {this.setState({value:e.target.value })}}
Good question. I'm having the same issue, and just found a solution.
The problem is that:
You can't just use the default state of the modal component to set the initial input value, because the modal renders one time within the parent component (starting off invisible), so the default state of the Modal wont keep up with any changes to the 'pre-filled' info in the store that the inputs within the modal require access to.
You can't use the value attribute of the input to reference some redux store prop, since this is needed to reference the onChange function so the user can make changes to that pre-filled info.
And, you can't use the onChange function to set the initial value, because it is required to update the local state with the users changes - not set an initial value. Anyway, this requires the user to click on something, and you want the modal inputs to be pre-populated before the user does anything as soon as the modal opens...
So. What we need is to update these input fields every time the Modal attribute isModalOpen (or whatever you are using) changes.
(ie, pre-populate the fields when the Modal is opened).
Again, note that opening the Modal is not RENDERING the modal, it was already rendered, once, and has sat there being invisible until that isModalOpen attribute changed to true.
The Solution:
Step 1: make a handler function in the Modal component that prefills the inputdata by updating the local state of the Modal component. Mine looks like this :
handlePreFillModalInputsOnOpen = () => {
this.setState(() => ({
orthForm: this.props.matchLexUnit['orthForm'],
orthVar: this.props.matchLexUnit['orthVar'],
oldOrthForm: this.props.matchLexUnit['oldOrthForm'],
oldOrthVar: this.props.matchLexUnit['oldOrthVar'],
source: this.props.matchLexUnit['source'],
namedEntityCheck: this.props.matchLexUnit['namedEntityCheck'],
styleMarkingCheck: this.props.matchLexUnit['styleMarkingCheck'],
artificialCheck: this.props.matchLexUnit['artificialCheck'],
error: ''
}));
};
Step 2: Make that function fire ONLY when the isOpen attribute of the modal changes from false to true.
(This is the meat of your problem I think).
Use the lifecycle method componentDidUpdate. This will execute every time the props of the modal change.
componentDidUpdate(prevProps) {
if (this.props.isModalOpen === true && prevProps.isModalOpen === false) {
this.handlePreFillModalInputsOnOpen();
}
}
Watch out
make sure that you have a conditional in componentDidUpdate, otherwise you can run into infinite-loop/performance issues
if you have the possibility of null values icoming in as the prefilled input info, make a null-check so that they will not be passed into the local state.
Hope this helps :)
How to Programmatically Prefill, Fill or Update input fields value in React or useState Hooks?
Firstly - Get and define the data from database
const **yourData** = isDataFromDatabase;
or if the data is stored in Redux, then...
const **yourData** = useSelector(isDataFromDatabase);
Secondly - append it as the default value of a useState hook
const [isDataValue, setIsDataValue] = useState(**yourData**);
Thirdly - create a function to watch and Update the changes made by the user to your data value and set it to the useState hook created above
/** handles Your Data Value */
const handleDataValue = (text) => {
setIsDataValue(text);
};
Lastly - in your input tag, use the useState State as the "Value" parameter so it can be updated with the onChange function
<input
className="css"
id="myDataInput"
type="text"
value={isDataValue}
placeholder={isDataValue}
onChange={(e) => handleDataValue(e.target.value)}
/>
Now when you load the component, the prefilled value will be shown and can be updated in the HTML Input field.
That's All.

Prop callback not returning?

I'm using a Material UI Table with ReactJS and would like to change a state variable whenever a row is selected/deselected. Table has onRowSelection which is triggered each time a row is selected:
<Table
height='300px'
fixedHeader={true}
multiSelectable={true}
showRowHover={true}
onRowSelection={this.handleRowSelection.bind(this)}
>
I have the following function passed to the onRowSelection prop:
handleRowSelection(selectedRows) {
let contactsImport = [];
if (selectedRows === 'all') {
contactsImport = this.state.contacts.new;
} else if (selectedRows !== 'none') {
selectedRows.forEach((index) => {
contactsImport.push(this.state.contacts.new[index]);
});
}
this.setState({
contactsImport:contactsImport
});
}
This sets the state correctly, however it prevents the Table Row selection from functioning correctly. If I click a row, the checkbox doesn't check -- it seems like it is checking and then instantly unchecking itself because I get the 'ripple' animation but no checkmark.
Removing the call to setState fixes the issue, so is it possible setState is preventing the callback from returning correctly? Or might this be a bug with Material UI?
You'll have to manage the selected property of a single row component from the state if you wish to control it programmatically. selected property is false by default, so when rerendering happens by setState it'll be reset back to false

Change Select (drop down) selection on state change within react component

I have a dropdown I want to be pre-selected when the data is available. However there appears to be no real chance for that?
Since I am waiting for a change in state for a particular value using that value as the value= causes the selections to be unselectable, while using it as a defaultValue= causes the UI to not recognize the value unless a change to the element has been made meaning if the user decides to go with the default choice it wouldn't be passed up the to the API I am trying to pass it up to.
Is there a way to dynamically change a select box after the dom is ready after the components mounted and when a state is changed?
It's a bit difficult without seeing the code, but have you tried setting the value into the React component's state and rendering that instead? You can also read the state's value instead of the DropDown's.
getInitialState: function () {
return {
dropDownSelection: "some default value"
};
},
handleSelectionChanged: function (e) {
this.setState({
dropDownSelection: e.target.value
});
},
render: function () {
return (
//...
<select className="form-control" value={this.state.dropDownSelection} onChange={this.handleSelectionChanged}>
//...
</select>
);
}

Categories

Resources