react-native : How to render check box inside flatlist - javascript

I created a checkbox inside my flatlist but when I click on the checkbox all the check boxes will render. I want to render the checkbox I press not the entire checkboxes.
This is my code:
const list = [
{
name: 'Kevin',
id:0
},
{
name: 'John',
id:1
},
]
export default class TestingScreen extends Component {
constructor(props) {
super(props)
this.state = {
checked: false
}
}
handleCheckBox = () => this.setState({ checked: !this.state.checked })
renderItem = ({ item }) => (
<ListItem
title={<View><Text>{item.name}</Text></View>}r
leftAvatar={
<View>
<Image
style={{width:50, height:50,borderRadius:25 }}
source={require('../Components/Assets/oval.png')} />
</View>
}
rightAvatar={
<CheckBox
checked={this.state.checked}
onPress={() => this.setState({checked: !this.state.checked})}
/>
}
>
</ListItem>
)
render() {
return(
<View style={styles.container}>
<FlatList
keyExtractor={this.keyExtractor}
data={list}
renderItem={this.renderItem}
extraData={this.state}
/>
</View>
)
};
}
Is there a way I could just render the checkbox I pressed?
Any comments or advise would be really helpful thanks! :)

You are using the same state variable for all your checkboxes. Clicking on one of the checkboxs will update the single global variable checked you gave to all checkboxes.
You have to either create a checkBox component with his own state or update a variable inside the list you are using to render the different items.
For example:
1)Move your list variable inside the state adding a checked key:
const list = [
{
name: 'Kevin',
id:0,
checked:false
},
{
name: 'John',
id:1,
checked:false
},
]
this.state = {
list: list
}
2) Use the state into the flatList data:
<FlatList
keyExtractor={this.keyExtractor}
data={this.state.list}
renderItem={this.renderItem}
extraData={this.state}
/>
3) Change the onPress of the checkBox:
<CheckBox
checked={this.state.list[item.id].checked}
onPress={() => this.checkThisBox(item.id)}
/>
where:
checkThisBox=(itemID)=>{
let list=this.state.list
list[itemID].checked=!list[itemID].checked
this.setState({list:list})
}

save the item.id in the state when triggering onPress
Example :
this.state = {
checked : null
}
then in your checkbox :
<CheckBox
checked={this.state.checked === item.id}
onPress={() => this.setState({checked: item.id})}
/>
OR
you can do it like
this.state = {
list: list,
},
then in your flatlist
<FlatList
keyExtractor={this.keyExtractor}
data={this.state.list}
renderItem={({item, index}) =>
<ListItem>
<Left>
<Text>{item.name}</Text>
</Left>
<Right>
<CheckBox
checked={item.checked}
onPress={() => this.onCheck(item,index)}
/>
</Right>
</ListItem>
}
extraData={this.state}
/>
oncheck function
onCheck = (item, i) => {
let items = this.state.list;
items[i].checked = items[i].checked ? ! items[i].checked : true
this.setState({list:items})
}

Related

How to add an attribute or change style of a button onPress react native - native base

I have a list with some items that are added to a state on click, Im using native-base, how can I change the style of the listitem when I press it, or add the "selected" attribute to the list item?
code
const [data, setData] = useState([]);
const _renderItem = ({ item, index }) => {
return (
<ListItem
button={true}
onPress={() => handleItemSelect(item)}
>
<Left>
<Text>{item.Name}</Text>
</Left>
<Right>
<Icon name="add" style={{ paddingHorizontal: 5 }} />
</Right>
</ListItem>
);
};
return(
<Container>
<List>
<FlatList
data={data}
renderItem={_renderItem}
/>
</List>
</Container>
);
Im wondering how am I going to add a style and distinguish between the different list items that I have, if this isn't possible how can I use native-base "selected" and append it to the listitem?
the handleItemSelect adds the item id to a state so im currently managing which items are selected, how can I use this info, or any other way to highlight the selected items?
Edit:
I figured how to easily do this since I have the selected items id's
<ListItem
selected={selectedItems.some((prevItem) => prevItem._id === item._id)}
style={sameasabove ? style1 : style2}
button={true}
onPress={() => handleItemSelect(item)}
>
</ListItem>
You can do some thing like this:
Example
export default class App extends React.Component {
constructor() {
super();
this.state = {
data: [
{ name: "Interstellar" },
{ name: "Dark Knight" },
{ name: "Pop" },
{ name: "Pulp Fiction" },
{ name: "Burning Train" },
],
setData: []
};
for (var i = 0; i < this.state.data.length; i++) {
this.state.setData[i] = "red";
}
this.setState({
setData: this.state.setData
})
}
handleItemSelect(item, index) {
this.state.setData[index] = "green";
this.setState({
setData: this.state.setData
})
}
renderItem = ({ item, index }) => {
return (
<ListItem button={true}
onPress={() => this.handleItemSelect(item, index)} style={{ marginLeft: 0 }}>
<Body>
<Text style={{ color: this.state.setData[index] }}>{item.name}</Text>
</Body>
</ListItem>
);
};
render() {
return (
<FlatList style={{ marginTop: 30 }}
data={this.state.data}
renderItem={this.renderItem}
/>
);
}
}
You can set a color to your ListItem initially and then you can change the color on a click event.
Hope this helps!

