I am developing an ecommerce app where i need to show product options like Size, color etc.
These options are coming dynamically from API.
I am using Picker component of react native to show option values so that user can choose a value.
Now issue is i select a value, it does not reflect in picker value because i don't know that how to define state variables for pickers dynamically.
so that i can update state values when picker onchangevalue is called.
Initially state looks like this:
state = {
options: {}
}
Now i want that this should dynamically add options to this blank object so it will look like this:
state = {
options: {
Size: '0.5"',
Colour: 'White Dudhiya'
}
}
And after I'll create it then How to access these state variables in any other function.
Please correct me if i am moving in wrong direction and share the correct way to achieve the same.
Please let me know if you need more information from my side.
Any help appreciated.
Thanks
Edit:
This is how i am rendering product options and their values dynamically:
renderOptions(data) {
if (data.options.length > 0) {
var allOptions = data.options.map((item) => {
if (item.product_option_value.length > 0) {
return (
<View key={item.option_id} style={{ marginLeft: 10, marginRight: 10, marginBottom: 15, width: windowWidth - 20 }}>
<MyAppText>{item.name}</MyAppText>
<View style={{ borderWidth: 1, borderColor: '#E8E8E8', marginTop: 5, height: 50 }}>
<Picker
selectedValue={this.state.options[item.name]}
style={{ height: 50, width: '100%' }}
onValueChange={(itemValue, itemIndex) =>
this.setState(() => {
key = item.name;
return {key: itemValue};
})
}
>
{this.renderOptionValues(item)}
</Picker>
</View>
</View>
);
} else {
return;
}
});
return allOptions;
}
}
renderOptionValues(option) {
if (option.product_option_value.length > 0) {
return (option.product_option_value.map((optionValue) => {
return (
<Picker.Item key={optionValue.option_value_id} label={entities.decode(optionValue.name)} value={optionValue.option_value_id} />
);
}));
}
}
I call renderOptions() function inside my render() function.
Take a look at the following implementation, I just tried with some hypothetical values and it worked fine.
class DynamicOptions extends React.Component {
constructor(props) {
super(props);
this.state = {};
}
renderOptions = (options = []) => {
return options.map(option => {
return <Picker.Item label={option.label} value={option.value} key={option.key}/>
});
}
render() {
const {
options
} = this.props;
console.log(this.state);
return ( <
View style = {{ flex: 1 }} >
{
options.map((item, index) => {
return (
<View style={{flex: 1}}>
{
options.map((item, index) => {
return (
<View key={`item-${index}`}>
<Text>{item.name}</Text>
<Picker
selectedValue={this.state[item.name]}
style={{ height: 50, width: '100%' }}
onValueChange={(listItem, index) => {
this.setState({
[item.name]: listItem
});
}}
>
{ this.renderOptions(item.options) }
</Picker>
</View>
)
})
}
</View>
)
}
}
export default DynamicOptions;
Following data I have used to render options (I am not sure what data you are using)
const options = [
{
name: 'Color',
options: [{label: 'Red', value: 'Red', key: 'Red'}, {label: 'Green', value: 'Green', key: 'Green'}]
},
{
name: 'Size',
options: [{label: '1', value: '1', key: '1'}, {label: '2', value: '2', key: '2'}]
}
];
This is how I have called that function
<DynamicOptions options={options}/>
Hope this will help!
according to https://stackoverflow.com/a/35398253/2083099 , I believe you need something like this,
import React, { Component } from 'react';
import { Platform, StyleSheet, Text, View, FlatList, Image, TouchableOpacity, Dimensions, Picker } from 'react-native';
export default class Test extends Component {
constructor() {
super();
this.state = {
services: [],
selectedService: 'a'
}
}
componentDidMount() {
//replace api request instead of setTimeout and then change the services data with setState
setTimeout(() => {
this.setState({
services: [ 'one', 'two', 'three', 'four', 'five' ]
})
}, 3000)
}
render() {
return (
<View>
<Text>Pick a service</Text>
<Picker
selectedValue={this.state.selectedService}
onValueChange={(service) => (this.setState({ selectedService: service }))} >
{this.state.services.map((s, i) => {
return <Picker.Item key={i} value={s} label={s} />
})}
</Picker>
</View>
);
}
}
Related
How to multi select and highlight the components in a react native flatlist. I have checked the doc. But it is bit confusing can anybody help me. I have done single select using this method.Could any one modify this to a multi select.I will give the snack link here where i have done the single select
import * as React from 'react';
import {
Text,
View,
StyleSheet,
FlatList,
TouchableOpacity,
} from 'react-native';
import Constants from 'expo-constants';
const Data = [
{
id: 1,
first_name: 'Sile',
},
{
id: 2,
first_name: 'Clementia',
},
{
id: 3,
first_name: 'Brita',
},
{
id: 4,
first_name: 'Duke',
},
{
id: 5,
first_name: 'Hedvig',
},
{
id: 6,
first_name: 'Paulie',
},
{
id: 7,
first_name: 'Munmro',
},
{
id: 8,
first_name: 'Dyanna',
},
{
id: 9,
first_name: 'Shanta',
},
{
id: 10,
first_name: 'Bambi',
},
];
// or any pure javascript modules available in npm
import { Card } from 'react-native-paper';
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
selectedItem: null,
};
}
onPressHandler(id) {
this.setState({ selectedItem: id });
}
render() {
return (
<View>
<FlatList
extraData={this.state.selectedItem} //Must implemented
//horizontal={true}
data={Data}
keyExtractor={item => item.id.toString()}
showsHorizontalScrollIndicator={false}
renderItem={({ item }) => (
<TouchableOpacity onPress={() => this.onPressHandler(item.id)}>
<Card
style={
this.state.selectedItem === item.id
? {
padding: 10,
borderRadius: 5,
backgroundColor: '#000000',
}
: {
padding: 10,
borderRadius: 5,
backgroundColor: '#a1a1a1',
}
}>
<Text>{item.first_name}</Text>
</Card>
</TouchableOpacity>
)}
/>
</View>
);
}
}
const styles = StyleSheet.create({
});
this is the sample data
I have made some changes and made your flatlist as multiselect. Please visit this link.
I have made below changes for making this as multiselect:
Added dummy data in state & passed it to flatlist's data.
On item press iterate data and for corresponding item set item.selected=true.
Inside flatlist's renderItem if item.selected==true then show selection else remove selection.
Please check and let me know.
check this logic,
...
this.state = {
clientsArray: clientsArray,
selectedClients: []
};
//'clientsArray' is your data array
...
_renderCell = ({ item, index }) => {
const { selectedClients, clientsArray } = this.state;
let isSelected =
selectedClients.filter(o => {
return o.id === item.id;
}).length > 0
? true
: false;
//change your UI based on the 'isSelected' value
return (
<TouchableOpacity
activeOpacity={Constants.ACTIVE_OPACITY}
onPress={() => {
this._didSelectClient(item);
}}
>
{
//Your component
}
</TouchableOpacity>
}
_didSelectClient = selectedItem => {
let selectedClients = this.state.selectedClients;
let isItemSelected =
selectedClients.filter(item => {
return item.id.includes(selectedItem.id);
}).length > 0
? true
: false;
if (isItemSelected) {
const index = selectedClients.findIndex(
obj => obj.id === selectedItem.id
);
selectedClients.splice(index, 1);
} else {
selectedClients.push(selectedItem);
}
this.setState({ selectedClients });
};
render() {
...
<FlatList
style={{ flex: 1 }}
data={clientsArray}
renderItem={this._renderCell}
keyExtractor={(item, index) => index.toString()}
extraData={this.props}
ListEmptyComponent={this._renderEmptyComponent}
/>
...
}
As said here <checkBox/> is only possible for android but i want to implement single code for both android and iOS (without using any node packages). For this i'm proceeding with views as below
import React, { Component } from 'react';
import { Platform, View, TouchableOpacity } from 'react-native';
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
checkSelected: 1
}
}
checkClick(id) {
this.setState({
checkSelected: id
})
}
render() {
const products = [{
id: 1
},
{
id: 2
},
{
id: 3
}];
return (
products.map((val) => {
return (
<TouchableOpacity key={val.id} onPress={this.checkClick.bind(this, val.id)}>
<View style={{
height: 24,
width: 24,
border: 12,
borderWidth: 2,
borderColor: '#000',
alignItems: 'center',
justifyContent: 'center',
}}>
{
val.id == this.state.checkSelected ?
<View style={{
height: 12,
width: 12,
border: 6,
backgroundColor: '#000',
}} />
: null
}
</View>
</TouchableOpacity>
)
})
);
}
}
This output will be like this
This approach is like RadioButton but i want to follow the <View/> approach for CheckBox also. For this i've implemented like this
import React, { Component } from 'react';
import { View, TouchableOpacity } from 'react-native';
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
checkSelected: []
}
}
checkClick(id) {
let todos = [...this.state.checkSelected]; //creating the copy
//adding new data
todos.push({
checkId: id
});
//updating the state value
this.setState({ checkSelected: todos }, () => {
alert('state: ' + JSON.stringify(this.state.checkSelected));
});
}
render() {
const products = [{
id: 1
},
{
id: 2
},
{
id: 3
}];
return (
products.map((val) => {
return (
<TouchableOpacity key={val.id} onPress={this.checkClick.bind(this, val.id)}>
<View style={{
height: 24,
width: 24,
border: 12,
borderWidth: 2,
borderColor: '#000',
alignItems: 'center',
justifyContent: 'center',
}}>
{
this.state.checkSelected.map((checkIds) => {
{
checkIds.checkId == val.id ?
<View style={{
height: 12,
width: 12,
border: 6,
backgroundColor: '#000',
}} />
: null
}
})
}
</View>
</TouchableOpacity>
)
})
);
}
}
In this approach i'm storing clicked id's in state and trying to select all checkboxes which id's are in state but i'm unable to do that. Can any one suggest me to select multiple check boxes.
Solution
Make new CheckBox component.
Call CheckBox components with right props.
Change your state value depending on CheckBox's clicked prop.
import React, { Component } from 'react';
import { View, TouchableOpacity } from 'react-native';
class CheckBox extends Component {
constructor(props) {
super(props);
this.state = {isCheck: false};
}
checkClicked = async () => {
await this.setState(prevState => ({
isCheck: !prevState.isCheck,
})); // setState is async function.
// Call function type prop with return values.
this.props.clicked && this.props.clicked(this.props.value, this.state.isCheck);
}
render() {
return (
<TouchableOpacity onPress={this.checkClicked} style={this.props.style}>
<View style={{
height: 24,
width: 24,
borderWidth: 2,
borderColor: '#000',
alignItems: 'center',
justifyContent: 'center',
}}>
<View style={{
height: 12,
width: 12,
backgroundColor: this.state.isCheck ? '#000' : '#FFF',
}} />
</View>
</TouchableOpacity>
)
}
}
const products = [
{
id: 1
},
{
id: 2
},
{
id: 3
}
];
export default class CheckBoxScreen extends Component {
constructor(props) {
super(props);
this.state = {
checkSelected: [],
}
}
toggleCheckBox = (id, isCheck) => {
let { checkSelected } = this.state;
if (isCheck) {
checkSelected.push(id);
} else { // remove element
var index = checkSelected.indexOf(id);
if (index > -1) {
checkSelected.splice(index, 1);
}
}
this.setState({ checkSelected });
alert(this.state.checkSelected); // logging
}
render() {
const checkboxs = products.map(({id}) =>
<CheckBox style={{marginTop: 50,}}key={id} value={id} clicked={(id, isCheck) => this.toggleCheckBox(id, isCheck)}></CheckBox>
)
return (
<View style={{flex: 1, alignItems: 'center'}}>
{checkboxs}
</View>
);
}
}
It will work and you can use my example to other ways what you want.
In a different soluion, i would recommend to make a checkbox component , which will have properties id and onCheckBoxValueChange. Both will take initial values from parent component, and on every change, the state of local component will change, returning a callback with the id of the selected.
Child:
constructor(props) {
super(props);
this.state = {
value: this.props.value
};
}
onCheckBoxValueChange(id) {
this.setState({ value: !this.state.value });
this.props.onCheckBoxValueChange(id, !this.state.value);
}
render() {
return (
<ViewStyledAsCheckBox
style={styles.checkBox}
isChecked={this.state.value}
onPress={() => this.onCheckBoxValueChange(this.props.id)}
/>
Parent will call child component like this:
<CheckBoxComponent
id={1}
onCheckBoxValueChange={(id, value) =>
this.doSomethingWithChangedValueInThisSpecificChekbox(id, value)
}
/>
<CheckBoxComponent
id={2}
onCheckBoxValueChange={(id, value) =>
this.doSomethingWithChangedValueInThisSpecificChekbox(id, value)
}
/>
Let me know if this works for you or want more information as this is more of a template than real implementation
I'm working on React native app. I'm looking for a searchable dropdown which I need to implement in many places.
Below see below video for reference:
Sample Video
I have implemented below third parties but they are not same as I need:
https://www.npmjs.com/package/react-native-searchable-dropdown
https://www.npmjs.com/package/react-native-searchable-selectbox
https://github.com/toystars/react-native-multiple-select
I tried implementing something similar a while ago and at the time I dropped the idea of having a drop down as it was inconsistent on both platforms & I could not find a perfect solution. I cannot see your video but I think I know where you're going with this.
Here is my advice:
I would create a separate screen that opens on the tap on this component that would be a 'dropdown', and in there create a searchable/filtrable list. You could try doing that using this: https://www.npmjs.com/package/searchable-flatlist, or create your own flatlist, which is super easy and allows for more customization!
EDIT:
If you don't want a separate screen use this: https://www.npmjs.com/package/react-native-searchable-dropdown
try implementing one :
const sports = ["Badminton","Cricket","Chess","Kho-Kho","Kabbadi","Hockey","Boxing","Football","Basketball","Volleyball","Tennis","Table Tennis"];
predict(){
let q = this.state.query;
let arr = sports.filter(ele => ele.toLowerCase().indexOf(q.toLowerCase()) != -1).splice(0,5);
this.setState((prev = this.state)=>{
let obj={};
Object.assign(obj,prev);
obj.predictions.splice(0,obj.predictions.length);
arr.forEach(ele=>{
obj.predictions.push({key : ele});
});
return obj;
});
}
<TouchableWithoutFeedback onPress={()=>{this.setState({done : true})}}>
<ScrollView
keyboardShouldPersistTaps='handled'
contentContainerStyle={style.content}
>
<View>
<TextInput
onChangeText={(text)=>{
this.setState({query : text , done : false});
this.predict();
}}
placeholder="What do you want to play ?"
placeholderTextColor="#A6A4A4"
value = {this.state.query}
onSubmitEditing = {()=>{this.setState({done : true})}}
underlineColorAndroid = "#0098fd"
></TextInput>
<TouchableOpacity onPress={()=>{this.filteredEvents()}}><Icon name="search" color = "#0098fd" size = {20}></Icon></TouchableOpacity>
</View>
{
this.state.predictions.length != 0 && !this.state.done &&
<FlatList
style={styles.predictor_view}
data={this.state.predictions}
extraData = {this.state}
renderItem = {
({item})=>(
<TouchableOpacity
style={styles.predictions}
onPress={()=>{
console.log('ok');
this.setState({query : item.key,done : true});
console.log(this.state);
}}>
<Text>{item.key}</Text>
</TouchableOpacity>
)
}
/>
}
</ScrollView>
</TouchableWithoutFeedback>
I have used react-native-autocomplete-input
I have written a component to help in the dropdown:
customDropDownComponent.js
/*This is an example of AutoComplete Input/ AutoSuggestion Input*/
import React, { Component } from 'react';
import { StyleSheet, Text, TouchableOpacity, View, Button, ScrollView } from 'react-native';
//import all the components we are going to use.
import Autocomplete from 'react-native-autocomplete-input'
//import Autocomplete component
class CustomDropDownComponent extends Component {
constructor(props) {
super(props);
//Initialization of state
//films will contain the array of suggestion
//query will have the input from the autocomplete input
this.state = {
query: '',
data: [],
dataDuplicate:[],
itemSelected: false
};
}
componentDidMount() {
//Loading all data
this.loadData()
}
findElement(query, text, itemSelected) {
//method called everytime when we change the value of the inputquery === '' ||
if (itemSelected === true||query==='') {
//if the query is null or an item is selected then return blank
return [];
}
//making a case insensitive regular expression to get similar value from the data json
const regex = new RegExp(`${query.trim()}`, 'i');
//return the filtered data array according the query from the input
var newList = [];
var result = this.state.IATADup.filter(data => {
if (data.id.search(regex) === 0) {
newList.push(data);
return false;
} else {
return data.id.search(regex) >= 0;
}
});
result = newList.concat(result);
this.props.adjustMargin(1, result.length);//expadnding space in page to make room for dropdown
this.setState({ data: result, query: text, itemSelected: itemSelected });
}
loadData = () => {
var dataToLoad = Commondata.aircraftDetail
dataToLoad.sort(function (a, b) {
if (a.id > b.id) {
return 1;
}
if (b.id > a.id) {
return -1;
}
return 0;
});
this.setState({
dataDuplicate: dataToLoad
})
}
render() {
const { query } = this.state;
const data = this.state.data;
const comp = (a, b) => a.toLowerCase().trim() === b.toLowerCase().trim();
var inputContainerStyle = styles.inputContainerStyle;
if (this.props.destinationBorder === "#FF0000") {
inputContainerStyle = styles.inputContainerRedStyle;
}
return (
<View style={styles.container} >
<Autocomplete
autoCapitalize="none"
autoCorrect={false}
flatListProps={{ nestedScrollEnabled: true }}
containerStyle={styles.autocompleteContainer}
listStyle={styles.listStyle}
inputContainerStyle={inputContainerStyle}
data={data}
keyExtractor={(item, i) => { return i }
defaultValue={query}
onChangeText={text => {
//handle input
if (text.trim() === "") this.props.adjustMarginBack();//adjust margin to normal in case of empty searrch element
this.findElement(text, text, false);//search for element
}}
placeholder={en.pick_one}
renderItem={({ item }) => (
//you can change the view you want to show in suggestion from here
<TouchableOpacity onPress={() => {
this.props.adjustMarginBack()
this.setState({ query: item.id, itemSelected: true, data: [] });
}}>
<Text style={styles.itemText}>
{item.id}
</Text>
<Text style={styles.itemSubText}>
{item.name}
</Text>
</TouchableOpacity>
)}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
backgroundColor: '#F5FCFF'
},
autocompleteContainer: {
backgroundColor: '#ffffff',
borderWidth: 0,
},
inputContainerStyle: {
borderWidth: 0.5, borderColor: '#D9D9D9', padding: '1.5%'
},
inputContainerRedStyle: {
borderWidth: 0.5, borderColor: '#FF0000', padding: '1.5%'
},
descriptionContainer: {
flex: 1,
justifyContent: 'center',
padding: '5%'
},
itemText: {
fontSize: 15,
paddingTop: 5,
paddingBottom: 5,
margin: 2,
},
itemSubText: {
fontSize: 10,
paddingTop: 5,
paddingBottom: 5,
margin: 2,
marginLeft: 10
},
infoText: {
textAlign: 'center',
fontSize: 16,
},
listStyle: {
height: 100,
position: "relative",
zIndex: 999
}
});
export default CustomComponent;
Now in the display screen:
app.js
import React, { Component } from 'react';
import { View, Text, ScrollView } from 'react-native';
import CustomDropDownComponent from './CustomDropDownComponent.js'
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
};
}
render() {
return (
<View>
<ScrollView
nestedScrollEnabled={true}
keyboardShouldPersistTaps={'handled'}>
<CustomDropDownComponent /*Handle all inputs and margin resets as props *//>
</ScrollView>
</View>
);
}
}
I create a component Confirm.js with react-native <Modal /> that has two DropDownMenu and two <Button />.
I want user click the Yes <Button /> than i can get the DropDownMenu onOptionSelected value. I think i should use this.props but i have no idea how to do it.
I want get the value in MainActivity.js from Confirm.js
Any suggestion would be appreciated. Thanks in advance.
Here is my MainActivty.js click the <Button /> show <Confirm />:
import React, { Component } from 'react';
import { Confirm } from './common';
import { Button } from 'react-native-elements';
class MainActivity extends Component {
constructor(props) {
super(props);
this.state = { movies: [], content: 0, showModal: false, isReady: false };
}
// close the Confirm
onDecline() {
this.setState({ showModal: false });
}
render() {
return (
<View style={{ flex: 1 }}>
<Button
onPress={() => this.setState({ showModal: !this.state.showModal })}
backgroundColor={'#81A3A7'}
containerViewStyle={{ width: '100%', marginLeft: 0 }}
icon={{ name: 'search', type: 'font-awesome' }}
title='Open the confirm'
/>
<Confirm
visible={this.state.showModal}
onDecline={this.onDecline.bind(this)}
>
</Confirm>
</View>
);
}
}
export default MainActivity;
Confirm.js:
import React from 'react';
import { Text, View, Modal } from 'react-native';
import { DropDownMenu } from '#shoutem/ui';
import TestConfirm from './TestConfirm';
import { CardSection } from './CardSection';
import { Button } from './Button';
import { ConfirmButton } from './ConfirmButton';
const Confirm = ({ children, visible, onAccept, onDecline }) => {
const { containerStyle, textStyle, cardSectionStyle } = styles;
return (
<Modal
visible={visible}
transparent
animationType="slide"
onRequestClose={() => {}}
>
<View style={containerStyle}>
<CardSection style={cardSectionStyle}>
{/* Here is my DropDownMenu */}
<TestConfirm />
</CardSection>
<CardSection>
<ConfirmButton onPress={onAccept}>Yes</ConfirmButton>
<ConfirmButton onPress={onDecline}>No</ConfirmButton>
</CardSection>
</View>
</Modal>
);
};
const styles = {
cardSectionStyle: {
justifyContent: 'center'
},
textStyle: {
flex: 1,
fontSize: 18,
textAlign: 'center',
lineHeight: 40
},
containerStyle: {
backgroundColor: 'rgba(0, 0, 0, 0.75)',
position: 'relative',
flex: 1,
justifyContent: 'center'
},
buttonStyle: {
flex: 1,
alignSelf: 'stretch',
backgroundColor: '#fff',
borderRadius: 5,
borderWidth: 1,
borderColor: '#007aff',
marginLeft: 5,
marginRight: 5
}
};
export { Confirm };
TestConfirm.js
import React, { Component } from 'react';
import { View } from 'react-native';
import { DropDownMenu, Title, Image, Text, Screen, NavigationBar } from '#shoutem/ui';
import {
northCities,
centralCities,
southCities,
eastCities,
islandCities
} from './CityArray';
class TestConfirm extends Component {
constructor(props) {
super(props);
this.state = {
zone: [
{
id: 0,
brand: "North",
children: northCities
},
{
id: 1,
brand: "Central",
children: centralCities
},
{
id: 2,
brand: "South",
children: southCities
},
{
id: 3,
brand: "East",
children: eastCities
},
{
id: 4,
brand: "Island",
children: islandCities
},
],
}
}
render() {
const { zone, selectedZone, selectedCity } = this.state
return (
<Screen>
<DropDownMenu
style={{
selectedOption: {
marginBottom: -5
}
}}
styleName="horizontal"
options={zone}
selectedOption={selectedZone || zone[0]}
onOptionSelected={(zone) =>
this.setState({ selectedZone: zone, selectedCity: zone.children[0] })}
titleProperty="brand"
valueProperty="cars.model"
/>
<DropDownMenu
style={{
selectedOption: {
marginBottom: -5
}
}}
styleName="horizontal"
options={selectedZone ? selectedZone.children : zone[0].children} // check if zone selected or set the defaul zone children
selectedOption={selectedCity || zone[0].children[0]} // set the selected city or default zone city children
onOptionSelected={(city) => this.setState({ selectedCity: city })} // set the city on change
titleProperty="cnCity"
valueProperty="cars.model"
/>
</Screen>
);
}
}
export default TestConfirm;
If i console.log DropDownMenu onOptionSelected value like the city it would be
{cnCity: "宜蘭", enCity: "Ilan", id: 6}
I want to get the enCity from MainActivity.js
ConfirmButton.js:
import React from 'react';
import { Text, TouchableOpacity } from 'react-native';
const ConfirmButton = ({ onPress, children }) => {
const { buttonStyle, textStyle } = styles;
return (
<TouchableOpacity onPress={onPress} style={buttonStyle}>
<Text style={textStyle}>
{children}
</Text>
</TouchableOpacity>
);
};
const styles = {
{ ... }
};
export { ConfirmButton };
You can pass a function to related component via props and run that function with the required argument you got from the dropdowns. Because you have couple of components in a tree it is going to be a little hard to follow but if you get the idea I'm sure you'll make it simpler. Also after getting comfortable with this sort of behavior and react style coding you can upgrade your project to some sort of global state management like redux, flux or mobx.
Sample (removed unrelated parts)
class MainActivity extends Component {
onChangeValues = (values) => {
// do some stuf with the values
// value going to have 2 properties
// { type: string, value: object }
const { type, value } = values;
if(type === 'zone') {
// do something with the zone object
} else if(type === 'city') {
// do something with the city object
}
}
render() {
return(
<Confirm onChangeValues={this.onChangeValues} />
)
}
}
const Confirm = ({ children, visible, onAccept, onDecline, onChangeValues }) => {
return(
<TestConfirm onChangeValues={onChangeValues} />
)
}
class TestConfirm extends Component {
render() {
return(
<Screen>
<DropDownMenu
onOptionSelected={(zone) => {
// run passed prop with the value
this.props.onChangeValues({type: 'zone', value: zone});
this.setState({ selectedZone: zone, selectedCity: zone.children[0] });
}}
/>
<DropDownMenu
onOptionSelected={(city) => {
// run passed prop with the value
this.props.onChangeValues({type: 'city', value: city});
this.setState({ selectedCity: city })
}}
/>
</Screen>
)
}
}
I have created 5 Text programatically in react native .
I want to change the borderColor colour of view By click item.
I tried using below code .But its changing all 5 views borderColor colour .
I want change borderColor colour of only one view.
for (var i = 0; i < 4; i++) {
pills.push (this.renderPill (i));
}
renderPill (index) {
return (
<TouchableOpacity key={index} style={ this.state.status ? boxStyle : boxStyleSelected } onPress={this.itemClick.bind(this)}>
<View >
<Text>
{index}
</Text>
</View>
</TouchableOpacity>
);
}
}
multiItemClick (index) {
this.setState({ status: true });
}
boxStyle: {
borderColor: '#ffffff',
},
boxStyleSelected: {
borderColor: '#000000',
}
You should use FlatList to render your item or component list.
Here are an Example:
render() {
return (
<View style={styles.container}>
<FlatList
data={ this.state.listItem }
ItemSeparatorComponent = {this._itemSeparator}
keyExtractor={(item, index) => index}
renderItem={this._renderItem}
selected={this.state.selected}
/>
</View>
);}
Separate the item list
_itemSeparator = () => (<View style={{ height: 1, backgroundColor: "#607D8B" }}/>);
Render the Item list
_renderItem = (item) => {
return (
<TouchableOpacity
key={item.index}
style={this.state.selected == item.index ? styles.boxSelected : styles.boxStyle}
onPress={()=>this._itemClick(item)}
>
<View style={{alignItems:'center'}}>
<Text>
{item.item.key}
</Text>
</View>
</TouchableOpacity>
);}
Event on Click item to Change the Style
_itemClick(item) { this.setState({selected:item.index}) }
Data State
constructor(props){
super(props);
this.state = {
selected: null,
listItem: [
{key: 'One'},
{key: 'Two'},
{key: 'Three'},
{key: 'Four'},
{key: 'Five'},
{key: 'Six'},
{key: 'Seven'},
{key: 'Eight'},
{key: 'Nine'},
{key: 'Ten'},
{key: 'Eleven'},
{key: 'Twelve'}
]
};}
Style Sheet your item
const styles = StyleSheet.create({
container :{
justifyContent: 'center',
flex:1,
margin: 10,
paddingTop:50
},
boxStyle: {
backgroundColor: '#778788',
padding: 10,
margin:3
},
boxSelected: {
backgroundColor: 'red',
padding: 10,
margin:3
}
});
enter image description here
This is what i got for you, Hope it will save your time.
The problem is, that you are using the state for all views. Try to modify the code to something, that depends on the index you clicked.
for (var i = 0; i < 4; i++) {
pills.push (this.renderPill (i));
}
renderPill (index) {
return (
<TouchableOpacity key={index} style={ this.state.status[index] ? boxStyle : boxStyleSelected } onPress={(index) => this.itemClick(index)}>
<View >
<Text>
{index}
</Text>
</View>
</TouchableOpacity>
);
itemClick(index) {
let status = this.state;
status[index] = true;
this.setState({
status: status
})
I have not tested this, so I am not 100% sure about the syntax, but i think the idea is clear. You have to save wich item is clicked in an array, so you know what item has to be rendered with the different border.
But I also would really advice to use a FlatList here https://facebook.github.io/react-native/docs/flatlist.html Because what you are trying to do is render a clickable List. That will give you way more control over the items, their direct styling and the list container. Also you would not need to have two separate lists, but could use an array of objects like this
{
value: 1
clicked: true
}
which makes it more readable and maintainable.
edit: there is actually a code sample for a multiselect on the link provided, i adapted it to your pills. Just hand the array to the component from somewhere else. Id and title is needed. View looks like this:
Code goes like this:
export default class MyView extends React.Component {
constructor(props) {
super(props);
this.state = {
pills: [{id: 1, title: 'Pill 1'},
{id: 2, title: 'Pill 2'},
{id: 3, title: 'Pill 3'}],
};
}
render() {
const {pills} = this.state;
return (
<MultiSelectList data={pills}/>
);
}
}
class MultiSelectList extends React.PureComponent {
state = {selected: (new Map())};
_keyExtractor = (item, index) => item.id;
_onPressItem = (id) => {
// updater functions are preferred for transactional updates
this.setState((state) => {
// copy the map rather than modifying state.
const selected = new Map(state.selected);
selected.set(id, !selected.get(id)); // toggle
return {selected};
});
};
_renderItem = ({item}) => (
<MyListItem
id={item.id}
onPressItem={this._onPressItem}
selected={!!this.state.selected.get(item.id)}
title={item.title}
/>);
render() {
return (
<FlatList
data={this.props.data}
extraData={this.state}
keyExtractor={this._keyExtractor}
renderItem={this._renderItem}
/>
);
}
}
class MyListItem extends React.PureComponent {
_onPress = () => {
this.props.onPressItem(this.props.id);
};
render() {
const color = this.props.selected ? "red" : "black";
return (
<TouchableOpacity onPress={this._onPress}>
<View>
<Text style={{borderStyle: 'solid', borderWidth: 2, borderColor: color }}>
{this.props.title}
</Text>
</View>
</TouchableOpacity>
);
}
}