I have an array of items which I have retrieved from an Object. The array has 5 items. It looks like this:
I have saved the array in my state as :
this.state={
serviceDetails: planDetails[0].nbs_plans.map(service => service.extension_attributes.productServicetList.map(name=>name.name)),
}
Now, I am trying to render the array in my component using map function like :
{
this.state.serviceDetails.map((serviceName) => {
return (
<SelectableChips initialChips={serviceName} />
);
})
}
But the problem is all the arrays are coming together at the same place as shown below:
The way it should be is : The first "See more" should be at the first section, the 2nd at the 2nd and so on.
My complete code for this component looks like this:
//This is an example code for FlatList//
import React from 'react';
import {
StyleSheet, FlatList, Text, View, Alert , Image, TouchableOpacity
} from 'react-native';
import SelectableChips from '../../../components/Chip/SelectableChips';
import CheckBox from '../../../components/CheckBox';
import propTypes from 'prop-types';
import Service from './Service';
import { planDetails } from '../../../api/mockedData/PlanServiceDetails';
class Selected_Items_Array {
constructor() {
selectedItemsArray = [];
this.state = {
planName: planDetails[0].nbs_plans.map(data => data.name),
serviceDetails: planDetails[0].nbs_services.map(data => data.service_line),
};
var result = planDetails.filter(d => {
return d.nbs_plans[0].name = "TruCompleteā Lawn Care Plan";
});
// alert(Object.keys(planDetails).length);
// alert(Object.keys(planDetails[0].nbs_plans).length);
// alert(JSON.stringify(planDetails[0].nbs_plans[0].productId));
// alert(JSON.stringify(planDetails[0].nbs_plans[0].name));
// alert(JSON.stringify(planDetails[0].nbs_plans.map(data => data.name)));
}
pushItem(option) {
selectedItemsArray.push(option);
}
getArray() {
return selectedItemsArray;
}
}
export default class Services extends React.Component {
constructor(props) {
super(props);
this.state = {
// FlatListItems: [
// { id: '1', value: 'TruGreen Mosquito Defense' ,applicationType:'annual' },
// { id: '2', value: 'Sprinkler Maintenance Program' ,applicationType:'first' },
// { id: '3', value: 'Soil Treatment to balance the PH of the lawn-' ,applicationType:'priceper'},
// { id: '4', value: 'Tree & Shrub Care' ,applicationType:'customquote'},
// ],
planName: planDetails[0].nbs_plans.map(data=>data.name),
serviceDetails: planDetails[0].nbs_plans.map(service => service.extension_attributes.productServicetList.map(name=>name.name)),
};
selectedArrayOBJ = new Selected_Items_Array();
alert(JSON.stringify(planDetails[0].nbs_plans.map(data => data.name)));
alert(JSON.stringify(planDetails[0].nbs_plans[0].extension_attributes.productServicetList.map(data=> data.name)));
alert(JSON.stringify(planDetails[0].nbs_plans.map(service => service.extension_attributes.productServicetList.map(name=>name.name))));
alert(this.state.planName);
alert(this.state.serviceDetails);
}
FlatListItemSeparator = () => {
return (
//Item Separator
<View
style={{ height: 7, width: '100%', backgroundColor: 'transparent' }}
/>
);
};
GetItem(item) {
//Function for click on an item
Alert.alert(item);
}
render() {
return (
<View style={styles.MainContainer}>
<FlatList
data={this.state.planName}
//data defined in constructor
ItemSeparatorComponent={this.FlatListItemSeparator}
//Item Separator View
renderItem={({ item }) => (
// Single Comes here which will be repeatative for the FlatListItems
<View style={styles.cellContainerStyle} >
<View backgroundColor = {"transparent"} flexDirection = {'row'} justifyContent= {'flex-start'} margin={0}>
<View backgroundColor={'#73c573'} justifyContent= {'center'} alignItems={'center'} width={35} height={35} marginTop={0} paddingTop={0}>
<View backgroundColor={'#73c573'} width={25} height={25}>
<CheckBox size={25}
keyValue={1}
selectedArrayObject={selectedArrayOBJ}
checked={false}
label = ''
color="transparent"
labelColor="#00703c"
checkBoxClick={this.checkBoxOnClicked}/>
</View>
</View>
<View flex={1.75} backgroundColor={'transparent'} marginLeft={5}>
<Text style={{ color: '#00703c', fontSize: 21, fontFamily: 'SourceSansPro-Bold' }}> {item}</Text>
</View>
<View flex={0.15} marginTop={10}>
<TouchableOpacity style = {{ backgroundColor: 'transparent' }} onPress = {this.props.seeMore} >
<Image source={require('../../../assets/img/iOS/chevron_right.png')} style={styles.rightArrowImageStyle}/>
</TouchableOpacity>
</View>
</View>
<View style={styles.cellSubViewTwo}>
<Text style = {styles.textHeaderStyle}>This plan includes:</Text>
<View backgroundColor = {"transparent"} flexDirection='column' marginTop={5}>
{
this.state.serviceDetails.map((serviceName) => {
return (
<SelectableChips selectedChipStyle={selectableStyles} initialChips={serviceName} onChangeChips={(chips) => console.log(chips)} alertRequired={false} backgroundColor={"transparent"}
subView={
<TouchableOpacity style = {{ backgroundColor: 'transparent' }} onPress = {this.props.seeMore} >
<View backgroundColor={'transparent'} flexDirection = {'row'} alignItems= {'center'} marginLeft={5}>
<Text style={styles.seeMoreStyle}>See more</Text>
<Image source={require('../../../assets/img/iOS/chevron_right.png')} style={styles.rightArrowSeeMoreImageStyle}/>
</View>
</TouchableOpacity>
}/>
);
})
}
</View>
</View>
<Service serviceType={item.applicationType} isButton={false}/>
</View>
)}
/>
</View>
);
}
checkBoxOnClicked() {
if (selectedArrayOBJ.getArray().length == 0) {
//Alert.alert('CheckBox UnChecked');
} else {
// Alert.alert('CheckBox Checked');
}
}
}
Services.propTypes = { seeMore: propTypes.string.isRequired };
const styles = StyleSheet.create({
MainContainer: {
justifyContent: 'center',
margin: 7,
backgroundColor: 'transparent',
},
cellContainerStyle: {
padding: 0,
fontSize: 18,
flexDirection: 'column',
backgroundColor: '#ffffff',
borderColor: 'lightgray',
borderWidth: 0.5,
},
cellSubViewOne: {
flexDirection: 'row',
},
cellSubViewTwo: {
flexDirection: 'column',
marginLeft: 15,
backgroundColor: "#ffffff",
marginTop: 15,
},
cellSubViewThree: {
flexDirection: 'column',
marginLeft: 0,
backgroundColor: "#eff5ef",
marginTop: 15,
},
textHeaderStyle: {
color: '#73c573',
fontSize: 10.5,
fontFamily: "SourceSansPro-SemiBold",
},
rightArrowImageStyle: {
height: 12,
width: 12,
resizeMode: 'center',
alignItems: 'center',
tintColor: '#a6a6a6',
},
rightArrowSeeMoreImageStyle: {
height: 8,
width: 8,
resizeMode: 'center',
alignItems: 'center',
tintColor: '#ff9933',
},
seeMoreStyle: {
fontSize: 11,
color: '#ff9933',
fontFamily: "SourceSansPro-SemiBold",
},
});
const selectableStyles = StyleSheet.create({
chip: {
backgroundColor: '#73c573',
borderColor: '#73c573',
borderWidth: 1,
margin: 3,
padding: 0,
borderRadius: 5,
alignItems: 'center',
justifyContent: 'center',
},
valueStyle: {
color: '#ffffff',
fontSize: 12,
fontFamily: "SourceSansPro-Regular",
},
chipSelected: {
backgroundColor: '#73c573',
borderColor: '#73c573',
borderWidth: 1,
margin: 3,
padding: 0,
borderRadius: 5,
alignItems: 'center',
justifyContent: 'center',
},
valueStyleSelected: {
color: '#ffffff',
fontSize: 12,
fontFamily: "SourceSansPro-Regular",
},
});
Can someone please guide me how to proceed.
As each plan has as productServicetList, create a object serviceDetails where the key is the planName and the value is productServicetList.
this.state={
serviceDetails: planDetails[0].nbs_plans.reduce(
(acc, service) => ({
...acc,
[service.name]: service.extension_attributes.productServicetList.map(
name => name.name
)
}),
{}
);
}
Then render the serviceDetail as follows
{
this.state.serviceDetails[item].map(serviceName => {
return <SelectableChips initialChips={serviceName} />;
});
}
Related
I'm trying to make a toy stopwatch app in order to learn react-native.
I made a lap system, but it is getting way too slow when there are >15 laps. I think the poor performance point is the laps: this.state.laps.concat([d - this.state.lapTimerStart]) part, because of .concat is making a new object every time the Lap button is pressed.
I've heard that .push is way faster than .concat.
So I tried to use .push, but because .push was mutating the array, and FlatList was a PureComponent so it re-rendered only when the props have changed.
I found a way, but it was just the same as doing .concat because basically, it was
let lapArr = this.state.laps;
Array.prototype.push.apply(lapArr, [d - this.state.lapTimerStart]);
this.setState({
laps: lapArr,
})
The full code is
import React, {Component} from 'react';
import {
View,
Text,
StyleSheet,
TouchableHighlight,
FlatList,
} from 'react-native';
import {useTheme} from 'react-native-paper';
import TimeFormatter from 'minutes-seconds-milliseconds';
class Stopwatch extends Component {
constructor(props) {
super(props);
this.state = {
laps: [],
isRunning: false,
mainTimer: null,
lapTimer: null,
mainTimerStart: null,
lapTimerStart: null,
};
}
handleLapReset() {
let {isRunning, mainTimerStart, lapTimer} = this.state;
if (mainTimerStart) {
if (isRunning) {
const d = new Date();
this.setState({
lapTimerStart: d,
lapTimer: d - this.state.lapTimerStart + lapTimer,
laps: this.state.laps.concat([d - this.state.lapTimerStart]),
});
return;
}
this.state.laps = [];
this.setState({
mainTimerStart: null,
lapTimerStart: null,
mainTimer: 0,
lapTimer: 0,
});
}
}
handleStartStop() {
let {isRunning, mainTimer, lapTimer} = this.state;
if (isRunning) {
clearInterval(this.interval);
this.setState({
isRunning: false,
});
return;
}
const d = new Date();
this.setState({
mainTimerStart: d,
lapTimerStart: d,
isRunning: true,
});
this.interval = setInterval(() => {
const t = new Date();
this.setState({
mainTimer: t - this.state.mainTimerStart + mainTimer,
lapTimer: t - this.state.lapTimerStart + lapTimer,
});
}, 10);
}
_renderTimers() {
const {theme} = this.props;
return (
<View
style={[
styles.timerWrapper,
{backgroundColor: theme.colors.background},
]}>
<View style={styles.timerWrapperInner}>
<Text style={[styles.lapTimer, {color: theme.colors.text}]}>
{TimeFormatter(this.state.lapTimer)}
</Text>
<Text style={[styles.mainTimer, {color: theme.colors.text}]}>
{TimeFormatter(this.state.mainTimer)}
</Text>
</View>
</View>
);
}
_renderButtons() {
const {theme} = this.props;
return (
<View style={styles.buttonWrapper}>
<TouchableHighlight
underlayColor={theme.colors.disabled}
onPress={this.handleLapReset.bind(this)}
style={[styles.button, {backgroundColor: theme.colors.background}]}>
<Text style={[styles.lapResetBtn, {color: theme.colors.text}]}>
{this.state.mainTimerStart && !this.state.isRunning
? 'Reset'
: 'Lap'}
</Text>
</TouchableHighlight>
<TouchableHighlight
underlayColor={theme.colors.disabled}
onPress={this.handleStartStop.bind(this)}
style={[styles.button, {backgroundColor: theme.colors.background}]}>
<Text
style={[styles.startBtn, this.state.isRunning && styles.stopBtn]}>
{this.state.isRunning ? 'Stop' : 'Start'}
</Text>
</TouchableHighlight>
</View>
);
}
_renderLaps() {
return (
<View style={styles.lapsWrapper}>
<FlatList
data={this.state.laps}
renderItem={this.renderItem}
keyExtractor={this.keyExtractor}
/>
</View>
);
}
keyExtractor(item, index) {
return index.toString();
}
renderItem({item, index}) {
return (
<View style={styles.lapRow}>
<View style={styles.lapStyle}>
<View style={styles.lapBoxStyle} />
<Text style={styles.lapNumber}>{index + 1}</Text>
</View>
<View style={styles.lapStyle}>
<Text style={styles.lapTime}>{TimeFormatter(item)}</Text>
</View>
</View>
);
}
render() {
return (
<View style={styles.container}>
<View style={styles.top}>{this._renderTimers()}</View>
<View style={styles.middle}>{this._renderButtons()}</View>
<View style={styles.bottom}>{this._renderLaps()}</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {flex: 1},
timerWrapper: {
justifyContent: 'center',
flex: 1,
},
top: {
flex: 1,
},
middle: {
flex: 1,
backgroundColor: '#F0EFF5',
},
bottom: {
flex: 2,
},
mainTimer: {
fontSize: 50,
fontFamily: 'CircularStd-Medium',
alignSelf: 'center',
},
lapTimer: {
fontSize: 18,
fontFamily: 'CircularStd-Medium',
alignSelf: 'flex-end',
},
timerWrapperInner: {
alignSelf: 'center',
},
buttonWrapper: {
flexDirection: 'row',
justifyContent: 'space-around',
paddingTop: 15,
paddingBottom: 30,
},
button: {
height: 80,
width: 80,
borderRadius: 40,
backgroundColor: '#FFF',
justifyContent: 'center',
alignItems: 'center',
},
lapRow: {
flexDirection: 'row',
justifyContent: 'space-between',
height: 40,
paddingTop: 10,
},
lapNumber: {
flexDirection: 'row',
fontSize: 16,
fontFamily: 'CircularStd-Book',
color: '#777',
flex: 1,
},
lapTime: {
flexDirection: 'row',
color: '#000',
fontSize: 20,
fontFamily: 'CircularStd-Book',
flex: 1,
},
startBtn: {
color: '#0C0',
fontFamily: 'CircularStd-Book',
},
stopBtn: {
color: '#C00',
fontFamily: 'CircularStd-Book',
},
lapsWrapper: {
backgroundColor: '#ddd',
},
lapResetBtn: {
fontFamily: 'CircularStd-Book',
},
lapStyle: {
width: '40%',
flexDirection: 'row',
},
lapBoxStyle: {
flexDirection: 'row',
flex: 1,
},
});
export default function StopwatchScreen(props) {
const theme = useTheme();
return <Stopwatch {...props} theme={theme} />;
}
I tried not to use arrow functions, many news, but it didn't help that much.
FlatList is a pure component and it is mandatory to give new ref of data prop to render list . You should use concat but it created new object.
i think the main issue is renderItem.
create a separate PureComponent to avoid re-rendeing of items
class Item extends PureComponent {
const {item,index} = this.props;
return (
<View style={styles.lapRow}>
<View style={styles.lapStyle}>
<View style={styles.lapBoxStyle} />
<Text style={styles.lapNumber}>{index + 1}</Text>
</View>
<View style={styles.lapStyle}>
<Text style={styles.lapTime}>{TimeFormatter(item)}</Text>
</View>
</View>
);
}
and use in render item
renderItem({item, index}) {
return (
<Item item={item} index={index} />
);
}
I am using react-native-simple-picker in my app which works fine in my project if I use the default show button but I would like to show the picker when I use a different button in my project. It looks like this.refs.picker.show() in ProposalPicker.js is the function that needs to be called, but I am not sure how to access this from another component file. Currently my code results in the following error - `Cannot read property 'show' of undefined. Appreciate any help.
ProposalPicker.js
import React, { Component } from 'react';
import { Picker, View, Text } from 'react-native';
import Button from './Button';
import SimplePicker from 'react-native-simple-picker';
const options = ['Option1', 'Option2', 'Option3'];
// Labels is optional
const labels = ['Banana', 'Apple', 'Pear'];
class ProposalPicker extends Component {
constructor(props) {
super(props);
this.state = {
selectedOption: '',
};
}
render() {
return (
<View style={styles.container}>
<Text style={styles.paragraph}>Current Option: {this.state.selectedOption}</Text>
<Text
style={{ color: '#006381', marginTop: 20 }}
onPress={() => {
this.refs.picker.show();
}}
>
Click here to select your option
</Text>
<Text
style={{ color: '#006381', marginTop: 20 }}
onPress={() => {
this.refs.picker2.show();
}}
>
Click here to select your option with labels
</Text>
<SimplePicker
ref={'picker'}
options={options}
onSubmit={(option) => {
this.setState({
selectedOption: option,
});
}}
/>
<SimplePicker
ref={'picker2'}
options={options}
labels={labels}
itemStyle={{
fontSize: 25,
color: 'red',
textAlign: 'left',
fontWeight: 'bold',
}}
onSubmit={(option) => {
this.setState({
selectedOption: option,
});
}}
/>
</View>
);
}
}
// class ProposalPicker extends Component {
// state={proposal: ''}
// selectedValue = '';
// updateProposal = (proposal) => {
// this.setState({ proposal: this.selectedValue });
// }
// handleConfirmClick = () => {
// this.setState({ proposal: this.selectedValue });
// }
// render() {
// return (
// <View>
// <Picker selectedValue = {this.selectedValue}
// onValueChange = {this.updateProposal}
// itemStyle={{ backgroundColor: 'grey' }}
// >
// <Picker.Item label = "Test" value = "TestValue1" />
// <Picker.Item label = "Test 1" value = "TestValue2" />
// <Picker.Item label = "Test" value = "TestValue3" />
// <Picker.Item label = "Test" value = "TestValue4" />
// <Picker.Item label = "Test" value = "TestValue5" />
// <Picker.Item label = "Test" value = "TestValue6" />
// <Picker.Item label = "Test" value = "TestValue7" />
// <Picker.Item label = "Test" value = "TestValue8" />
// <Picker.Item label = "Test nothing" value = "TestValue9" />
// </Picker>
// <Text style = {styles.textStyle}>CONFIRM</Text>
// </View>
// )
// }
// }
const styles = {
proposalPickerStyle: {
backgroundColor: 'lightgrey'
},
textStyle: {
flex: 1
}
}
export default ProposalPicker;
ProposalPickerButton.js
import React from 'react';
import { View, Text, Image, TouchableOpacity } from 'react-native';
const PickerButton = ({ onPress, text }) => {
const { textStyle, iconStyle, iconContainerStyle, textContainerStyle, buttonStyle } = styles;
return (
<TouchableOpacity onPress={onPress} style={buttonStyle}>
<View style={styles.containerStyle}>
<View style={iconContainerStyle}>
<Image
style={iconStyle}
source={require('./images/201.png')}
/>
</View>
<View style={textContainerStyle}>
<Text style={textStyle}>{text}</Text>
</View>
<View style={iconContainerStyle}>
<Image
style={iconStyle}
source={require('./images/201.png')}
/>
</View>
</View>
</TouchableOpacity>
);
}
const styles = {
containerStyle: {
flex: 1,
//backgroundColor: 'red',
borderWidth: 2,
borderRadius: 0,
borderColor: '#FFFFFF',
//shadowColor: '#000',
//shadowOffset: { width: 0, height: 2 },
//shadowOpacity: 0.1,
//shadowRadius: 2,
//elevation: 1,
marginLeft: 40,
marginRight: 40,
marginTop: 10,
marginBottom: 10,
justifyContent: 'center',
alignItems: 'center',
flexDirection: 'row'
},
iconContainerStyle: {
flex: 2,
//backgroundColor: 'blue',
justifyContent: 'center',
//alignItems: 'center',
//width: '20%',
//height: '20%'
},
iconStyle: {
flex: 1,
width: null,
height: null,
resizeMode: 'contain',
marginLeft: 10,
marginRight: 10,
marginTop: 10,
marginBottom: 10
},
textContainerStyle: {
flex: 8,
//backgroundColor: 'orange',
alignItems: 'flex-start',
justifyContent: 'center',
},
textStyle: {
fontSize: 20,
fontWeight: 'bold',
color: '#FFFFFF',
//marginLeft: 10
//padding: 18
},
buttonStyle: {
width: '100%',
height: '100%'
}
};
export default PickerButton;
App.js
import React, { Component } from 'react';
import { View, Text, ImageBackground } from 'react-native';
import Logo from './Logo';
import ProposalPickerButton from './ProposalPickerButton';
import Button from './Button';
import ProposalPicker from './ProposalPicker';
import SimplePicker from 'react-native-simple-picker';
class App extends Component {
render() {
return (
<ImageBackground
source={require('./images/city.png')}
style={styles.backgroundStyle}
>
<View style={styles.backgroundOverlayStyle} />
<View style={styles.container}>
<View style={styles.logoContainer}>
<Logo />
</View>
<View style={styles.proposalPickerButtonStyle}>
<ProposalPickerButton
onPress={() => new ProposalPicker().refs.picker.show()}
// onPress={() => console.log('Proposal picker button pressed')}
//onPress={() => Linking.openURL(url)}
text="Select a service line"
/>
</View>
<View style={styles.startProposalButtonStyle}>
<Button text="Start proposal"/>
</View>
<View style={styles.proposalPickerStyle}>
{/* <ProposalPicker /> */}
</View>
</View>
</ImageBackground>
);
}
}
const styles = {
backgroundStyle: {
flex: 1,
backgroundColor: '#000000',
width: '100%',
height: '100%',
position: 'absolute'
},
backgroundOverlayStyle: {
flex: 1,
position: 'absolute',
backgroundColor: '#003284',
opacity: 0.5,
width: '100%',
height: '100%'
},
container: {
//backgroundColor: 'red',
flex: 1,
//opacity: 0.5,
alignItems: 'center',
width: '100%',
height: '65%',
},
logoContainer: {
//backgroundColor: 'blue',
flex: 3,
alignItems: 'center',
justifyContent: 'center',
width: '100%',
height: '65%',
},
proposalPickerButtonStyle: {
flex: 1,
//backgroundColor: 'yellow',
alignItems: 'center',
justifyContent: 'center',
width: '100%',
height: '100%',
marginLeft: 100,
marginRight: 100
},
startProposalButtonStyle: {
flex: 1,
//backgroundColor: 'purple',
width: '100%',
height: '100%',
marginTop: 10,
marginRight: 80
},
proposalPickerStyle: {
opacity: 1,
flex: 2,
backgroundColor: 'green',
width: '100%',
height: '100%'
},
};
export default App;
To call methods via refs you need to have a ref assigned to an already mounted component. Therefore you can't say new ProposalPicker().refs.picker.show() because refs.picker does not exist until the component is mounted. You Should have your button and picker components in the same parent, that way you can easily create a ref in that parent, assign it, and call methods from it:
Also you should use callback refs instead of string refs because string refs are deprecated. In that case it would look like:
constructor(props){
super(props)
this.state = ...
this.picker = React.createRef() // make the ref
}
Then assign the ref:
<SimplePicker
ref={this.picker}
And then you can make an function to call when your button is pressed:
showPicker = () => {
if (this.picker.current) {
this.picker.current.show()
}
}
I am running sample project. I want to display the increment and decrement values. In my project increment and decrement values are not displayed. How to change the values in text.
Here is my code:
constructor(props){
super(props);
this.state={
increment:0,
decrement:1
}
}
incrementFunc(){
var countIncrement = this.state.increment
this.setState({
increment : countIncrement + 1
},()=>{
alert(this.state.increment)
})
}
decrementFunc(){
var countDecrement = this.state.increment
this.setState({
decrement : countDecrement- 1,
},()=>{
alert(this.state.decrement)
})
}
<View style={styles.arrowsView}>
<TouchableOpacity onPress ={this.incrementFunc.bind(this)}>
<Image style={styles.arrowStyle} source={require('#images/up-arrow.png')} />
</TouchableOpacity>
</View>
<View style={styles.numberView}>
<Text style={{fontSize:15, color:'black'}}>{this.state.increment}
</Text>
</View>
<View style={styles.arrowsView}>
<TouchableOpacity onPress ={this.decrementFunc.bind(this)}>
<Image style={styles.arrowStyle} source={require('#images/down-arrow.png')} />
</TouchableOpacity>
</View>
here is my screenshot:
Please give any suggestion. Thank You
Here is the solution which i had made in my project , what i did
Firstly ->created an another component which will help us to have a quantity input functionality inside list element
Secondly ->This component needs to be called by the parent component inside list renderRow to make this component visible in all the rows.
and put this QuantityInput component class inside the same file where you want to use it...
Thirdly -> Run yours application and have a look like this...
Have a look to the file attached...
/*Use this component in yours parent view inside list to have a Quantity Input inside list , I have used native base as well if some thing gets miss please have native base in yours project...*/
{<QuantityInput item={this.state.data[rowID]} viewAddToCart={false} />}
/* QuantityInput */
class QuantityInput extends React.Component {
userProductQty = Array.apply(null, Array(this.props.item.length)).map(Number.prototype.valueOf, 1);
itemPosition = -1;
constructor(props) {
super(props);
this.state = {
viewAddToCart: this.props.viewAddToCart,
item: this.props.item,
style: { flex: 1 },
styleTextInput: { backgroundColor: '#ffffff' },
styleButton: { backgroundColor: '#000000' },
styleImage: { width: 12, height: 12 },
editable: true,
stepsize: 1,
initialValue: 1,
min: 1,
max: 100
}
}
upBtnPressed = (dataSource, fieldName) => {
if (dataSource.userQty < this.state.max) {
let value = (parseInt(dataSource.userQty) + parseInt(this.state.stepsize)).toString();
dataSource.userQty = value;
this.setState({
item: dataSource
});
}
}
downBtnPressed = (dataSource, fieldName, props) => {
if (dataSource.userQty < this.state.min) {
let value = (parseInt(dataSource.userQty) - parseInt(this.state.stepsize)).toString();
dataSource.userQty = value;
this.setState({
item: dataSource
});
}
}
onChangeText = (text, item, fieldName, itemPosition) => {
if (!isNaN(text)) {
item.userQty = text.toString();
this.setState({
item: item
});
} else {
item.userQty = 0;
this.setState({
item: item
});
}
}
render() {
return (
this.state.viewAddToCart ?
/* Add to cart */
<View style={[{ flexDirection: 'row' }]}>
<Left style={{ flex: 0 }}>
<Button rounded danger
title="Add"
color="white"
style={[{ width: 70 }, { height: 30 }, { justifyContent: 'center' }]}
onPress={() => { this.props.onAddToCart(this.state.item); this.setState({ viewAddToCart: false }) }}
>
<Text style={[{ color: 'white' }]}>{string.addToCart}</Text>
</Button>
{/*</TouchableOpacity>*/}
</Left>
</View>
:
/* Quantity Text */
<View style={{ flexDirection: 'row' }}>
<View style={stylesQuantityText.verticle}>
<TouchableOpacity style={[styles.button, styles.transparentBkg, { backgroundColor: '#d9534f' }, { paddingLeft: 10 }, { borderTopLeftRadius: 5 }, { borderBottomLeftRadius: 5 }, { justifyContent: 'center' }, { alignItems: 'center' }]} onPress={() => { this.downBtnPressed(this.state.item, this.state.item.productId); }} >
<Text style={[{ width: 20 }, { height: 26 }, { fontSize: 21 }, { alignSelf: 'center' }, { paddingBottom: 10 }, { fontWeight: 'bold' }]}>-</Text>
{/*<Icon name={"remove"} />*/}
</TouchableOpacity>
<TextInput
style={[stylesQuantityText.textinput, this.state.styleTextInput]}
editable={this.state.editable}
keyboardType={'numeric'}
text={this.state.item.userQty.toString()}
value={this.state.item.userQty.toString()}
ref={"Qty" + this.state.item.productId}
key={"Qty" + this.state.item.productId}
onChangeText={(text) => { this.onChangeText(text, this.state.item, this.state.item.productId); this.props.onAddToCart(this.state.item); }} />
<TouchableOpacity style={[styles.button, styles.transparentBkg, { backgroundColor: '#d9534f' }, { paddingLeft: 10 }, { borderTopRightRadius: 5 }, { borderBottomRightRadius: 5 }]} onPress={() => { this.upBtnPressed(this.state.item, this.state.item.productId); this.props.onAddToCart(this.props.item); }}>
{/*<Icon name={"add"}
size={27} />*/}
<Text style={[{ width: 20 }, { height: 26 }, { fontSize: 19 }, { alignSelf: 'center' }]}>+</Text>
</TouchableOpacity>
</View>
</View>
);
}
}
const stylesQuantityText = StyleSheet.create({
wrapper: {
flex: 1,
backgroundColor: '#eeeeee'
},
verticle: {
flexDirection: 'row',
paddingLeft: 0,
paddingRight: 0,
},
horizontal: {
flexDirection: 'row'
},
textinput: {
backgroundColor: '#eeeeee',
textAlign: 'center',
width: 30,
borderColor: 'black',
borderWidth: 1,
height: 26
},
button: {
backgroundColor: '#dedede',
padding: 5
},
image: {
width: 18,
height: 18
},
buttonText: {
alignSelf: 'center'
}
});
]1
I am learning react native for the first time for developing android app not IOS one and I was learning from Building a Simple ToDo App With React Native and Firebase tutorial from youtube.But I am getting an error while trying to add items. I get following error
Firebase.push failed: first argument contains an invalid key($$typeof) in property 'restaurant.restaurant_name.targetInst._nativeParent._currentElement'.keys must be non-empty strings and cant contain ".","#","$","/","["
What might be creating this issue?
import React, { Component } from 'react';
import Firebase from 'firebase';
import {
AppRegistry,
StyleSheet,
Text,
View,
TouchableHighlight,
TextInput,
ListView
} from 'react-native';
class foodOrderSystem extends Component {
constructor(props){
super(props);
const firebaseRef = new Firebase('foodordersystem.firebaseio.com');
console.log(firebaseRef);
this.itemRef = firebaseRef.child('restaurant');
this.state = {
newRestaurant:'',
// estimated_delivery:'',
// description:'',
restaurantSource: new ListView.DataSource({rowHasChanged: (row1,row2) => row1 !== row2})
};
this.restaurant = [ ];
}
componentDidMount() {
this.itemRef.on('child_added', (snap) => {
this.restaurant.push({
id:snap.key(),
text:snap.val()
});
this.setState({
restaurantSource:this.state.restaurantSource.cloneWithRows(this.restaurant)
});
});
this.itemRef.on('child_removed', (snap) => {
this.restaurant = this.restaurant.filter((x) => x.id !== snap.key());
this.setState({
restaurantSource:this.state.restaurantSource.cloneWithRows(this.restaurant)
});
});
}
addRestaurant(){
if(this.state.newRestaurant !== ''){
this.itemRef.push({
restaurant_name: this.state.newRestaurant
});
this.setState({ newRestaurant:''});
}
}
removeRestaurant(rowData){
this.itemRef.child(rowData.id).remove();
}
render() {
return (
<View style={styles.appContainer}>
<View style={styles.titleView}>
<Text style={styles.titleText}>
foodOrderSystem
</Text>
</View>
<View style={styles.inputcontainer}>
<TextInput
style={styles.input}
onChange={(text) => this.setState({newRestaurant:text})}
value={this.state.newRestaurant} />
<TouchableHighlight
style={styles.button}
onPress={ () => this.addRestaurant() }
underlayColor="#00ffff">
<Text style={styles.btnText}>Add</Text>
</TouchableHighlight>
</View>
<ListView
dataSource={this.state.restaurantSource}
renderRow={this.renderRow.bind(this)} />
</View>
);
}
renderRow(rowData){
return(
<TouchableHighlight
underlayColor="#dddddd"
onPress={() => this.removeRestaurant(rowData)}>
<View>
<View style={styles.row}>
<Text style={styles.todoText}>{rowData.text}</Text>
</View>
<View style={styles.separator} />
</View>
</TouchableHighlight>
);
}
}
const styles = StyleSheet.create({
appContainer:{
flex: 1
},
titleView:{
backgroundColor: '#48afdb',
paddingTop: 30,
paddingBottom: 10,
flexDirection: 'row'
},
titleText:{
color: '#fff',
textAlign: 'center',
fontWeight: 'bold',
flex: 1,
fontSize: 20,
},
inputcontainer: {
marginTop: 5,
padding: 10,
flexDirection: 'row'
},
button: {
height: 36,
flex: 2,
flexDirection: 'row',
backgroundColor: '#48afdb',
justifyContent: 'center',
color: '#FFFFFF',
borderRadius: 4,
},
btnText: {
fontSize: 18,
color: '#fff',
marginTop: 6,
},
input: {
height: 36,
padding: 4,
marginRight: 5,
flex: 4,
fontSize: 18,
borderWidth: 1,
borderColor: '#48afdb',
borderRadius: 4,
color: '#48BBEC'
},
row: {
flexDirection: 'row',
padding: 12,
height: 44
},
separator: {
height: 1,
backgroundColor: '#CCCCCC',
},
todoText: {
flex: 1,
},
});
AppRegistry.registerComponent('foodOrderSystem', () => foodOrderSystem);
Here is the attachment of error
I am new to react native. And I would like to create dynamic color of my application on the basis of selection.
/**
* Sample React Native App
* https://github.com/facebook/react-native
* #flow
*/
import React, {
AppRegistry,
Component,
StyleSheet,
Text,
Image,
NavigatorIOS,
AlertIOS,
ListView,
ScrollView,
TouchableHighlight,
View
} from 'react-native';
import {
times,
uniqueId
} from 'lodash';
var Accordion = require('react-native-accordion/src/index.js');
var my = '#eee';
class AwesomeProject extends Component {
render() {
return (
<View style = {styles.group} >
<NavigatorIOS style = {styles.group}
initialRoute = {{
component: AccordionList,
title: 'Color Selector',
rightButtonIcon: require('./img/a.png'),
onRightButtonPress: () => {
AlertIOS.alert(
'Select Color',
null, [{
text: 'Red',
onPress: () =>setColor( 'red'),
}, {
text: 'Blue',
onPress: () => setColor( 'blue'),
}]
);
}
}
}
barTintColor = "#0391D7"
titleTextColor = "#fff"
tintColor = '#fff' />
<View style = {styles.line}/>
</View>
);
}
}
setColor = function(color){
if(color == 'blue')
my = '#eee';
else
my = '#aaa';
}
const AccordionList = React.createClass({
getInitialState() {
const ds = new ListView.DataSource({
rowHasChanged: (r1, r2) => r1 !== r2
});
return {
dataSource: ds.cloneWithRows(times(6, uniqueId.bind(null, 'ball_'))),
};
},
render() {
return (
<View style = {{flex: 1}} >
<ListView dataSource = {this.state.dataSource}
renderRow = {this._renderRow}
/>
</View>
);
},
_renderHeader() {
return ( <View style = { styles.listView } >
<Image style = {styles.icon}
source = {require('./img/1.jpg')}/>
<Text> Click to Expand {my}< /Text>
</View>
);
},
_renderContent() {
return ( <View style = {styles.container} >
<Text style = {styles.welcome} >
{
'greeting'
}
Welcome to React Native!
</Text>
<Text style = {
styles.instructions
} >
To get started, edit index.ios.js
</Text>
<Text style = {
styles.instructions
} >
Press Cmd + R to reload, {
'\n'
}
Cmd + D or shake
for dev menu
</Text>
</View>
);
},
_renderRow(rowData) {
return ( <Accordion header = {
this._renderHeader()
}
content = {
this._renderContent()
}
duration = {
300
}
easing = "easeOutCubic" />
);
}
});
const styles = StyleSheet.create({
icon: {
height: 20,
width: 20,
alignItems: 'flex-end',
borderWidth: 1
},
listView: {
alignItems: 'flex-end',
paddingTop: 15,
paddingRight: 15,
paddingLeft: 15,
paddingBottom: 15,
borderBottomWidth: 1,
borderBottomColor: my,
backgroundColor: my,
},
line: {
backgroundColor: '#bbbbbb',
height: StyleSheet.hairlineWidth,
},
container: {
flex: 1,
borderWidth: 1,
justifyContent: 'center',
alignItems: 'flex-end',
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
instructions: {
textAlign: 'center',
color: '#3333f3',
marginBottom: 5,
},
group: {
backgroundColor: 'white',
flex: 1
},
groupSpace: {
height: 15,
padding: 10
},
});
const styles_a = StyleSheet.create({
icon: {
height: 30,
width: 30
},
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
line: {
backgroundColor: '#bbbbbb',
height: StyleSheet.hairlineWidth,
},
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
instructions: {
textAlign: 'center',
color: '#3333f3',
marginBottom: 5,
},
listView: {
alignItems: 'flex-start',
paddingTop: 15,
paddingRight: 15,
paddingLeft: 15,
paddingBottom: 15,
borderBottomWidth: 1,
borderBottomColor: my,
backgroundColor: '#fafafa',
},
group: {
backgroundColor: 'white',
flex: 1,
padding: 10
},
groupSpace: {
height: 15,
padding: 10
},
});
AppRegistry.registerComponent('AwesomeProject', () => AwesomeProject);
Whenever I select a new color and alert it, it shows me the color selection but, doesn't update the background color of my list.
Any idea what I am doing wrong.
Try this:
Instead of storing the color in a global variable, you should store it in the component's state. If you don't know what state means in React, consider reading this article.
I see you call a setColor function to change the variable my. Instead you could call
this.setState({currentColor: 'red'})
and then in a render() method, you could append it to an array to overwrite the default style:
<SomeComponent style={[styles.myStyle, {backgroundColor: this.state.currentColor}]}/>
The point of doing this is that setState triggers a new UI rendering.