How do I toggle between items in a FlatList?

I added a custom radio button to each of my flatlist items. So there's a radio button on the left of each item row and I want to be able to toggle between the selected value of the radio button depending on row item. So, I can select the first row item and that's selected/toggled on or select the second one item and that's toggled on and the first row item is toggled off.
I'm a bit confused on how to set up the logic for this with my current object. My current object has an id and isSelected bool. The bool will indicate if the row is isSelected or not (i.e. is checked or not).
Here's what i have so far:
This is my component that renders the flatlist fooItems. The fooItems itself is the individual elements that make up the list.
export class FooItemsComponent extends Component {
constructor(props) {
super(props);
}
async componentDidMount() {
//some reducer action
}
renderItem = item => {
if (item.load) {
return <ActivityIndicator color={Colors.activityColor} size="small" />;
} else {
return (
<View>
<FooItem
{...item}
navigation={this.props.navigation}
showParticularItems={true}
/>
</View>
); }
};
render() {
const { fooItems, navigation, loading, props} = this.props;
if (!fooItems) fooItems = [];
return (
<View style={styles.container}>
<FlatList
keyExtractor={(item, index) => `key-${index}`}
data={fooItems}
renderItem={item => this.renderItem(fooItems.item)}
ItemSeparatorComponent={Separator}
ListHeaderComponent={Header}
ListFooterComponent={loading ? LoadingFooter : Separator}
/>
</View>
);
}
}
FooItem component:
export default class FooItem extends Component {
constructor(props) {
super(props);
this.state = {
isSelected: this.props.fooItems.isSelected
};
}
changeSelected = isSelected => {
if(!isSelected) {
let selected = this.props.fooItems;
selected = selected.isSelected = true;
this.setState({ isSelected: selected});
}
};
render() {
const {
Details,
showPreferred = false,
showSetSelected = false,
navigation
} = this.props;
const { isSelected} = this.state;
return (
<View
style={[ showSetSelected? styles.setDefaultContainer :
styles.container,
showBorder ? { borderBottomWidth: 1, borderTopWidth: 1 } : {},
]}
>
{showSetSelected && (
<View>
<TouchableOpacity
style={[styles.info, !isSelected ? styles.lineBreak : {}]}
onPress={() => this.changeSelected(isSelected)}
>
<RadioButton isChecked={isSelected}></CheckedCircle>
</TouchableOpacity>
</View>
)}
</View>
);
}
}
My custom control:
const RadioButton = ({ isChecked }) => {
let checkedStatus;
switch (isChecked) {
case true:
checkedStatus = <Image style={styles.container} source={require('../../../assets/radioButton.png')} />
break
default:
checkedStatus = <Image style={styles.container} source={require('../../../assets/circle.png')} />
break
}
return <View style={styles.container}>{checkedStatus}</View>
}
Right now, I'm noticing the other row that is not already selected and I select it, the radio button state for that particular row is checked but now I have two checked/selected rows instead of one. So I want to know how to toggle the other row. How can I get this done?
EDIT:
Example of radio button toggle in a list where I only want to toggle between listed radio buttons between rows of the list.
Maintain a state variable such as selectedIndex or some unique id in your FooItemsComponent and pass this index/id to each of your FooItem and compare against this selectedIndex as
<RadioButton
isChecked={item.id === this.props.selectedIndex}
/>
Maintain a method at FooItemsComponent level which controls which item is checked as follows
changeSelected = index => {
this.setState({
selectedIndex: index,
});
};
and pass the same to every FooItem
<FooItem
{...item}
...
selectedIndex={this.state.selectedIndex}
changeSelected={this.changeSelected}
/>
and finally in the FooItem put this on a Touchable and pass the FooItem's id or index.
<TouchableOpacity onPress={() => this.props.changeSelected(item.id)}>
Here is a expo link for rough idea.(Please ignore the styles and make it truly yours!)
You need to keep track of which FooItem is selected in the state of your FooItemsComponent.
Then use that to check
<FooItem
{...item}
isSelected={this.state.selectedItem.id === item.id}
navigation={this.props.navigation}
showParticularItems={true}
/>
Or something in this fashion.

