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.
Related
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.
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]);
I have a dropdown with 2 possibles menus that can reach each others by clicking on some dropdown items. By adding autoClose='outside' I fixed the problem of untimely closing when clicking somewhere in the dropdown main menu. But since I have another menu, once it's showed, the first time I open it, the autoClose doesn't really work, instead, it's as if it was never set, close the whole dropdown, and when I reopen it, go in the secondary menu for the second, this 'bug' doesn't occur again on this menu, but occurs when I go back in the first one etc..
I suspect it's because autoClose only works on the current selected menu, in the example below it works with the main menu and does not in the secondary menu first then, as described above, when I reopen the dropdown it shows directly the secondary menu, works, and once I go back in the main menu, it doesn't.
This is basically the code I'm running.
import {Dropdown} from 'react-bootstrap';
import {useState} from 'react';
const Mydropdown = (props) => {
const [menu,setMenu] = useState('main');
return(
<>
<Dropdown autoClose='outside'>
{
menu=="main"
&&
(
<>
<Dropdown.Menu>
<Dropdown.Item onClick={()=>setMenu("secondary")}>
Secondary menu
</Dropdown.Item>
</Dropdown.Menu>
</>
)
}
{
menu=="secondary"
&&
(
<>
<Dropdown.Menu>
<Dropdown.Item onClick={()=>setMenu("main")}>
Secondary menu
</Dropdown.Item>
</Dropdown.Menu>
</>
)
}
</Dropdown>
</>
);
}
I'm not sure I'm following your requirements 100%, but this version should allow a single dropdown to optionally toggle contents (without auto-closing):
const Mydropdown = (props) => {
const [menu, setMenu] = useState("main");
return (
<Dropdown autoClose="outside">
<Dropdown.Toggle variant="primary">Dropdown Test</Dropdown.Toggle>
<Dropdown.Menu>
<Dropdown.Item href="#">Menu Item</Dropdown.Item>
<Dropdown.Item href="#">Menu Item</Dropdown.Item>
<Dropdown.Item href="#">Menu Item</Dropdown.Item>
{menu == "main" && (
<Dropdown.Item onClick={() => setMenu("secondary")}>
Secondary menu
</Dropdown.Item>
)}
{menu == "secondary" && (
<Dropdown.Item onClick={() => setMenu("main")}>
Main menu
</Dropdown.Item>
)}
</Dropdown.Menu>
</Dropdown>
);
};
Working example available here: https://codepen.io/ablewhite/pen/BawdVpg
If I understand your question correctly you want a dropdown menu with another dropdown menu inside of it? The following code would acomplish that, I would suggest using autoClose={false) to prevent the menu from closing.
import { Dropdown } from "react-bootstrap"
import { useState } from "react"
const Mydropdown = (props) => {
const [menu, setMenu] = useState("main")
return (
<Dropdown autoClose={false}>
<Dropdown.Toggle>
Main Menu
</Dropdown.Toggle>
<Dropdown.Menu>
<Dropdown.Item onClick={() => setMenu("secondary")}>Action 1</Dropdown.Item>
{menu === "secondary" &&
<Dropdown autoClose={false}>
<Dropdown.Toggle>
Secondary
</Dropdown.Toggle>
<Dropdown.Menu>
<Dropdown.Item onClick={() => setMenu("main")}>Action 2</Dropdown.Item>
</Dropdown.Menu>
</Dropdown>
}
</Dropdown.Menu>
</Dropdown>
)
}
export default Mydropdown
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>
I figured out how to use react-bootstrap to display a dropdown list:
<DropdownButton bsStyle="success" title="Choose" onSelect={this.handleSelect} >
<MenuItem key="1">Action</MenuItem>
<MenuItem key="2">Another action</MenuItem>
<MenuItem key="3">Something else here</MenuItem>
</DropdownButton>
But how am I suppose to write the handler for onSelect to capture the option being selected? I tried this but don't know what to write inside:
handleSelect: function () {
// what am I suppose to write in there to get the value?
},
Also, is there a way to set an option to be selected by default?
Thank you!
The onSelect function is passed the selected value
<DropdownButton title='Dropdowna' onSelect={function(evt){console.log(evt)}}>
<MenuItem eventKey='abc'>Dropdown link</MenuItem>
<MenuItem eventKey={['a', 'b']}>Dropdown link</MenuItem>
</DropdownButton>
In this case if you select the first option, 'abc' is printed, in the second option you can see an object can be passed in as well.
So in your code
handleSelect: function (evt) {
// what am I suppose to write in there to get the value?
console.log(evt)
},
I'm not sure what you mean by a default value since this isn't a select - the button text is whatever is in the title attribute. If you want to handle a default value you could just set a value when value is null.
you forgot to mention that eventKey is passed as a second parameter, this is the correct form to obtain the value of what you clicked:
handleSelect: function (evt,evtKey) {
// what am I suppose to write in there to get the value?
console.log(evtKey)
},
You may want to use the FormControl >> select component for your case:
<FormControl componentClass="select" placeholder="select">
<option value="select">select</option>
<option value="other">...</option>
</FormControl>
You should change the handleSelect signature as follows (inside the Component Class):
handleSelect = (evtKey, evt) => {
// Get the selectedIndex in the evtKey variable
}
To set the default value, you'll need to use the title prop on the DropdownButton
Ref: https://react-bootstrap.github.io/components/dropdowns/