React / React-Select / Firebase : Refreshing React-Select on addition of new entry - reactjs

I have a select:
<Select classNamePrefix="select" ref={myRef} menuPortalTarget={document.body} styles={style} placeholder="Select Foods" name="Foods" value={inputField.foods} options={options} onChange={event => handleInputChange2(index, event)} className="select selectNarrow" />
const handleInputChange2 = (index, event) => {
const values = [...inputFields];
values[index] = event;
setInputFields(values);
console.log(event);
};
Whereby {options} are built from a collection. On this same page I can add to this collection - after adding a new item and then opening the select it is not immediately visible until after I have chosen an already existing item. How do I get the React-Select to refresh the list each time I open it (rather than an onChange)

I feel like we're missing some code to properly answer your question. How did you add a 'new item'? While you added to the collection, did you also update your options array?
Displayed options are controlled by the options prop. If you add a new option to this array, React-Select will rerender and the new option would be available.

Related

How to select defaultValue with react-select

I have a ReactJS application. I have the Select component of react-select below which is loaded with information obtained from a database. From this information there is a default value that must be selected every time the page is loaded. So far so good. My application works with the following code
<Select
name="planting_system_id"
id="planting_system_id"
options={plantingSystemsList}
value={plantingSystemsList.find(e => e.label === planting_description)}
placeholder="Select..."
isDisabled={apiData ? false : true}
onChange={(event) => this.onChangeInputSelected("planting_system_id", event)}
/>
However, with this code I cannot select any other option that is available in the Select list.
Searching a little more the Select component has a parameter called defaultValue, where from the list of objects that will be available in my select I pass the option that I want to be displayed. For example list [3]. However, as it is data that comes from the database, the position of an object's list will change and I need to obtain this position dynamically but I'm not able to do it that way
<Select
name="planting_system_id"
id="planting_system_id"
options={plantingSystemsList}
defaultValue={plantingSystemsList[this.getIndexOf(plantingSystemsList, planting_description)]}
placeholder="Select..."
isDisabled={apiData ? false : true}
onChange={(event) => this.onChangeInputSelected("planting_system_id", event)}
/>
getIndexOf(list, description) {
const obj = list.find(e => e.label === description)
return list.indexOf(obj);
}
However, if I do it this way it works
<Select
name="planting_system_id"
id="planting_system_id"
options={plantingSystemsList}
defaultValue={plantingSystemsList[3]}
placeholder="Select..."
isDisabled={apiData ? false : true}
onChange={(event) => this.onChangeInputSelected("planting_system_id", event)}
/>

How to set dropdown selection to localStorage?

I have a dropdown component where I am trying to set a localStorage value to the option that is selected from the dropdown.
const [userLanguage, setUserLanguage] = useState('en');
useEffect(() => {
localStorage.setItem("userLanguage", userLanguage ? userLanguage : '')
}, [userLanguage]);
return (
<select>
<option onClick={?}>one</option>
<option onClick={?}>two</option>
</select>
);
I am really confused on how to handle the onClick event that would set the selected option the the localStorage.
I have been able to find solutions that are somewhat related, but not that show examples for React, and specifically using hooks.
Any help would really be appreciated.
I would bind to the onChange event listener instead. The click event of option elements in single-select select elements is notoriously fragile. In your case, change your code to something like:
const [userLanguage, setUserLanguage] = useState('en');
useEffect(() => {
localStorage.setItem("userLanguage", userLanguage ? userLanguage : '')
}, [userLanguage]);
return (
<select onChange={(e) => setUserLanguage(e.target.value)}>
<option value="one">one</option>
<option value="two">two</option>
</select>
);
I added value attributes to your options only in an abundance of caution; by default the value of the select will gain the text of the option if the value is not explicitly set.
I should point out that older questions have pointed out the fragility of the click event on option elements. In particular, the answers to the question getting an onclick event to a select option using js by Vad.Gut explain the situation well.

How to delete Material UI chip element based on Material UI's github label picker example