React Native highlight items and return indexes alert

I have json and i render items with flatlist component. I have component "TouchableOpacity" and I need to highlight some items from flatlist. After highlighting I need display choosen items IDs to alert after I press button. Can someone help me with this issue?
export default class Grid extends Component {
constructor(props) {
super(props)
this.state = {
selectId: [],
countIds: 0,
}
}
renderItem = ({item}) => {
return(
<View style={styles.container}>
<TouchableOpacity onPress={() => this.highlightItem(item.id)} style={this.state.selectId === item.id ? styles.selected : null}>
<View style={styles.viewContainer}>
<Image source={{uri: item.imageUrl}} style={styles.imageContainer}/>
<Text>{item.name}</Text>
</View>
</TouchableOpacity>
</View>
)
}
highlightItem = (id) => {
console.log(id)
this.setState({
selectId: [...this.state.selectId, " " + id],
countIds: this.state.selectId.length + 1
})
}
selectedItems = () => {
Alert.alert(
'Data alert',
`Count of items: ${this.state.countIds} \nIDs items selected: ${this.state.selectId}`,
[
{
text: 'Cancel',
onPress: () => console.log('Cancel Pressed'),
},
{
text: 'OK',
onPress: () => console.log('OK Pressed')
},
],
{cancelable: false},
)
}
render() {
return(
<View>
<FlatList
data={dataSource}
extraData={this.state.selectId}
renderItem={this.renderItem}
keyExtractor={(item, index) => index.toString()}
numColumns={columnNumber}
ListFooterComponent={this.renderButton}
/>
</View>
)
}
}

How to pass the props from parent to child to child of child?

