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
}
Related
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
Hello guys I'm using React Material UI select. When I change option I trigger onChange method and add attr on selected value so how can I set fisrt option of items as selected.
value={} **// I want to display first option to selected without trigger on Change method**
onChange={(e) => {
data.forEach(a => {
if (a.Id === e.target.value) {
a.selected = true
} else {
a.selected = false
}
});
}}
>
<MenuItem disabled value=""><em>Please Select</em></MenuItem>
{data.map((item) => {
return (
<MenuItem key={item.Id} value={item.Id} >
{item.Ad}
</MenuItem>
);
})}
</Select>
You need 2 states on your component, data and active. Where data is the items you want to display on the dropdown, and active which indicates what item is currently selected. Commonly, we use useEffect hook to initialize states.
Also, wehave to re-implement your onChange function. I suggest you review the docs on how to update states on functional component https://reactjs.org/docs/hooks-reference.html#usestate.
Anyway, you can change your code to this
export default function App() {
const [data, setData] = React.useState(DATA);
// select the first option by default
const [active, setActive] = React.useState(DATA[0].Id);
function onChange(event) {
setActive(event.target.value);
}
return (
<Select value={active} onChange={onChange} fullWidth>
<MenuItem disabled value="">
<em>Please Select</em>
</MenuItem>
{data.map((item) => (
<MenuItem key={item.Id} value={item.Id}>
{item.Ad}
</MenuItem>
))}
</Select>
);
}
...and I created a codesandbox for you to try it out.
Hay I am struggling on how to pass data that's in a class, to another react native component. I am able to display data on the same screen, however I want to have the user input some text and have it display on another screen.
1) Initial Screen: User presses button to navigate to text inputs, and will navigate back to this screen to view the list. Note: If I add the list here I get an error "undefined is not an object". Because I was not able to figure out how to PASS THE LISTARRAY variable to that screen.
export const GoalsScreen = ({ navigation }) => {
return (
<SafeAreaView style={styles.container}>
<Header>
{/* header title */}
<Text style={styles.goalText}> Expand your life</Text>
{/* add goal button goto stack */}
<TouchableOpacity onPress={() => navigation.navigate("AddGoal")} >
<Text style={styles.addBtn}> + </Text>
</TouchableOpacity>
</Header>
{/* Error here, need to get data from other screen */}
<FlatList
data={this.state.listArray}
renderItem={({ item, index }) => {
return (
<View>
<Text style={{ fontSize: 30 }}>{item.fireListGoal} </Text>
<Text style={{ fontSize: 20 }}>{item.fireListCat}</Text>
<Text style={{ fontSize: 15 }}> {item.fireListWhy}</Text>
</View>
);
}}
>
</FlatList>
</SafeAreaView>
);
}
2) List Screen: If I put the flatList here everything works, but I need to PASS THE DATA thats inputted here in the firebase real-time database and display it on the other screen shown above.
export class AddGoalList extends React.Component {
// state and defult values
constructor(props) {
super(props)
// set inital values
this.state = {
listArray: [],
goal: '',
category: 'Pick One',
why: '',
}
}
//triggers rerendering, put values in a JSON array
componentDidMount() {
goalsRef.on('value', (childSnapshot) => {
const listArray = [];
childSnapshot.forEach((doc) => {
listArray.push({
key: doc.key,
fireListGoal: doc.toJSON().fireListGoal,
fireListCat: doc.toJSON().fireListCat,
fireListWhy: doc.toJSON().fireListWhy
});
this.setState({
listArray: listArray.sort((a, b) => {
return (
a.fireListGoal < b.fireListGoal,
a.fireListCat < b.fireListCat,
a.fireListWhy < b.fireListWhy
);
}),
});
});
});
}
// when button pressed...
onGoal = ({ }) => {
// if form empty alert user
if (this.state.goal.trim() && this.state.why.trim() === '') {
alert("Please fill form.");
return;
}
if (this.state.category.valueOf() === 'Pick One') {
alert("Fill in all inputs.");
return;
}
// otherwise push data to firebase
goalsRef.push({
fireListGoal: this.state.goal,
fireListCat: this.state.category,
fireListWhy: this.state.why
});
}
render() {
return (
// KeyboardAvoidingView ==> prevent keyboard from overlapping
<KeyboardAvoidingView style={styles.container}>
<SafeAreaView>
<Text>Sparks your life!</Text>
{/* Goal title */}
<Text>What is your goal</Text>
<TextInput
placeholder="Enter your goal"
keyboardType='default'
onChangeText={
(text) => {
this.setState({ goal: text });
}
}
value={this.state.goal}
/>
{/* pick selected cetegory */}
<Text>Pick a Category</Text>
{/* picker component */}
<Picker
selectedValue={this.state.category}
onValueChange={(itemValue) => this.setState({ category: itemValue })}
>
<Picker.Item label="Pick One" value="Pick One" />
<Picker.Item label="Fitness" value="Fitness" />
<Picker.Item label="Health" value="Health" />
<Picker.Item label="Travel" value="Travel" />
<Picker.Item label="Wealth" value="Wealth" />
<Picker.Item label="Creativity" value="Creativity" />
<Picker.Item label="Skills" value="Skills" />
</Picker>
<Text>Why did you pick this goal?</Text>
<TextInput
placeholder="Enter your why"
keyboardType='default'
onChangeText={
(text) => {
this.setState({ why: text });
}
}
value={this.state.why}
/>
{/* nav back to My Goal list */}
<Button title="add goal" onPress={this.onGoal.bind(this)} />
</SafeAreaView>
{/* remove list here and add to other GoalsScreen */}
<FlatList
data={this.state.listArray}
renderItem={({ item, index }) => {
return (
<View>
<Text style={{fontSize: 30}}>{item.fireListGoal} </Text>
<Text style={{fontSize: 20}}>{item.fireListCat}</Text>
<Text style={{fontSize: 15}}> {item.fireListWhy}</Text>
</View>
);
}}
>
</FlatList>
</KeyboardAvoidingView>
);
}
}
I have tried to useState and pass data as a param but got errors, in able to use the variable navigation in a class..? Also tried to put it in a separate function and that did now work ether. I'll add my code bellow so you can take a look. Any suggestions and or references to any helpful docs would really be appreciated.
Would really appreciate some help, been trying to resolve this for the past few days with no luck. Many thanks!
If i understand the flow correctly, what you want is the following:
Initially, you have a first screen with a list of items (GoalsScreen). From there the user can open a new screen, where he can add items (AddGoalScreen). So, when the user goes back, you want him to see the updated list.
First of all, in the above code, the GoalsSrceen has not defined any state listArray, so that's why you get undefined error. You need to declare it just like you did in AddGoalScreen. Also, as i can see, the AddGoalScreen will no longer display this listArray, so you can simply move the goalsRef.on('value', ... subscription in the GoalsScreen. Doing so, each time you push to the firebase through AddGoalScreen, the on('value') subscription will be triggered inside GoalsScreen, and the GoalsScreen will rerender, keeping its state available. So you have your problem fixed
A feature in my project in province searching but now I'm using typing the name of province and now I want to use Picker in React-native to setState from value that user selected.How can I setState from value that user selected from Picker?
My searching function and constructor.
constructor(props) {
super(props);
this.state = {
currentCity: "Phuket",
searchText: ""
};
this.handleSubmit = this.handleSubmit.bind(this);
}
handleSubmit(event) {
event.preventDefault();
const { searchText } = this.state;
this.refs.modal3.close();
this.setState({ currentCity: searchText });
}
My Searching box and picker.
<TextInput
placeholder="City name"
ref={el => (this.element = el)}
style={styles.textInput}
value={this.state.searchText}
onChangeText={searchText => this.setState({ searchText })}
/>
<View>
<Button style={styles.btn} onPress={this.handleSubmit}>
<Text style={styles.submitText}>Submit</Text>
</Button>
</View>
{//Dropdown Picker
}
<Picker
selectedValue={this.state.language}
style={{ height: 50, width: 200 }}
onValueChange={(itemValue, itemIndex) =>
this.setState({ language: itemValue })
}
>
<Picker.Item label="Amnat Charoen" value="1906689" />
<Picker.Item label="Ang Thong" value="1621034" />
<Picker.Item label="Bangkok" value="1609350" />
from the code you provided in your question i think you are new to react-native. your code is wrong( you just copied & pasted code). this part selectedValue={this.state.language} in your Picker is wrong because there is no language in your state.
imagine you have a Picker which has list of cities. and you have a variable in state named selectedCity.
so your picker would be like this :
<Picker
selectedValue={this.state.selectedCity}
onValueChange={(itemValue, itemIndex) =>
this.setState({ selectedCity: itemValue })
}
>
<Picker.Item label="city1" value="1" />
<Picker.Item label="city2" value="2" />
</Picker>
this will make a Picker listing 2 cities( city1 - city2) and whenever user selects one of them this.setState() will be called and selectedCity in state will be initialized.
if you want to call setState in another method, just instead of
onValueChange={(itemValue, itemIndex) =>
this.setState({ selectedCity: itemValue })
}
use
onValueChange={(itemValue, itemIndex) =>
//call method here!
}
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>
);
}