I was playing with Material UI autocomplete component's github label picker example and modified it as per sandbox below:
https://codesandbox.io/s/material-demo-hwi3l?file=/demo.js
The Autocomplete works fine. When I select company names from the list they show up as chip elements after closing and when I deselect them individually, they get hidden as well. However, I am unable to figure out how to delete individual elements by clicking on chip's close button. I am unable to figure out what exactly to put in the chip's onDelete prop?
{
value.map((company, index) => (
<Chip
label={company.name}
onDelete={(event, newValue) => {
//setPendingValue(company);
}}
color="primary"
className={classes.selectedCompanies}
/>
))
}
Since the Chip as per sandbox is inside the value array, I am not sure how I could delete something from inside it while looping through it. Any help would be greatly appreciated.
One way to delete from an array is to filter where each iterated item is not the deletable item. Doing so returns a new array that omits the deletable item. So in your example:
The delete-handler:
const handleDelete = name => {
const newValue = value.filter(company => company.name !== name);
setValue(newValue);
};
The chip element:
{value.map((company) => (
<Chip
key={company.name}
label={company.name}
onDelete={() => handleDelete(company.name)}
The codesandbox with the solution
Note, in React, you should include the iterated key in each list item.

Testing Material-UI Textfield select component with jest

I am trying to write a test for a simple Material-UI Textfield select component. The test should show that selecting an options triggers the corresponding event.
Here ist the component
<TextField
inputProps ={{"data-testid": "testId"}}
id="TextFieldId"
aria-label={"TextFieldAriaLabel"}
select
label="Files"
value={limit}
onChange={handleLimitChange}
SelectProps={{
native: true,
}}
variant="outlined"
>
{[{value: 5, label: "5"}, {value: 10, label: "10"}, {value: 15, label: "15"}].map(option => (
<option key={option.value} value={option.value}>
{option.label}
</option>
))}
</TextField>
Selecting the value "10" triggers the call of a function with 10 as an input parameter.
I use jest to write the test. I want to click on the select component to open the dropdown. Then I want to click on one of the options. To prove that the event was triggered, I check if the related function is called with the right argument.
It sound very simple, but I ran into many issues. Most of the issues were related to not finding the elements, since material ui nests different html components. My so far best approach looks like this.
testObject.renderResult.getByTestId('testId').click();
testObject.rerender();
jest.runAllTimers();
const dropdown = testObject.renderResult.getByTestId('testId');
within(dropdown).getByText('10').click();
testObject.rerender();
jest.runAllTimers();
expect(mostRecentImports).toHaveBeenCalledWith(10)
Jest finds the elements, but the test fails. The component remains in its default, showing the value 5 (not 10). What am I doing wrong?
I also had the same problem in my app. Finally I solved it using this solution I found here: https://github.com/testing-library/react-testing-library/issues/322#issuecomment-581650108
Write a simple function that opens the select menu and selects the wanted option:
const selectMaterialUiSelectOption = (element, optionText) => {
// The the button that opens the dropdown, which is a sibling of the input
const selectButton = element.parentNode.querySelector('[role=button]');
// Open the select dropdown
UserEvent.click(selectButton);
// Get the dropdown element. We don't use getByRole() because it includes <select>s too.
const listbox = document.body.querySelector('ul[role=listbox]');
// Click the list item
const listItem = within(listbox).getByText(optionText);
UserEvent.click(listItem);
};
[... in your test]
selectMaterialUISelectOption(getByTestId('testId'), "10")
You can utilize the findAByDisplayValue method of #testing-library/react
https://testing-library.com/docs/dom-testing-library/api-queries#bydisplayvalue

How to get text of selected <Dropdown/> option in ReactJS?

I am working on a ReactJS application and I am trying to get the text of a selected option in a dropdown (Semantic UI component);
exposedCampaignOnChange = (e, {value}) => {
this.props.campaignExposedSelected(value);
};
<Dropdown
placeholder='Campaign Exposed To'
fluid
search
selection
multiple
options={this.state.campaigns}
onChange={this.exposedCampaignOnChange}
/>
The above code returns the value. this.state.campaigns is made up of an array of objects with value and text properties. In addition to the value, I also want to get the textvalue of the selected options.
Appreciate any guidance on the matter.
You can use synthetic event's target property to get the text like:
exposedCampaignOnChange = (e, {value}) => {
e.persist();
console.log(e.target.textContent);
this.props.campaignExposedSelected(value);
};
<Dropdown
placeholder='Campaign Exposed To'
fluid
search
selection
multiple
options={this.state.campaigns}
onChange={this.exposedCampaignOnChange}
/>
Semantic ui react Dropdown onChange event takes two arguments -
onChange(event: SyntheticEvent, data: object). You don't need to pass them explicitly while calling the function.
exposedCampaignOnChange = (e, value) => {
e.persist();
this.props.campaignExposedSelected(value);
};
data/value should have selected option text like in semantic UI
function getSelectedTextValue() {
alert( $('.ui.dropdown').dropdown('get text') + " : " + $('.ui.dropdown').dropdown('get value') );
}

Resources