How to reference an object name in React with the key? - reactjs

So I'm coding a budget app right now, and I'm using a drop-down menu in a certain part of the app.
<Dropdown>
<Dropdown.Button color="secondary">{selectedValue}</Dropdown.Button>
<Dropdown.Menu ref={budgetIDRef} selectionMode="single" selectedKeys={selected} onSelectionChange={setSelected} aria-label="Multiple selection actions">
{budgets.map(budget => (
<Dropdown.Item key={budget.id}>{budget.name}</Dropdown.Item>
))}
</Dropdown.Menu>
</Dropdown>
The .map() here serves to introduce a dropdown selection option for each budget item key, using the name to display the name. This all works, however the {selectedValue} for the Button displays the key, not the name (as it's derived from {selected} which assigns the selected key). So my question is, how can I extract the name of my object using the key?
I tried using an if statement within .map(), but it didn't work properly and when it did work it was displaying all the names of my objects in local storage one after the other.

One way to do it would be changing the the function that you call on onSelectionChange to a custom function that would receive the value of key (I'm assuming this is the only value that you get to work with since I don't know wich lib you're using).
This custom function would use this key value, wich is the budget.id, to filter the bugdets array and update the selectedValue state with the name and the id of the selected budget. Then you would call selectedValue.name inside the <Dropdown.Button>.
The code could be something like this:
const [selectedValue, setSelected] = useState({});
const updateSelectedValue = (budgetId) => {
const selectedBuget = budgets.filter(budget => budget.id === budgetId);
setSelected({
name: selectedBuget.name,
id: selectedBuget.id
});
}
return (
<Dropdown>
<Dropdown.Button color="secondary">{selectedValue.name}</Dropdown.Button>
<Dropdown.Menu ref={budgetIDRef} selectionMode="single" selectedKeys={selected} onSelectionChange={updateSelectedValue} aria-label="Multiple selection actions">
{budgets.map(budget => (
<Dropdown.Item key={budget.id}>{budget.name}</Dropdown.Item>
))}
</Dropdown.Menu>
</Dropdown>
);
See, the code I provided is not optimized and don't do validity checks. So if you decide on moving forward with my suggestion, add the necessary validations to see if the objects and properties you're trying to access are not undefined.

One option is to find the selected budget based on the selected value:
const selectedBudget = budgets.find(budget => budget.id === selectedValue);
return (
<Dropdown>
<Dropdown.Button color="secondary">{selectedBudget?.name}</Dropdown.Button>
<Dropdown.Menu ref={budgetIDRef} selectionMode="single" selectedKeys={selected} onSelectionChange={setSelected} aria-label="Multiple selection actions">
{budgets.map(budget => (
<Dropdown.Item key={budget.id}>{budget.name}</Dropdown.Item>
))}
</Dropdown.Menu>
</Dropdown>
)
You may want to wrap this calculation in a useMemo so it only runs when the selected budget changes. For example:
const selectedBudget = useMemo(() => {
return budgets.find(budget => budget.id === selectedValue)
}, [budgets, selectedValue]);

Related

React DropdownButton

I would like to use DropdownButton to change the language on my website. I managed with Select and changing the language works. Unfortunately there is a problem with img placement in Select so I wanted to do it with DropdownButton. And here I have a problem with getting the value from Dropdown.Item.
I get the message: Uncaught TypeError: evt is null. What should I do in such a situation
const DropdownLanguage = () => {
const { i18n } = useTranslation();
const [language, setLanguage] = useState("pl");
const handleLangChange = (evt) => {
const lang = evt.target.value;
console.log(lang);
setLanguage(lang);
i18n.changeLanguage(lang);
};
return (
<>
<DropdownButton
id="dropdown-basic-button"
title="Dropdown button"
value={language}
onSelect={handleLangChange}
>
<Dropdown.Item value="pl">
<img className="flag" src={PL} />
PL
</Dropdown.Item>
<Dropdown.Item value="en">
<img className="flag" src={UK} />
EN
</Dropdown.Item>
</DropdownButton>
</>
);
}
I checked the documentation in React Bootstrap
I was reading the react bootstrap documentation and I see that maybe it's the problem.
The select callback sends you 2 parameters, the first is the eventKey and the second is the event.
OnSelect function description:
A callback fired when a menu item is selected.
(eventKey: any, event: Object) => any
Try changing your handleChange funciton:
const handleLangChange = (evtKey, evt) => {
const lang = evt.target.value;
console.log(lang);
setLanguage(lang);
i18n.changeLanguage(lang);
};
Good luck!!
You are missing the selectKey attribute on your Dropdown.Item components. From the documentation for Dropdown.Item:
Name
Type
Default
Description
...
...
...
...
eventKey
string | number
Value passed to the onSelect handler, useful for identifying the selected menu item.
and note the documentation on Dropdown.onEvent, where the first argument name is eventKey:
Name
Type
Default
Description
...
...
...
...
onSelect
function
A callback fired when a menu item is selected. (eventKey: any, event: Object) => any
Note that DropdownButton is a convenience component, it wraps a Dropdown component with nested Dropdown.Toggle and Dropdown.Menu components, with any Dropdown.Item components used to populate the Dropdown.Menu children.
You may have mistakenly used a value attribute instead of eventKey here. Replacing value with eventKey works, the value of this property is passed directly to your handler as the first argument:
const DropdownLanguage = () => {
const { i18n } = useTranslation();
const [language, setLanguage] = useState("pl");
const handleLangChange = (lang) => {
console.log(lang);
setLanguage(lang);
i18n.changeLanguage(lang);
};
return (
<>
<DropdownButton
id="dropdown-basic-button"
title="Dropdown button"
onSelect={handleLangChange}
>
<Dropdown.Item eventKey="pl" active={language === 'pl'}>
<img className="flag" src={PL} />
PL
</Dropdown.Item>
<Dropdown.Item eventKey="en" active={language === 'en'}>
<img className="flag" src={UK} />
EN
</Dropdown.Item>
</DropdownButton>
</>
);
}
Note that DropdownButton has no value property, either. Instead, to pick a specific menu option as the selected item, set the active property of the selected Dropdown.Item to true.
Here is an online sandbox to demonstrate:
You could otherwise access the event object itself (and event.target) if you give your handleLangChange() handler a second argument to receive it, or you can use arguments[1]. You'll have to use a DOM method in that case, like event.target.getAttribute("value"), to access any attributes. But that's really overkill here.
According to the docs, DropdownButton doesn't have prop onSelect. onSelect is only existed in Dropdown, so you can change from DropdownButton to Dropdown.

Unable to get the selected value from the React fluent UI dropdown

I am trying to do something extremely simple, something that in JS I can do in a fraction of a second, but that for some reason is not working in the React
I am trying to change the dropdown value and capture the target element in the event, so I could assign it to the state with a certain index (idx)
However, no matter what I do, the event target comes up as undefined. I did already try to apply bind but in that case the event wouldn't fire at all
Please help, thank you in advance
Here is the dropdown
<Dropdown onChange={event => this.handleRoleChange(event, idx)}
placeholder="Staff Member Roles"
options={options}
styles={dropdownStyles}
/>
Here is handleRoleChange event
private handleRoleChange(event, idx) {
alert(idx);
alert(event.target.value);
}
Found an answer
<Dropdown onChange={this.handleRoleChange}
placeholder="Staff Member Roles"
options={options}
styles={dropdownStyles}
id={idx.toString()}
/>
public handleRoleChange = (event, option, index) => {
let idx = parseInt(event.target.id);
alert(idx);
alert(option.key);
}

React Semantic-UI: Dropdown.Menu / Problem

I am trying to build a language selector dropdown showing the flag symbols of the languages - in the menu when it is not opened as well as in the opened menu. I would not like to show any texts.
I am using inline style to style my components in my app, therefore I would like to define the menu style as well via style={myStyle}, else the opening dropdown menu won't be affected by the style in the component.
<Dropdown
value={value}
selection
compact
style={myStyle}
onChange={getLanguage} // could be removed
options={countryOptions}
>
<Dropdown.Menu style={myStyle} >
{countryOptions.map( country => {
return (
<Dropdown.Item key={country.key} value={country.value} flag={country.flag} onClick={getLanguage} />
)
})}
</Dropdown.Menu>
</Dropdown>
I use the code above and it works for me, the only problem is, that I get the error message, that I cannot use <Dropdown.Items> and options in the component at the same time:
Warning: Failed prop type: Prop `selection` in `Dropdown` conflicts with props: `children`. They cannot be defined together, choose one or the other.
My problem without using the options is, that I don't know how to set the active item in the component. Without the options it seems, it is not possible to display the current value inside this component.
What am I missing or doing wrong? Is it possible at all to set the current value without using options? Can I ignore the error message?
Thank you a lot for your help.
I think what you're asking for is to set active prop on the Dropdown.Item, with a test to see if the Item value matches the set value for the dropdown.
<Dropdown
value={value}
compact
style={myStyle}
selection
onChange={getLanguage} // could be removed
options={countryOptions}
>
<Dropdown.Menu style={myStyle} >
{countryOptions.map( country => {
return (
<Dropdown.Item
key={country.key}
value={country.value}
active={(value === country.value)}
flag={country.flag}
onClick={getLanguage}
/>)
})}
</Dropdown.Menu>
</Dropdown>

React bootstrap default selected value for dropdown

I was using react-bootstrap library and I wanted to have default selected value.
I went through their docs and I wasn't able to find anything related to pass/set default value.
This is how I am currently using
const dropDownQuestion = (props) => {
const { options, upsideEmit, value } = props
return (
<DropdownButton
id="dropdown-basic-button"
onSelect={(eventKey) => upsideEmit(eventKey)}
>
{options.map((element) => (
<Dropdown.Item key={element.id}>{element.value}</Dropdown.Item>
))}
</DropdownButton>
)
}
Where value happens to be optional default Value. Can someone help me how to achieve this with react-bootstrap dropdown?
It depends on what do you mean by default value. If you mean value that appears on the dropdown button before the user touch it, you can simply insert it (hard-coded or by variable) as the text of the Dropdown.Toggle, for example:
<Dropdown.Toggle id="dropdown-basic">
Your "default value" here
</Dropdown.Toggle>
If by default value you mean the value of the dropdown's selected item before the user touch it, it's up to you, by choosing it in the data structure you use to set the values, for example:
var options = ["1", "2", "3", "4", "5"];
let chosenValue=options[0] // The "default Value"
function onSelect(eventKey, event) { // user can change the "default value"
chosenValue=eventKey;
.
.
.
}
<Dropdown onSelect={onSelect}>
<Dropdown.Toggle id="dropdown-basic" />
<Dropdown.Menu>
{options.map(option => (
<Dropdown.Item
eventKey={option}
key={option}>
{option}
</Dropdown.Item>
))}
</Dropdown.Menu>
</Dropdown>
You can use the active prop on the Dropdown.Item to highlight it, if that's what you mean?
A DropdownButton isn't designed as an input, so you can't have a "default value", each item in the menu is rendered as a button.

Cannot pass the correct value when user Selects an new Option in Dropdown Component

I'm creating a new generic dropdown component for this form. I'm running into an issue where when you go to make a new selection, it sets the new value to the current value again. When I select the desired option a second time, the dropdown will then show the correct option.
Upon inspection I've noticed that when I use event.target.value, it's only returning the current (default) value I set, not the value I'm trying to select. I suspect that this is the issue.
function SelectInput (props) {
const [selectedOption, setSelectedOption] = useState(undefined);
useEffect(() => {
setSelectedOption(input.currentValue);
}, [props.currentValue])
return (
<select
name={props.inputName}
value={selectedOption}
ref={props.register}
onChange={e => setSelectedOption(e.target.value)}>
{props.options.map((option, i) => (
<option value={i+1} key={i}>{option}</option>
))}
</select>
)
};
If using e.target.value isn't the correct way to get the option the user is trying to select, I'm not sure what is. This field needs to be able to show pre-populated data (or option) but also allow the user to change the value. (In hopefully not two clicks, like it's currently behaving)
Your setup seems a little strange to me, so I have replaced your input param with standard React props. You don't need the useEffect hook and it works if you take it out:
function SelectInput(props) {
const [selectedOption, setSelectedOption] = useState(props.defaultVal);
return (
<select
name={input.inputName}
value={selectedOption}
ref={input.register}
onChange={e => setSelectedOption(e.target.value)}
>
{input.options.map((option, i) => (
<option value={i + 1} key={i}>
{option}
</option>
))}
</select>
);
}
ReactDOM.render(
<SelectInput options={input.options} defaultVal={3} />,
document.getElementById("root")
);
Possibly the 'currentValue' you were trying to set did not correlate to an option value (e.g. number).
https://codesandbox.io/s/react-select-input-fn4to

Resources