I want to pass the props from App.js(parent) to CommentItem.js(child) to Button.js(child of child),
but the props is empty in Button,js(child of child)'s component.
App.js(parent) to CommentItem.js(child)
I pushed mainuser: this.state.head to FlatList, and the props(mainuser) passed by renderItem={({ item }) => <CommentItem {...item}
And, CommentItem.js(child) received mainuser by the code below.
const {
head,
text,
created,
mainuser,
subuser,
} =
CommentItem.js(child) to Button.js(child of child)
I thought props was pased to Button by ,
and Button(child of child) received the props by the code below.
const {
mainuser,
} = this.props;
However, props id empty in Button.js(child of child).
#
Are there any problems of my code?
Could you give some advice please?
App.js(parent)
export default class App extends Component<{}> {
constructor(props) {
super(props);
this.state = {
head: [],
list: [],
};
}
_onPress = (text) => {
const list = [].concat(this.state.list);
list.push({
key: Date.now(),
text: text,
done: false,
mainuser: this.state.head,
});
this.setState({
list,
});
}
render() {
const {
head,
list,
} = this.state;
var data = [["User1", "User2", "User3"],];
return (
<View style={styles.container}>
<View style={styles.dropdownHeader}>
<View style={styles.dropdown}>
<DropdownMenu
style={{flex: 1}}
bgColor={'white'}
tintColor={'#666666'}
activityTintColor={'green'}
handler={(selection, row) => this.setState({head: data[selection][row]})}
data={data}
>
</DropdownMenu>
</View>
</View>
<Text>To Do</Text>
<View style={styles.postinput}>
<CommentInput onPress={this._onPress} />
</View>
</View>
<View style={styles.CommentListContainer}>
<FlatList
/*inverted*/
style={styles.CommentList}
data={list}
renderItem={({ item }) => <CommentItem {...item} /> }
/>
</View>
);
}
}
CommentItem.js(child)
const CommentItem = (props) => {
const {
head,
text,
created,
mainuser,
subuser,
} = props;
return (
<View style={styles.container}>
<View style={styles.left}>
<Text style={styles.text}>{text}</Text>
</View>
<View style={styles.function}>
<Button {...mainuser} />
</View>
</View>
);
}
Button.js(child of child)
export default class ApplauseButton extends Component {
constructor(props) {
super(props);
this.state = {
};
}
render() {
const {
mainuser,
} = this.props;
return (
<View style={styles.container}>
<Text>{mainuser}</Text>
</View>
);
}
}
If you want to access mainuser as a prop, then you've to pass it as <Button mainuser={mainuser} />.
As it stands, you're spreading the contents of mainuser.
as per your code it seems that main user is array,
this.state = {
head: [],//array
list: [],
};
....
list.push({
key: Date.now(),
text: text,
done: false,
mainuser: this.state.head,// main user should be array
});
so you need to give prop name also in <Button />
like this
<Button mainuser={mainuser} />

React Native - Flatlist Single Select

I've been searching around how to make a single select in Flatlist but I can't find any, here in my code I'am trying to make a single select on every cells that is inside my Flatlist.
Example: I select cell no.1, then no.1 will be selected. And if I need to select no.2, both no.1 and no.2 will be selected.
What is happening in my code is when I select no.1, it would select all cells.
export default class Dishes extends Component {
constructor(props) {
super (props)
this.state = {
data: [],
id: [],
price: [],
count: 0,
SplOrder: '',
tbl: this.props.navigation.state.params.tbl,
orderDet: this.props.navigation.state.params.orderDet,
DineIn: this.props.navigation.state.params.DineIn,
TakeOut: this.props.navigation.state.params.TakeOut,
}
}
/********************EDIT*************************
_incrementCount() {
this.setState({ count: this.state.count + 1 });
}
_decreaseCount() {
this.setState({ count: this.state.count - 1 });
}
changeTextHandler() {
this.setState({ ['count'+index]: text });
};
*/
_renderItem = ({ item, index }) => {
return (
<View>
<View>
<View>
<Text>Name: { item.menu_desc }</Text>
<View}>
<Text>Price: ₱{ item.menu_price }</Text>
<Text>Status: { item.menu_status }</Text>
</View>
<TextInput
placeholder = "Insert Special Request"
onChangeText = { (text) => this.setState({ SplOrder: text }) }
value = { this.state.SplOrder }
/>
</View>
<View>
<TouchableOpacity
onPress = {() => this._incrementCount()}>
<Text> + </Text>
</TouchableOpacity>
<TextInput
onChangeText={this.changeTextHandler}
value={this.state['count'+index].toString()} // Not working
placeholder="0"/>
<TouchableOpacity
onPress = {() => this._decreaseCount()}>
<Text> - </Text>
</TouchableOpacity>
</View>
</View>
</View>
)
}
render() {
return (
<View>
<View>
<Text>Table No: { this.state.tbl }</Text>
<Text>Order No: { this.state.orderDet }</Text>
<Text>{ this.state.DineIn }{ this.state.TakeOut }</Text>
</View>
<FlatList
data = {this.state.data}
keyExtractor={(item, index) => index.toString()}
extraData={this.state}
renderItem = {this._renderItem}
/>
<View>
<TouchableOpacity
onPress = {() => this.submit()}>
<Text>Send Order</Text>
</TouchableOpacity>
</View>
</View>
)
}
}
The TextInputs are targeting the same state SplOrder so, if you change it in any TextInput the others will display the same. The solution I see is to put an state for each item you create.
You should do this:
<TextInput
placeholder = "Insert Special Request"
onChangeText = { (text) => this.setState({ ['SplOrder'+index]: text }) }
value = { this.state['SplOrder'+index] }
/>
The second problem we have discussed in the comments should be fixed by passing index parameter to incrementCount function.
Hi, now in the method _incrementCount() you will have to pass the index and increment each count with it index as you have in the value of. So you could do
<TouchableOpacity
onPress = {() => this._incrementCount(index)}>
<Text> + </Text>
</TouchableOpacity>
And then change your _incrementCount method adding a parameter and doing like this:
_incrementCount(index) {
this.setState({ ['count'+index]: this.state['count'+index] + 1 });
}

Categories