I am trying to make a searchable flatlist for skills using the below JSON file:
const employeeList = [
{
id: "1",
name: "John",
image: require("../images/John.png"),
skills: [
{ id: 1, name: "Cooking" },
{ id: 2, name: "Climbing" },
],
},
{
id: "2",
name: "Pat",
image: require("../images/Pat.png"),
skills: [
{ id: 1, name: "Cooking" },
{ id: 2, name: "Rowing" },
],
},
];
export default employeeList;
I was successful in making a screen that will display and allow me to search for employee names but I would like to make a searchable flatlist with all the skills while also displaying the employee name who has that skill. I don't need them to be unique. In my code below I have managed to display all employees and their skills however my search feature only filters for the employee name.
// Searching using Search Bar Filter in React Native List View
// https://aboutreact.com/react-native-search-bar-filter-on-listview/
// import React in our code
import React, { useState, useEffect } from "react";
// import all the components we are going to use
import {
SafeAreaView,
Text,
StyleSheet,
View,
FlatList,
TextInput,
Image,
TouchableOpacity,
} from "react-native";
// import employee json
import employeeList from "../json/employee";
const AllListScreen = ({ navigation, route }) => {
const [search, setSearch] = useState("");
const [filteredDataSource, setFilteredDataSource] = useState([]);
const [masterDataSource, setMasterDataSource] = useState([]);
// set employee json as filter source
useEffect(() => {
setFilteredDataSource(employeeList);
setMasterDataSource(employeeList);
// skills show as undefined unless index is specified
console.log(JSON.stringify(employeeList[0].skills));
}, []);
const searchFilterFunction = (text) => {
// Check if searched text is not blank
if (text) {
// Inserted text is not blank
// Filter the masterDataSource
// Update FilteredDataSource
const newData = masterDataSource.filter(function (item) {
const itemData = item.name ? item.name.toUpperCase() : "".toUpperCase();
const textData = text.toUpperCase();
return itemData.indexOf(textData) > -1;
});
setFilteredDataSource(newData);
setSearch(text);
} else {
// Inserted text is blank
// Update FilteredDataSource with masterDataSource
setFilteredDataSource(masterDataSource);
setSearch(text);
}
};
const ItemView = ({ item, index }) => {
return (
// Flat List Item
<View>
// use map to display all skills under employee
{item.skills.map((v, i) => (
<>
<TouchableOpacity
onPress={() => console.log(v.name)}
style={styles.itemStyle}
key={item.id}
>
<Image
source={{ uri: "https://source.unsplash.com/random" }}
style={{ height: 50, width: 50 }}
/>
<View style={styles.textPortion}>
<Text>{item.name}</Text>
<Text>{v.name.toUpperCase()}</Text>
</View>
</TouchableOpacity>
<ItemSeparatorView />
</>
))}
</View>
);
};
const ItemSeparatorView = () => {
return (
// Flat List Item Separator
<View
style={{
height: 0.5,
width: "100%",
backgroundColor: "#C8C8C8",
}}
/>
);
};
return (
<SafeAreaView style={{ flex: 1 }}>
<View style={styles.container}>
<TextInput
style={styles.textInputStyle}
onChangeText={(text) => searchFilterFunction(text)}
value={search}
underlineColorAndroid="transparent"
placeholder="Search Here"
/>
<FlatList
data={filteredDataSource}
keyExtractor={(item, index) => index.toString()}
renderItem={ItemView}
/>
</View>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
container: {
backgroundColor: "#FFFFFF",
},
itemStyle: {
flex: 1,
padding: 8,
flexDirection: "row",
},
textInputStyle: {
height: 50,
borderWidth: 1,
paddingLeft: 20,
margin: 6,
borderColor: "#009688",
backgroundColor: "#FFFFFF",
borderRadius: 5,
},
textPortion: {
flexWrap: "wrap",
flexShrink: 1,
marginLeft: 6,
},
});
export default AllListScreen;
Here is an image of how it is displayed but as stated the search only works on the employee name while I want it to work on the skill:
Any help is much appreciated. Thanks.
I managed to get this working by restructuring the JSON in an array:
skillArray = [];
for (var key in employeeList) {
if (employeeList.hasOwnProperty(key)) {
for (item in employeeList[key].skills) {
skillArray.push({
name: employeeList[key].name,
skill: employeeList[key].skills[item].name,
});
}
}
}
Then I changed my search filter to target the skill instead of the name:
// set employee json as filter source
useEffect(() => {
setFilteredDataSource(skillArray);
setMasterDataSource(skillArray);
// skills show as undefined unless index is specified
console.log(JSON.stringify(employeeList[0].skills));
}, []);
const searchFilterFunction = (text) => {
// Check if searched text is not blank
if (text) {
// Inserted text is not blank
// Filter the masterDataSource
// Update FilteredDataSource
const newData = masterDataSource.filter(function (item) {
const itemData = item.skill ? item.skill.toUpperCase() : "".toUpperCase();
const textData = text.toUpperCase();
return itemData.indexOf(textData) > -1;
});
setFilteredDataSource(newData);
setSearch(text);
} else {
// Inserted text is blank
// Update FilteredDataSource with masterDataSource
setFilteredDataSource(masterDataSource);
setSearch(text);
}
};
And my updated ItemView:
const ItemView = ({ item }) => {
return (
// Flat List Item
<View style={styles.itemStyle}>
<Image
source={{ uri: "https://source.unsplash.com/random" }}
style={{ height: 50, width: 50 }}
/>
<Text style={styles.textPortion}>
{item.name.toUpperCase()}
{"\n"}
{item.skill.toUpperCase()}
</Text>
</View>
);
};
I'm not sure if this is the optimal approach but hopefully it helps someone.
Related
I am working on todo list in native , i have a function called onDelete but when i click on it , it delete all element in list and after then program crashed.
this is my main file where i have stored value as key , value pair
export default function App() {
const [courseGoal, setCourseGoal] = useState([]);
const [count, setCount] = useState('');
const submitHandler = () => {
setCourseGoal((currGoal) => [
...currGoal,
{ key: Math.random().toString(), value: count },
]);
};
console.log('App', courseGoal)
return (
<View style={styles.container}>
<SearchBar
setCourseGoal={setCourseGoal}
count={count}
setCount={setCount}
submitHandler={submitHandler}
/>
<ListItem courseGoal={courseGoal} setCourseGoal={setCourseGoal} courseGoal={courseGoal}/>
</View>
);
}
this is my list component where i am facing issue, you can see ondelete here.
import React from "react";
import { StyleSheet, Text, TouchableOpacity } from "react-native";
import { FlatList } from "react-native-web";
export default function ListItem(props) {
const onDelete = (goalId) => {
props.setCourseGoal((currGoal) => {
currGoal.filter((goal) => goal.key !== goalId);
console.log("clicked", props.courseGoal[0].key);
});
};
return (
<FlatList
data={props.courseGoal}
keyExtractor={(item, index) => item.key}
renderItem={(itemData) => (
<TouchableOpacity
onPress={onDelete.bind(itemData.item.key)}
activeOpacity={0.2}
>
<Text style={styles.listData}>{itemData.item.value}</Text>
{console.log(itemData.item.key)}
</TouchableOpacity>
)}
/>
);
}
this is my main component where i have my search input
import React from "react";
import { View, Text, StyleSheet, Pressable, TextInput } from "react-native";
export default function SearchBar(props) {
const onInputHandler = (value) => {
props.setCount(value);
};
return (
<View style={styles.searchBox}>
<Pressable style={styles.submitBtn} title="Click Me !">
<Text>☀️</Text>
</Pressable>
<TextInput
style={styles.searchInput}
placeholder="Enter Goal"
onChangeText={onInputHandler}
/>
<Pressable
style={styles.submitBtn}
title="Click Me !"
onPress={props.submitHandler}
>
<Text>🔥🔥</Text>
</Pressable>
</View>
);
}
const styles = StyleSheet.create({
searchBox: {
flexDirection: "row",
justifyContent: "space-around",
},
searchInput: {
width: "90%",
textAlign: "center",
padding: 10,
// color: 'white',
borderRadius: 10,
borderWidth: 1,
marginHorizontal: 5,
},
submitBtn: {
color: "black",
justifyContent: "space-around",
padding: 10,
borderRadius: 10,
borderWidth: 1,
},
});
You have to return the filtered array from your onDelete function
const onDelete = (goalId) => {
props.setCourseGoal((currGoal) => {
return currGoal.filter((goal) => goal.key !== goalId);
});
};
I am building a todo list app, and I want to long press individual todos, to change their color to green in order to mark them as finished.
I have a var color = 'white'; inside my App.js and I have another component named listItem for the list items.
I have this pretty basic function to change the color
const longPressHandler = () => {
(color == 'white') ? color = 'green' : color = 'white';
}
and I am sending the color via props of listItem
<ListItem item={item} longPressHandler = {longPressHandler} color={color} pressHandler = {pressHandler}/>
and I am using it as follows backgroundColor: props.color Check below:
const styles = StyleSheet.create({
listItem:{
padding: 8,
margin:4,
fontSize: 18,
textAlignVertical:'center',
borderColor:'gray',
borderWidth: 3,
borderStyle: 'solid',
borderRadius:10,
backgroundColor: props.color,
}
})
BUUT, it does not work... What am i doing wrong? Is there any simple solution that I am missing...
Here is the full code of App.js
import React, {useEffect, useState} from 'react';
import {Text, View, StyleSheet, FlatList, Alert, TouchableWithoutFeedback, Keyboard, Button, AsyncStorage } from 'react-native';
import ListItem from './components/listItem';
import AddItem from './components/addItem';
// npx react-native start // TO START
// npx react-native run-android // TO PROJECT INTO EMULATOR
//Hooks cant be used in class components, thus, switched from Class component structure => Function component structure
export default function TODOList() {
const [todos, setTodos] = useState([
{todo: 'do chores', key: '1'},
{todo: 'do homework', key: '2'},
{todo: 'go to grocery', key: '3'},
]);
var color = 'white';
//This handler DELETES the pressed list item from the list
const pressHandler = (key) => {
const newtodos = todos.filter(todo => todo.key != key);
setTodos(newtodos);
}
//ADDS a new todo with the given text and a randomly generated key to the old todos list
const inputSubmitHandler = (text) => {
if(text.length > 0){
const key = Math.random().toString();
const newTodos = [{text, key}, ...todos];
setTodos(newTodos);
}else{
Alert.alert('ERROR!', 'Text cannot be empty', [{text:'OK'}])
}
}
//TODO Change color of the individual item in the list
const longPressHandler = () => {
(color == 'white') ? color = 'green' : color = 'white';
}
console.log('color', color);
return (
<TouchableWithoutFeedback onPress={() => {Keyboard.dismiss();}}>
<View style={styles.mainPage}>
<View style = {styles.header}>
<Text style={styles.title}>TODO List</Text>
</View>
<View style={styles.content}>
<AddItem inputSubmitHandler={inputSubmitHandler} />
<View style={styles.list}>
<FlatList
data={todos}
renderItem={( {item} ) => (
<ListItem item={item} longPressHandler = {longPressHandler} color={color} pressHandler = {pressHandler}/>
)}
/>
</View>
</View>
</View>
</TouchableWithoutFeedback>
);
}
//The margins, paddings, etc. are given as pixel values, wont work same in other devices.
const styles = StyleSheet.create({
mainPage: {
flex: 1, // takes the whole background
backgroundColor: 'white',
},
content: {
flex: 1,
},
list:{
margin: 10,
flex:1,
},
header:{
height: 50,
paddingTop: 8,
backgroundColor: 'orange'
},
title:{
textAlign: 'center',
fontSize: 24,
fontWeight: 'bold',
},
});
Here is the full code of listItem.js
import React from 'react';
import {Text, View, StyleSheet, TouchableOpacity} from 'react-native';
export default function ListItem(props) {
//Moved the style inside of the function since I want to use the color prop in 'backgroundCcolor'
const styles = StyleSheet.create({
listItem:{
padding: 8,
margin:4,
fontSize: 18,
textAlignVertical:'center',
borderColor:'gray',
borderWidth: 3,
borderStyle: 'solid',
borderRadius:10,
backgroundColor: props.color,
}
})
return (
<TouchableOpacity onLongPress={() => props.longPressHandler()} onPress = {() => props.pressHandler(props.item.key)}>
<Text style={styles.listItem}> {props.item.todo}</Text>
</TouchableOpacity>
)
}
There are few changes you can do to the code
Move the color choice to the ListItem and pass a prop to decide that
No need to create the whole style inside the item itself you can pass the ones that you want to override
So to do this you will have to start with your listitem
<TouchableOpacity
onLongPress={() => props.longPressHandler(props.item.key)}
onPress={() => props.pressHandler(props.item.key)}>
<Text
style={[
// this will make sure that only one style object is created
styles.listItem,
{ backgroundColor: props.marked ? 'green' : 'white' },
]}>
{props.item.todo}
</Text>
</TouchableOpacity>
And your long press handler should change like below, this will set the marked property in the state which you use to decide the color above
const longPressHandler = (key) => {
const updatedTodos = [...todos];
const item = updatedTodos.find((x) => x.key == key);
item.marked = !item.marked;
setTodos(updatedTodos);
};
You can refer the below snack
https://snack.expo.io/#guruparan/todo
Try this way
const longPressHandler = (index) => {
const newTodos = [...todos];
newTodos[index].color = (newTodos[index].color && newTodos[index].color == 'green') ? 'white' : 'green';
setTodos(newTodos);
}
<FlatList
data={todos}
renderItem={( {item, index} ) => (
<ListItem
item={item}
index={index}
longPressHandler = {longPressHandler}
color={item.color || 'white'}
pressHandler = {pressHandler}
/>
)}
/>
export default function ListItem(props) {
return (
<TouchableOpacity onLongPress={() => props.longPressHandler(props.index)} >
.....
</TouchableOpacity>
)
}
Note: You have to pass an index from renderItem to ListItem and also from ListItem to longPressHandler function
It might sound silly but I am just learning here
I am trying to convert a component to a function-based component. I did everything right but I am stuck on something very silly
I have this code for Discover
export default class Discover extends React.PureComponent {
state = {
items: [],
};
cellRefs: {};
constructor(props) {
super(props);
this.cellRefs = {};
}
what is the correct way to convert cellRefs to work with the function I have? I tried everything when I do this in my class file it is fine it gives me an object with the things I need.
const cell = this.cellRefs[item.key];
However,
const cell = cellRefs[item.key];
is just giving undefined
Full code for the converted component
import React, { useState, useEffect, useRef, Children } from 'react';
import {
StyleSheet,
Text,
View,
FlatList,
Dimensions,
TouchableOpacity,
Image,
} from 'react-native';
import { Video } from 'expo-av';
const { height, width } = Dimensions.get('window');
const cellHeight = height * 0.6;
const cellWidth = width;
const viewabilityConfig = {
itemVisiblePercentThreshold: 80,
};
class Item extends React.PureComponent {
video: any;
componentWillUnmount() {
if (this.video) {
this.video.unloadAsync();
}
}
async play() {
const status = await this.video.getStatusAsync();
if (status.isPlaying) {
return;
}
return this.video.playAsync();
}
pause() {
if (this.video) {
this.video.pauseAsync();
}
}
render() {
const { id, poster, url } = this.props;
const uri = url + '?bust=' + id;
return (
<View style={styles.cell}>
<Image
source={{
uri: poster,
cache: 'force-cache',
}}
style={[styles.full, styles.poster]}
/>
<Video
ref={ref => {
this.video = ref;
}}
source={{ uri }}
shouldPlay={false}
isMuted
isLooping
resizeMode="cover"
style={styles.full}
/>
<View style={styles.overlay}>
<Text style={styles.overlayText}>Item no. {id}</Text>
<Text style={styles.overlayText}>Overlay text here</Text>
</View>
</View>
);
}
}
interface FeedListProps {
}
export const FeedList: React.FC<FeedListProps> = (props) => {
const initialItems = [
{
id: 1,
url: 'https://s3.eu-west-2.amazonaws.com/jensun-uploads/shout/IMG_1110.m4v',
poster:
'https://s3.eu-west-2.amazonaws.com/jensun-uploads/shout/norwaysailing.jpg',
},
{
id: 2,
url:
'https://s3.eu-west-2.amazonaws.com/jensun-uploads/shout/croatia10s.mp4',
poster:
'https://s3.eu-west-2.amazonaws.com/jensun-uploads/shout/croatia10s.jpg',
},
];
const [items, setItems] = useState([]);
//this.cellRefs = {};
//let cellRefs: {};
//cellRefs= {};
const cellRefs = React.useRef({})
const viewConfigRef = React.useRef({ itemVisiblePercentThreshold: 80 })
useEffect(() => {
loadItems();
setTimeout(loadItems, 1000);
setTimeout(loadItems, 1100);
setTimeout(loadItems, 1200);
setTimeout(loadItems, 1300);
}, []);
const _onViewableItemsChanged = React.useRef((props)=>{
const changed = props.changed;
changed.forEach(item => {
const cell = cellRefs[item.key];
console.log("CALLING IF"+ cell + " " + item.key)
if (cell) {
if (item.isViewable) {
console.log("PLAY OS CALLED")
cell.play();
} else {
console.log("Pause is played")
cell.pause();
}
}
});
});
function loadItems(){
const start = items.length;
const newItems = initialItems.map((item, i) => ({
...item,
id: start + i,
}));
const Litems = [...items, ...newItems];
setItems( Litems );
};
function _renderItem({ item }){
return (
<Item
ref={cellRefs[item.id]}
{...item}
/>
);
};
return (
<View style={styles.container}>
<FlatList
style={{ flex: 1 }}
data={items}
renderItem={_renderItem}
keyExtractor={item => item.id.toString()}
onViewableItemsChanged={_onViewableItemsChanged.current}
initialNumToRender={3}
maxToRenderPerBatch={3}
windowSize={5}
getItemLayout={(_data, index) => ({
length: cellHeight,
offset: cellHeight * index,
index,
})}
viewabilityConfig={viewabilityConfig}
removeClippedSubviews={true}
ListFooterComponent={
<TouchableOpacity onPress={loadItems}>
<Text style={{ padding: 30 }}>Load more</Text>
</TouchableOpacity>
}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
},
cell: {
width: cellWidth - 20,
height: cellHeight - 20,
backgroundColor: '#eee',
borderRadius: 20,
overflow: 'hidden',
margin: 10,
},
overlay: {
position: 'absolute',
top: 0,
right: 0,
bottom: 0,
left: 0,
backgroundColor: 'rgba(0,0,0,0.4)',
padding: 40,
},
full: {
position: 'absolute',
top: 0,
right: 0,
bottom: 0,
left: 0,
},
poster: {
resizeMode: 'cover',
},
overlayText: {
color: '#fff',
},
});
Should be enough to use a functional component and use useRef([]) initialized as an array
Working example:
https://snack.expo.io/2_xrzF!LZ
It would be best if you could inline your source code into stack overflow, than keeping it in a separate link. However I took a look at the component, and I think the issue is with how you are using props.
On line 91,
export const FeedList: React.FC<FeedListProps> = ({}) => {
So here, you need to get the props as an argument. Earlier with the class component it was available at this.props. However here you need to pass it as below,
export const FeedList: React.FC<FeedListProps> = (props) => {
Or you may destructure the props as below,
export const FeedList: React.FC<FeedListProps> = ({changed}) => {
You will also need to modify the interface on line 87 to reflect the type.
Here is the full code:
import * as React from 'react';
import { View, ScrollView, StyleSheet } from 'react-native';
import {
Appbar,
Searchbar,
List,
BottomNavigation,
Text,
Button,
} from 'react-native-paper';
const AccordionCollection = ({ data }) => {
var bookLists = data.map(function (item) {
var items = [];
for (let i = 0; i < item.total; i++) {
items.push(
<Button mode="contained" style={{ margin: 10 }}>
{i}
</Button>
);
}
return (
<List.Accordion
title={item.title}
left={(props) => <List.Icon {...props} icon="alpha-g-circle" />}>
<View
style={{
flexDirection: 'row',
flexWrap: 'wrap',
alignItems: 'flex-start',
backgroundColor: 'white',
}}>
{items}
</View>
</List.Accordion>
);
});
return bookLists;
};
const MusicRoute = () => {
const DATA = [
{
key: 1,
title: 'Zain dishes',
total: 21,
},
{
key: 2,
title: 'Sides',
total: 32,
},
{
key: 3,
title: 'Drinks',
total: 53,
},
{
key: 4,
title: 'Aesserts',
total: 14,
},
];
const [data, setData] = React.useState(DATA);
const [searchQuery, setSearchQuery] = React.useState('');
const [sortAZ, setSortAZ] = React.useState(false);
const onChangeSearch = (query) => {
setSearchQuery(query);
const newData = DATA.filter((item) => {
return item.title.toLowerCase().includes(query.toLowerCase());
});
setData(newData);
};
const goSortAZ = () => {
setSortAZ(true);
setData(
data.sort((a, b) => (a.title > b.title ? 1 : b.title > a.title ? -1 : 0))
);
};
const goUnSort = () => {
setSortAZ(false);
setData(DATA);
};
return (
<View>
<Appbar.Header style={styles.appBar}>
<Appbar.BackAction onPress={() => null} />
<Searchbar
placeholder="Search"
onChangeText={onChangeSearch}
value={searchQuery}
style={styles.searchBar}
/>
<Appbar.Action
icon="sort-alphabetical-ascending"
onPress={() => goSortAZ()}
/>
<Appbar.Action icon="library-shelves" onPress={() => goUnSort()} />
</Appbar.Header>
<ScrollView>
<List.Section title="Accordions">
<AccordionCollection data={data} />
</List.Section>
</ScrollView>
</View>
);
};
const AlbumsRoute = () => <Text>Albums</Text>;
const MyComponent = () => {
const [index, setIndex] = React.useState(0);
const [routes] = React.useState([
{ key: 'music', title: 'Music', icon: 'queue-music' },
{ key: 'albums', title: 'Albums', icon: 'album' },
]);
const renderScene = BottomNavigation.SceneMap({
music: MusicRoute,
albums: AlbumsRoute,
});
return (
<BottomNavigation
navigationState={{ index, routes }}
onIndexChange={setIndex}
renderScene={renderScene}
/>
);
};
const styles = StyleSheet.create({
appBar: {
justifyContent: 'space-between',
},
searchBar: {
width: '60%',
shadowOpacity: 0,
borderRadius: 10,
backgroundColor: '#e4e3e3',
},
});
export default MyComponent;
Expo Snack Link
There are two weird mechanisms.
First
If I remove sortAZ(true) in goSortAZ() and sortAZ(false) in goUnSort(), the state data stops updating after you press on (1) sort and (2) unsort buttons more than three times.
Second
If I remove DATA array outside the component, sort and unsort buttons does not work/update.
If I do not remove these two, I can sort and unsort the list.
I feel that the code is messy although it achieves the function.
My questions is:
Why adding extra state (sortAZ) helps to update other state (data)?
Just totally remove sortAZ variable (no need to use it unless you somehow want to have a loading status, but since you are not making http requests, that's not necessary) and replace goSortAZ with the following:
Remember to clone the original array in order to create a new copy and then sort that copy.
This is working fine.
const goSortAZ = () => {
setData(
[...data].sort((a, b) => (a.title > b.title ? 1 : b.title > a.title ? -1 : 0))
);
};
i would suggest using the same technique for the unSort method too.
I'm using React Native Elements CheckBox inside List Items, of Flat List.
import React, { Component } from "react";
import { View, Text, StyleSheet, FlatList } from "react-native";
import axios from "axios";
import {
Button,
Container,
Content,
Header,
Body,
Left,
Right,
Title
} from "native-base";
import Icon from "react-native-vector-icons/Ionicons";
import { List, ListItem, SearchBar, CheckBox } from "react-native-elements";
// const itemId = this.props.navigation.getParam('itemId', 'NO-ID');
// const otherParam = this.props.navigation.getParam('otherParam', 'some default value');
class TeacherSubjectSingle extends Component {
static navigationOptions = {
header: null
};
// static navigationOptions = {
// headerStyle: {
// backgroundColor: '#8E44AD',
// },
// headerTintColor: '#fff',
// }
state = {
class_id: null,
userid: null,
usertype: null,
student_list: [],
faq: [],
checked: []
};
componentWillMount = async () => {
const {
class_id,
student_list,
userid,
usertype
} = this.props.navigation.state.params;
await this.setState({
class_id: class_id,
student_list: student_list,
userid: userid,
usertype: usertype
});
console.log(this.state.class_id);
var result = student_list.filter(function(obj) {
return obj.class_section_name == class_id;
});
this.setState({
student_list: result[0]
});
};
renderSeparator = () => {
return (
<View
style={{
height: 1,
width: "100%",
backgroundColor: "#CED0CE"
}}
/>
);
};
checkItem = item => {
const { checked } = this.state;
if (!checked.includes(item)) {
this.setState({ checked: [...checked, item] });
} else {
this.setState({ checked: checked.filter(a => a !== item) });
}
};
render() {
return (
<Container>
<Header style={{ backgroundColor: "#8E44AD" }}>
<Left>
<Button
transparent
onPress={() => this.props.navigation.navigate("ClassTeacher")}
>
<Icon name="ios-arrow-dropleft" size={24} color="white" />
</Button>
</Left>
<Body>
<Title style={{ color: "white" }}>{this.state.class_id}</Title>
</Body>
<Right />
</Header>
<View style={{ flex: 1, backgroundColor: "#fff" }}>
<List containerStyle={{ borderTopWidth: 0, borderBottomWidth: 0 }}>
<FlatList
data={this.state.student_list.students}
renderItem={({ item }) => (
<ListItem
// roundAvatar
title={
<CheckBox
title={item.name}
onPress={() => this.checkItem(item.userid)}
checked={this.state.checked.includes(item.userid)}
/>
}
// subtitle={item.email}
// avatar={{ uri: item.picture.thumbnail }}
containerStyle={{ borderBottomWidth: 0 }}
onPress={() =>
this.props.navigation.navigate("IndividualChat", {
rc_id: item.userid,
userid: this.state.userid,
usertype: this.state.usertype,
subject_name: this.state.student_list.subject_name
})
}
/>
)}
keyExtractor={item => item.userid}
ItemSeparatorComponent={this.renderSeparator}
/>
</List>
</View>
</Container>
);
}
}
export default TeacherSubjectSingle;
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: "center",
justifyContent: "center"
}
});
Above is my code for the same, I have tried every possibility and checked the GitHub page for the same, but my items are not getting checked if I press on the checkbox.
My renderItem will have an array to render which is having a field like 'name' and 'userid'.
This is the example of the code from where I have coppied the coding for the same, where it is working
I want to save selected ids to an array so that I can pass that as a prop to the next screen.
Since FlatList is a PureComponent, it will not re-render the items unless the data changes. If you want the FlatList to re-render when checked array changes, you need to pass it to e.g. extraData.
<FlatList
data={this.state.student_list.students}
extraData={this.state.checked}
renderItem={({ item }) => {
// ...
}}
keyExtractor={item => item.userid}
ItemSeparatorComponent={this.renderSeparator}
/>