How to make react-native Picker stay at newly selected option? - javascript

I have a picker that I'm testing on iOS right now with two options. Every time I drag down from the first option to the second option, the picker immediately returns to the first option.
This is what my the code for my picker looks like.
<Picker
style={{
width: 100,
}}
selectedValue={(this.state && this.state.pickerValue) || 'a'}
onValueChange={(value) => {
this.setState({value});
}} itemStyle={{color: 'white'}}>
<Picker.Item label={'Hello'} value={'a'} />
<Picker.Item label={'World'} value={'b'} />
</Picker>
I want the selector to stay at the newly scrolled-to option. I've also removed the || 'a' part of the selectedValue attribute but that didn't solve the issue either.

On value change you need to specify which property of the state changed and change it accordingly with this.setState
onValueChange={(value) => {this.setState({pickerValue: value});
Complete Code
<Picker
style={{
width: 100,
}}
selectedValue={(this.state && this.state.pickerValue) || 'a'}
onValueChange={(value) => {
this.setState({pickerValue: value});
}} itemStyle={{color: 'white'}}>
<Picker.Item label={'Hello'} value={'a'} />
<Picker.Item label={'World'} value={'b'} />
</Picker>

I just came across this and was facing the same issue, the scrolling reaches the new item and resets to the first item.
I have done this using stateless component (Hooks):
I have an array of objects as the value and option as key
const data = useState({
"options":[{
"name":"Dish 1","price":0},{"name":"Dish 2","price":0}]})
const [selected, setSelected] = useState(0)
The Picker component:
<PickerIOS
selectedValue={selected_choice}
onValueChange={(value, index) => {
set_selected_choice(index)
}}
>
{data?.map((item, index) => (
<PickerIOS.Item
key={item}
value={index}
label={item.name}
/>
))}
</PickerIOS>
Here, I have stored the index of the array elements in the selected state and have updated it from the PickerIOS Item, keeping the value as index.

I used this "hack":
render() {
const values = ['1', '2'];
return (
<Picker
value={this.state.value}
onValueChange={this.onValueChange.bind(this)}
>
{
<Picker
value={this.state.value}
onValueChange={this.onValueChange.bind(this)}
>
{
[<Picker.Item
label="n/a"
value={null}
/>].concat(values.map(value => {
return (
<Picker.Item
label={value}
value={value}
/>
)
})
)
}
</Picker>
);
}

Related

How to clear data on Select multiple when typing on another textfield using reactjs

This is my current code, what I want here is after selecting on Select option (CHIP) and if the user type on the textfield I want to clear what the user selected on CHIP, What should I do to get what i want functionality?
const names = [
'Oliver Hansen',
'Van Henry',
'April Tucker',
];
function getStyles(name, personName, theme) {
return {
fontWeight:
personName.indexOf(name) === -1
? theme.typography.fontWeightRegular
: theme.typography.fontWeightMedium,
};
}
export default function MultipleSelectChip() {
const theme = useTheme();
const [personName, setPersonName] = React.useState([]);
const handleChange = (event) => {
const {
target: { value },
} = event;
setPersonName(
// On autofill we get a stringified value.
typeof value === 'string' ? value.split(',') : value
);
};
const handleChangeTextField = (event) => {
setPersonName(null);
};
return (
<div>
<FormControl sx={{ m: 1, width: 300 }}>
<InputLabel id="demo-multiple-chip-label">Chip</InputLabel>
<Select
labelId="demo-multiple-chip-label"
id="demo-multiple-chip"
multiple
value={personName}
onChange={handleChange}
input={<OutlinedInput id="select-multiple-chip" label="Chip" />}
renderValue={(selected) => (
<Box sx={{ display: 'flex', flexWrap: 'wrap', gap: 0.5 }}>
{selected.map((value) => (
<Chip key={value} label={value} />
))}
</Box>
)}
MenuProps={MenuProps}
>
{names.map((name) => (
<MenuItem
key={name}
value={name}
style={getStyles(name, personName, theme)}
>
{name}
</MenuItem>
))}
</Select>
<TextField
variant="outlined"
label="Type anything to remove the value of Chip"
onChange={handleChangeTextField} />
</FormControl>
</div>
This is my current code, what I want here is after selecting on Select option (CHIP) and if the user type on the textfield I want to clear what the user selected on CHIP, What should I do to get what i want functionality?
I would set your textfield to be controlled (ie backed by a state variable) and add an effect hook to watch it.
When it receives a value, clear the selected names by setting personNames back to an empty array.
const [text, setText] = useState("");
useEffect(() => {
if (text) {
setPersonName([]);
}
}, [text]);
const handleChangeTextField = ({ target: { value } }) => {
setText(value);
};
<TextField
value={text}
variant="outlined"
label="Type anything to remove the value of Chip"
onChange={handleChangeTextField}
/>
You might also want to clear the text field when selecting names by adding this into handleChange...
setText("");

MUI : Out-of-range value `X` for the select component

I'm making a glossary where each of the definitions are a cards that can be flipped (CardFlip) I build an array where I send for each card, the data via props to my component "CardFlip" dealing with the actual construction of cards with my data
This is my first component sending everything :
<div>
{glossaire.map((carte, index) => (
<Fragment key={carte.dat_id}>
<CardFlip item={carte} tags={tags} />
</Fragment>
))}
</div>
First prop ,"item", contains information such as: a title, a definition, a search tag
Second prop, "tags", is the list of tags that a definition can have, a definition can have only one tag, right now only those tags are available : "Application", "Entreprise", "Technique" and "Télécom"
And here is the code for my second component (only the interesting part):
export default function CardFlip = ({ item, user, tags }) => {
// -- [Variables] --
// Flip front / back
const [isFlipped, setIsFlipped] = useState(false);
// Storage
const [titreDef, setTitreDef] = useState("");
const [definitionDef, setDefinitionDef] = useState("");
const [tagSelected, setTagSelected] = useState("");
// Flag for error
const [errorTitre, setErrorTitre] = useState(false);
const [errorDefinition, setErrorDefinition] = useState(false);
const [errorSelect, setErrorSelect] = useState(false);
console.log(item.dat_tag);
console.log(tags);
// -- [Handlers] --
// UPDATE
const handleTitre = (data) => {
setTitreDef(data);
setErrorTitre(false);
};
const handleDefinition = (data) => {
setDefinitionDef(data);
setErrorDefinition(false);
};
const handleSelect = (event) => {
const {
target: { value },
} = event;
setTagSelected(value);
setErrorSelect(false);
}
return (
<Grow in style={{ transformOrigin: "0 0 0" }} {...{ timeout: 1000 }}>
<div style={{ display: "flex", padding: "10px" }}>
<ReactCardFlip
isFlipped={isFlipped}
flipDirection="horizontal"
style={{ height: "100%" }}
>
<div
className={style.CardBack}
style={{ display: "flex", height: "100%" }}
>
<Card className={style.mainCard}>
<CardActions className={style.buttonFlipCard}>
<Tooltip title="Retour">
<IconButton
className={style.iconFlipCard}
disableRipple
onClick={() => setIsFlipped((prev) => !prev)}
>
<ChevronLeftIcon />
</IconButton>
</Tooltip>
</CardActions>
<CardContent>
<div className={style.divTagBack}>
<FormControl
sx={{width: "90%"}}
>
<InputLabel
id="SelectLabel"
sx={{display: "flex"}}
>
{<TagIcon />}
{" Tag"}
</InputLabel>
<Select
labelId="SelectLabel"
label={<TagIcon /> + " Tag"}
renderValue={(selected) => (
<Chip
onMouseDown={(event) => {
event.stopPropagation();
}}
key={selected}
label={selected}
icon={<TagIcon />}
/>
)}
defaultValue={item.dat_tag}
onChange={handleSelect}
>
{tags && tags.map((tag) => (
<MenuItem key={tag.dat_tag} value={tag.dat_tag}>
{tag.dat_tag}
</MenuItem>
))}
</Select>
</FormControl>
</div>
</CardContent>
</Card>
</div>
</ReactCardFlip>
</div>
</Grow>
);
};
When the user returns the card, he can change the title, description and tag of the chosen card.
My problem is with the Select.
In order to display the selected tag before any modification, I display the tag in defaultValue={item.dat_tag}
(Also tried with value and not defaultValue)
Then with my second prop, I build the list of my menu.
This is where I get my warning (which seems to extend the rendering time of the page considerably (Since it load / render like +100 definitions, getting a warning for every definition)
MUI: You have provided an out-of-range value Entreprise for the select component.
Consider providing a value that matches one of the available options or ''. The available values are "".
This is an example of what a console.logs told me about my props :
item.dat_tag
Entreprise
tags
0: {dat_tag: "Applicatif"}
1: {dat_tag: "Entreprise"}
2: {dat_tag: "Technique"}
3: {dat_tag: "Télécom"}
I already looked at several posts saying to put in a string variable my tag data (item.dat_tag) or to display my menu when it is not empty. No change.

React Material-UI Multiselect with checkbox ccannot select all

I am trying to use Material UI multiselect with checkboxes. So far, i am able to make multiple selects and get the values but i am unable to render the actual names of selected values or get all selected values. Any leads to a new approach i can use or useful links to help get the ids of all selected values in my array will be appreciated.
I created a sandbox that has a mock of my data from an api as well here : sandbox
My select looks like this :
const [selected, setSelected] = useState([]);
const isAllSelected =
options.length > 0 && selected.length === options.length;
const handleChange = (event) => {
console.log("vals", event.target);
const value = event.target.value;
if (value[value.length - 1] === "all") {
setSelected(selected.length === options.length ? [] : options.title);
return;
}
setSelected(value);
console.log("values", selected);
};
<FormControl className={classes.formControl}>
<InputLabel id="mutiple-select-label">Multiple Select</InputLabel>
<Select
labelId="mutiple-select-label"
multiple
variant="outlined"
value={selected}
onChange={handleChange}
renderValue={(selected) => selected}
MenuProps={MenuProps}
>
<MenuItem
value="all"
classes={{
root: isAllSelected ? classes.selectedAll : ""
}}
>
<ListItemIcon>
<Checkbox
classes={{ indeterminate: classes.indeterminateColor }}
checked={isAllSelected}
indeterminate={
selected.length > 0 && selected.length < options.length
}
/>
</ListItemIcon>
<ListItemText
classes={{ primary: classes.selectAllText }}
primary="Select All"
/>
</MenuItem>
{options.map((option) => (
<MenuItem key={option.id} value={option.id}>
<ListItemIcon>
<Checkbox checked={selected.includes(option.id)} />
</ListItemIcon>
<ListItemText primary={option.title} />
</MenuItem>
))}
</Select>
<p>{selected}</p>
</FormControl>
I did a few fix in your code so it works, in this sandbox:
To display some text in your menu, you are supposed to display the text in the component ListItemText:
<ListItemText>{option}</ListItemText>
An other thing is that you cannot access selected directly, since it is a state, so it is set asynchronously. To solve this, you can simply access it like this:
selected?.length
This way, even if selected is still undefined, it will not throw any errors

MaterialUI Autocomplete - Avoid clearing input text filter when option is selected

I've imported the Autocomplete component from MaterialUI in my React project and using it as a multiple select with checkboxes: https://material-ui.com/components/autocomplete/#checkboxes
I noticed that when I type into the input to filter the list and then select a value, the filter inserted by the user resets. I want to avoid this and continue to multi-select with the filter instead of reinsert it every time. I didn't find any props in the component API to solve this.
Any suggestion?
That's my component code:
const VirtualAutocomplete = (props) => {
const classes = useStyles();
const textClasses = textStyles();
return (
<Autocomplete
id={props.id}
style={{ width: 'auto' }}
value={props.value}
limitTags={4}
noOptionsText="No records found."
classes={classes}
disableCloseOnSelect
ListboxComponent={ListboxComponent}
renderGroup={renderGroup}
onChange={props.onChange}
options={props.options}
filterOptions={startsWith}
multiple={props.multiple}
renderInput={(params) =>
<ThemeProvider theme={theme}>
<TextField {...params}
variant='outlined'
classes={{ root: textClasses.formControlRoot }}
InputLabelProps={{ classes: { root: textClasses.labelRoot } }}
label={props.label}
/>
</ThemeProvider>
}
renderOption={(option, { selected }) => (
<Fragment>
<Checkbox
icon={icon}
checkedIcon={checkedIcon}
style={{ marginRight: 8 }}
checked={selected}
/>
{option}
</Fragment>
)}
/>
);
}
Create a state that holds input value. Then on TextField onChange pass the function to change this state. Then on Autocomplete pass the props inputValue with that state content. You can also use disableCloseOnSelect props to Autocomplete so options box doesnt close on option selected.
Take a look at their docs about those props https://material-ui.com/pt/api/autocomplete/
Here is a example using their demo: https://codesandbox.io/s/material-demo-forked-pdh81?file=/demo.js:746-766

onPress on picker.item to close the dropdown- react-native

I have a dropdown and I'm using react-native picker component. Everything is working fine, the problem is that I need to close the dropdown when the user presses on any picker items
this.state.list.map((obj, index) => {
return (
<Picker.Item key={index} label={obj.label} value={obj.value} />
);
the picker gives us only onValueChange prop, but I need onPress functionality for any picker items individually to close the dropdown.
I have also tried this
this.state.list.map((obj, index) => {
return (
<TouchableWithoutFeedback onPress={this.itemPressHandler}>
<Picker.Item key={index} label={obj.label} value={obj.value} />
</TouchableWithoutFeedback>
);
but it doesn't render the dropdown.
Is there any way to get this functionality?
According to docs.
<Picker
selectedValue={this.state.valueSelected}
onValueChange={(itemValue, itemIndex) => {
this.handlePickerValueChange(itemValue, itemIndex)
}
mode={'dialog'} // optional
>
this.state.list.map((obj, index) => {
return (
<Picker.Item key={index} label={obj.label} value={obj.value} />
);
});
</Picker>
Set the default selected value in state
state={
valueSelected: "Choose a value"
}
Handle change when user selects a different option
handlePickerValueChange = (itemValue, itemIndex) => {
//do your stuff
}

Categories

Resources