There are two select fields, Language and Currency. I am getting values dynamically showing in both fields, but now I have to change drop down value and op press on button I am calling Onclick fucntion and updating to server .
If not changing cvalue in preferredLanguage and updating its showing undefined
preferredCurrency - if am using below code for this is giving boolean value.
Please review my code and correct it .
I have to display data dynamically in both selectfield and after changing the value in selectfield and update it should updated current selected value .
this.state = { languageAndCurrecny:{
preferredLanguage: navigation.state.params.customerInfo[0].billingPreferenceDetails.presentationLanguageCode,
},
currencyChangedValue:{
preferredCurrency: navigation.state.params.customerInfo[0].billingPreferenceDetails.preferedCurrencyCode,
}
this.handleChangeCurrency=this.handleChangeCurrency.bind(this);
}
OnButtonClick = async (preferredLanguage, preferredCurrency) => {
const { OnButtonClick } = this.props;
await OnButtonClick(preferredLanguage, preferredCurrency);
this.setState({
preferredCurrency:'',
preferredLanguage:'',
})
}
languageChanged = (key, val) => {
this.handleChange({ field: "preferredLanguage" }, val);
};
handleChange = (props, e) => {
let tempObj = this.state.languageAndCurrecny;
tempObj[props.field] = e;
this.setState({ preferredLanguage: tempObj });
};
currencyChanged = (key, val) => {
this.handleChangeCurrency({ field: "preferredCurrency" }, val);
};
handleChangeCurrency = (props, e) => {
let tempObj = this.state.currencyChangedValue;
tempObj[props.field] = e;
this.setState({ preferredCurrency: tempObj });
};
render (
let {languageAndCurrecny,currencyChangedValue} = this.state;
const { navigation, clmmasterData } = this.props;
const { masterData, language } = clmmasterData;
let currencyData=[];
masterData.preferredCurrency.map(({ code: value, name: label }) => {
currencyData.push({ value, label });
});
let languageData=[];
masterData.language.map(({ code: value, name: label }) => {
languageData.push({ value, label });
});
return (
<View style={{ padding: 20 }}>
<Form style={{ width: '100%' }}>
<SelectField
label="Presentation Language"
node="presentationLanguage"
options={languageData}
value={languageAndCurrency.preferredLanguage}
onChange={this.languageChanged}
that={this}
setIcon={true}
img="LANGUAGE"
/>
<SelectField
label="Preferred Currency"
options={currencyData}
value={preferredCurrency}
node="preferredCurrency"
onChange={this.handleChangeCurrency}
that={this}
setIcon={true}
img="CURRENCY"
/>
<View style={{ marginTop: 50 }}>
<PrimaryBtn label={'submit'} disabled={false} onPress={()=> this.OnButtonClick(this.state.preferredLanguage,this.state.preferredCurrency,)}/>
</View>
Thanks .. Please help
new answer:
onChange returns a value which contain new selected value.
Use these 2 function as below
languageChanged = (key, val) => {
let languageAndCurrecny.preferredLanguage = val
this.setState({ languageAndCurrecny: languageAndCurrecny})
};
handleChangeCurrency(value){
this.setState({
preferredCurrency: value
})}
Old answer just add this in render method, you just missed preferredCurrency:
let { languageAndCurrecny, preferredCurrency } = this.state;
Related
Panel is a datamodel fetched from database. avialablePanels is a dropdown where I can select an option I want. PanelCode dropdown is populated using a lookup table because it acts as a form where the displayed value is what Panel['PanelCode'] has and other values with which I can update. When I update a value of Panel[PanelCode] with the help of indexing using the PanelCode dropdown form it initially updates the value in the Panel['PanelCode'] array. Now lets say I want to update another value in the Panel['PanelCode'] and save them together as soon as I select another option from avialablePanels the first updated value of Panel['PanelCode'] is lost.
Panel: {
PanelCode: [ 1, 4 ]
}
availablePanels:[
{ OptionCode: 'R1-1', OptionKey: 1, OptionValue: 'Stop' },
{ OptionCode: 'R1-3P',OptionKey: 4,OptionValue: 'All Way (plaque)'}
]
export default class PanelTest extends Component {
constructor(props) {
super(props);
console.log(this.props.pointModel)
this.state = {...this.props.pointModel,
availablePanels:[],
selectedIndex: 0,
selectedPanel: null,
tempPanelCode: this.props.pointModel.Panel.PanelCode[0]===null?0:
this.props.pointModel.Panel.PanelCode[0],
}
}
render() {
return(
<Container>
{this.state.availablePanels.length>0 &&
<PtSelect label="Available Panel"
options={this.state.availablePanels}
name="selectedPanel" defaultVal={this.state.selectedPanel}
onChange={this.onChangeSelectedPanelDropdown} />}
{this.renderPanelinfo()}
</Container>
)
}
onChangeSelectedPanelDropdown = (e) => {
const { target } = e;
const {name, value} = target;
let indexVal = this.state.Panel.PanelCode.indexOf(parseInt(value))
this.setState({ [name]: parseInt(value),
selectedIndex:indexVal,
tempPanelCode: this.props.pointModel.Panel.PanelCode[indexVal]===null?0:
this.props.pointModel.Panel.PanelCode[indexVal]
});
}
renderPanelinfo = () =>{
const {typeOptions} = DropdownLib.getSignNum().Signs_Types;
/* typeOptions looks like availablePanels but with more options */
return (
<div>
<PtSelect label="Panel Code" options={typeOptions}
disabled={this.props.disabled}
name="PanelCode" defaultVal={this.state.tempPanelCode}
onChange={this.onChangeDropdown} />
</div>
)
}
getAvaialablePanels=()=>{
const availablePanelOptions = []
const optionKey = []
//const optionvalue = []
fetch(`${config.server}/getavailablepanels/`+this.state.Support.SignId)
.then(response=>
{
return response.json();
})
.then(data=>{
for (var i =0;i<data.length;i++){
availablePanelOptions.push(data[i]['OptionCode'])
optionKey.push(data[i]['OptionKey'])
//optionvalue.push(data[i]['OptionValue'])
}
let dropOptions = availablePanelOptions.map((option,idx)=>{
return {key:optionKey[idx],value: optionKey[idx], label:option}
});
this.setState({
availablePanels:dropOptions
});
})
.catch(error=>{
console.log(error);
});
}
onChangeDropdown = (e) => {
const { target } = e;
const {name, value} = target;
this.props.triggerNeedSave();
// eslint-disable-next-line
let stateVariable = 'temp'+[name]
this.setState({
[stateVariable]: parseInt(value)
});
this.props.pointModel.Panel[name][this.state.selectedIndex] = parseInt(value);
console.log(this.state)
}
componentDidMount(){
this.getAvaialablePanels()
}
}
Any help is really appreciated.
There are two Select field where am getting data in drop down . Now when I am changing the value and selecting other value its throwing error .
Please suggest me how can I change these value dynamically and submit to server .On button click I have to update this to server . Please help me for that .
class UpdateBillPreferences extends Component {
constructor(props) {
super(props);
const {navigation,clmmasterData} =this.props;
this.state = {
title: 'Update Bill Preferences',
mobile: navigation.state.params.customer.service.serviceNumber,
icon: 'sim',
email:'',
smsNum:'',
faxNum:'',
preferredLanguage: navigation.state.params.customerInfo[0].billingPreferenceDetails.presentationLanguageCode,
preferredCurrency: navigation.state.params.customerInfo[0].billingPreferenceDetails.preferedCurrencyCode,
};
this.presentationLanguageOptions=[{value:'english',label:'English'}, {value:'spanish',label:'Spanish'}]
this.preferredCurrencyOptions=[{value:'dollar',label:'Dollar'}, {value:'niara',label:'Niara'}]
}
componentDidMount() {
}
OnButtonClick = async (preferredLanguage, preferredCurrency,email,smsNum,faxNum) => {
const { OnButtonClick } = this.props;
await OnButtonClick(preferredLanguage, preferredCurrency,email,smsNum,faxNum);
this.setState({
preferredLanguage: '',
preferredCurrency:'',
email :'',
smsNum :'',
faxNum :''
})
}
simRegionChanged = (val, target) => {
this.handleChange({ field: "preferredLanguage" }, target);
};
handleChange = (props, e) => {
let tempObj = this.state.presentationLanguageCode;
tempObj[props.field] = e;
this.setState({ presentationLanguageCode: tempObj });
};
render() {
let { title, mobile, icon } = this.state;
const { navigation,clmmasterData} = this.props;
const {billingAddressDetails,billingPreferenceDetails} = navigation.state.params.customerInfo[0];
const {masterData , language} = clmmasterData;
let submitBtn = { label: 'Submit', OnSubmit: this.onSubmit };
let currencyData=[];
masterData.preferredCurrency.map(({ code: value, name: label }) => {
currencyData.push({ value, label });
});
let languageData=[];
masterData.language.map(({ code: value, name: label }) => {
languageData.push({ value, label });
});
return (
<ImageBackground source={BG} style={styles.imgBG}>
<ScrollView>
<View style={styles.container}>
<View>
<Header title={title} subtitle={mobile} icon={icon} navigation={navigation}/>
</View>
<View style={styles.contentContainer}>
<View style={{ padding: 20 }}>
<Form style={{ width: '100%' }}>
<SelectField
label="Presentation Language"
node="presentationLanguage"
options={languageData}
value={this.state.preferredLanguage}
onChange={this.simRegionChanged}
that={this}
setIcon={true}
img="LANGUAGE"
/>
<SelectField
label="Preferred Currency"
options={currencyData}
value={this.state.preferredCurrency}
node="preferredCurrency"
onChange={this.handleChange}
that={this}
setIcon={true}
img="CURRENCY"
/>
<PrimaryBtn label={'submit'} disabled={false} onPress={()=> this.OnButtonClick(this.state.preferredLanguage,this.state.preferredCurrency,
Thanks
Your problem is here:
simRegionChanged = (val, target) => {
this.handleChange({ field: "preferredLanguage" }, target);
};
handleChange = (props, e) => {
let tempObj = this.state.presentationLanguageCode;
tempObj[props.field] = e;
this.setState({ presentationLanguageCode: tempObj });
};
You are calling handleChange with the prop {field: "preferredLanguage"}. The first line of handleChange then returns undefined because presentationLanguageCode isn't in your state, so when you then do this:
tempObj[props.field] = e; // tempObj["preferredLanguage"] = e
... it throws the error because you're attempting to set a property on an object that doesn't exist.
It looks like you should just be updating preferredLanguage:
handleChange = (props, e) => {
this.setState({ preferredLanguage: e });
};
I have a DayPicker component that allows a user to select multiple dates. I store this data in an array of Date objects that gets sent to the reducer when the user clicks next in a multistep form. However, if I return back to this form, I cannot add AND remove any dates. This is what my component looks like
class StepThree extends Component {
static getDerivedStateFromProps = (nextProps) => {
const {
stepThree: { dates }
} = nextProps;
const shouldUpdate = dates.length !== 0;
if (shouldUpdate) {
const newDates = dates.map(date => new Date(date));
return {
dates: newDates
};
}
return null;
};
state = {
dates: []
};
handleDayClick = (day, { selected }) => {
const { dates } = this.state;
if (selected) {
const selectedIndex = dates.findIndex(selectedDay => DateUtils.isSameDay(selectedDay, day));
dates.splice(selectedIndex, 1);
} else {
dates.push(day);
}
this.setState({ dates });
};
handleNext = (e) => {
e.preventDefault();
this.props.setStepThree(this.state.dates);
};
render() {
return (
<Col>
<Col style={{ textAlign: 'center' }}>
<DayPicker selectedDays={this.state.dates} onDayClick={this.handleDayClick} />
</Col>
<div
style={{
width: '100%',
position: 'fixed',
bottom: '0px',
zIndex: '100',
textAlign: 'center',
padding: '10px',
left: '0px'
}}
>
<PreviousButton handleClick={this.props.handlePrevious} />
<NextButton handleClick={this.handleNext} />
</div>
</Col>
);
}
}
When I return to this form, I see the new date being passed into the handleClick method, but it does not append to the array. The state remains the name.
NOTE: This is a reproducible pattern after the first time the user has filled the form. After the first time, this is basically uneditable.
This is the reducer code
case ACTIONS.SET_STEP_THREE: {
const newDates = action.dates.map(d => new Date(d));
return {
...state,
stepThree: {
...state.stepThree,
dates: newDates
}
};
}
Pushing or removing date to/ from dates array will not change its reference. you should recreate the dates array to update its reference and allow react to detect the changes of the component state. you can use any method to recreate the dates array exp : array.concat or array.slice or the Spread syntax let newDatesRf = [...dates];
handleDayClick = (day, { selected }) => {
const { dates } = this.state;
if (selected) {
const selectedIndex = dates.findIndex(selectedDay =>
DateUtils.isSameDay(selectedDay, day));
dates.splice(selectedIndex, 1);
} else {
dates.push(day);
}
let newDatesRf = [...dates];//copy dates array to a new array
this.setState({ dates:newDatesRf });
};
I'm trying to display/store a list of items in my flatlist, but the problem is when I save an item and load that item in a different screen it is in a kind of repetition(look for the screen shot). And when I try to add different item, this new item will replace the previous item with the same kind of repetition. What I'm targeting is to have a list.
List_ScreenShot
Here is my code
AddModal.js
export default class AddModal extends React.Component {
constructor(props) {
super(props);
this.state = {
modalVisible: props.modalVisible,
id: null,
count: 0,
price: null
};
}
state = {
text: '',
}
save = () => {
const { text } = this.state;
let myArray = {
text, text
}
AsyncStorage.setItem('myArray', JSON.stringify(myArray));
alert(text + 'saved');
}
onChange = (text) => {
this.setState({ text });
}
componentWillReceiveProps(nextProps) {
this.setState({
modalVisible: nextProps.modalVisible,
id: nextProps.id,
price: nextProps.price
})
}
render() {
console.log('inside AppModal', this.state.modalVisible);
return (
<View>
<TextInput style = { styles.input }
keyboardType = "numeric"
onChangeText = { this.onChange }
value = { this.state.text } //Item **
>
</TextInput>
</View>
<View}>
<TouchableOpacity
onPress = {() => { this.props.setModalVisible(false) }}
>
<Text style = { styles.buttonText }>Cancel</Text>
</TouchableOpacity>
<TouchableOpacity
onPress = { this.save }>
<Text style = { styles.buttonText }>Send</Text>
</TouchableOpacity>
</View>
)
}
}
Settlment.js
import Details from '../Menus/Details';
const key = '#MyApp:key';
export default class Settlement extends React.Component {
state = {
text: '',
storedValue: '',
myArray: ''
}
componentWillMount() {
//this.onLoad();
AsyncStorage.getItem('myArray')
.then(text => this.setState({ text }));
}
showData = async() => {
let myArray = await AsyncStorage.getItem('myArray');
let d = JSON.parse(myArray);
this.setState({ myArray : myArray });
}
render() {
const { myArray, text } = this.state;
return (
<View>
<TouchableOpacity onPress = {this.showData}>
<Text>Load Data</Text>
</TouchableOpacity>
<FlatList data = { this.state.myArray }
renderItem = {({ item }) =>
<Text>{myArray}</Text>
}
keyExtractor={(item, index) => index.toString()}
>
</FlatList>
</View>
);
}
}
What I see here:
const { text } = this.state;
let myArray = {
text, text
}
AsyncStorage.setItem('myArray', JSON.stringify(myArray));
alert(text + 'saved');
is an object called myArray, and nothing is being added to it. It's being defined and then assigned a value.
Maybe you could declare your array elsewhere like in the constructor (as an array, not an object, using myArray = []) and then use myArray.push(text) or if you want an array containing objects you can push object using myArray.push({ yourKeyName: text }). Also, it seems like the object you're storing in AsyncStorage is being replaced and not added to. But I'm not sure why you're getting multiple list items instead of just one.
PS - Where you're declaring state looks a bit off. I usually see it like this:
constructor() {
super();
this.state = {
text: '',
storedValue: '',
myArray: '',
};
}
I am trying to search through a flatlist based on a search bar text. The problem I am running into is that when the user mistypes...say they wanted to type "burger" but typed "burget" by mistake then it returns nothing as it should. When the user deletes the "t" then it should re-render the flatlist again with the last text matching the "burge" part.
note: using react-native-elements search bar which allows me to call the text with just e or event.
What I have so far in the Main.js file:
searchText = (e) => {
let text = e.toLowerCase();
let trucks = this.state.data;
// search by food truck name
let filteredName = trucks.filter((truck) => {
return truck.name.toLowerCase().match(text);
});
// if no match and text is empty
if(!text || text === '') {
console.log('change state');
this.setState({
data: initial
});
}
// if no name matches to text output
else if(!Array.isArray(filteredName) && !filteredName.length) {
console.log("not name");
this.setState({
data: [],
});
}
// if name matches then display
else if(Array.isArray(filteredName)) {
console.log('Name');
this.setState({
data: filteredName,
});
}
};
<View style={styles.container}>
<SearchBar
round
lightTheme
containerStyle={styles.search}
ref="search"
textInputRef="searchText"
onChangeText={this.searchText.bind(this)}
placeholder='Search by Truck Name...'
/>
<TruckList getTruck={(truck) => this.setTruck(truck)} truckScreen={this.truckScreen} data={this.state.data}/>
</View>
then the TruckList.JS:
export default class TruckList extends Component {
// rendering truck screen
renderTruckScreen = (item) => {
this.props.truckScreen();
this.props.getTruck(item);
}
render() {
return(
<List style={styles.list}>
<FlatList
data={this.props.data}
renderItem={({ item }) => (
<ListItem
roundAvatar
avatar={{uri: item.pic1}}
avatarStyle={styles.avatar}
title={item.name}
titleStyle={styles.title}
subtitle={
<View style={styles.subtitleView}>
<Text style={styles.subtitleFood}>{item.food}</Text>
<View style={styles.subtitleInfo}>
<Icon
name="favorite"
size={20}
color={"#f44336"}
style={styles.subtitleFavorite}
/>
<Text style={styles.subtitleFavoriteText}>{item.favorited} favorited</Text>
</View>
</View>
}
onPress={() => this.renderTruckScreen(item)}
/>
)}
keyExtractor={(item) => item.uid}
ListFooterComponent={this.footer}
/>
</List>
)
}
}
I have tried a few other ways to no avail. Also the only solutions I have seen working for React Native are with ListView which will be depreciated in time. So I am trying to do this with the new FlatList Component.
Thanks for your help!
I came across this same issue today when trying to implement a filter / search function on the new FlatList component. This is how I managed to solve it:
By creating another item in the state of the parent component called noData, you can set that to true when there are no results that match your search and then render your FlatList conditionally.
My implementation is slightly different to yours, but if I had to adjust your code it would look something like this:
Searchtext function:
searchText = (e) => {
let text = e.toLowerCase()
let trucks = this.state.data
let filteredName = trucks.filter((item) => {
return item.name.toLowerCase().match(text)
})
if (!text || text === '') {
this.setState({
data: initial
})
} else if (!Array.isArray(filteredName) && !filteredName.length) {
// set no data flag to true so as to render flatlist conditionally
this.setState({
noData: true
})
} else if (Array.isArray(filteredName)) {
this.setState({
noData: false,
data: filteredName
})
}
}
Then pass the noData bool to your TruckList component:
<TruckList getTruck={(truck) => this.setTruck(truck)}
truckScreen={this.truckScreen} data={this.state.data} noData={this.state.noData}/>
Then render your FlatList in the TruckList component only if there are results:
<List style={styles.list}>
{this.props.noData ? <Text>NoData</Text> : <FlatList {...} />}
</List>
That should then take care of handling user typing errors - as it will re-render the flatlist as soon as there are no results, and will remember the previous search state when you remove the typing error..
Let me know if that helps!
For a useful in-memory search you should keep initial data seperately.
I have more simple solution for this.
This solution for in-memory search on FlatList's data and uses it String.prototype.includes() method to search substring.
You can find full source code of this component in this gist;
https://gist.github.com/metehansenol/46d065b132dd8916159910d5e9586058
My initial state;
this.state = {
searchText: "",
data: [],
filteredData: []
};
My SearchBar component (it comes from react-native-elements package);
<SearchBar
round={true}
lightTheme={true}
placeholder="Search..."
autoCapitalize='none'
autoCorrect={false}
onChangeText={this.search}
value={this.state.searchText}
/>
My search method;
search = (searchText) => {
this.setState({searchText: searchText});
let filteredData = this.state.data.filter(function (item) {
return item.description.includes(searchText);
});
this.setState({filteredData: filteredData});
};
And last my FlatList's DataSource expression;
<FlatList
data={this.state.filteredData && this.state.filteredData.length > 0 ? this.state.filteredData : this.state.data}
keyExtractor={(item) => `item-${item.id}`}
renderItem={({item}) => <ListItem
id={item.id}
code={item.code}
description={item.description}
/>}
/>
Happy coding...
Update:
This blog can help you better understand the searching in a FlatList.
FYI:
If you have huge online data then you can also use algolia.
I adjusted the above code for me in order to make it work properly. The reason is that when user removes the last wrong character, code search this new string from a previous search list (state) which does not contain all objects, although it had to search from a full list available. So, I have two list now. One contains full list of objects and second contains only rendered list of objects which is changing upon search.
handleSearchInput(e){
let text = e.toLowerCase()
let fullList = this.state.fullListData;
let filteredList = fullList.filter((item) => { // search from a full list, and not from a previous search results list
if(item.guest.fullname.toLowerCase().match(text))
return item;
})
if (!text || text === '') {
this.setState({
renderedListData: fullList,
noData:false,
})
} else if (!filteredList.length) {
// set no data flag to true so as to render flatlist conditionally
this.setState({
noData: true
})
}
else if (Array.isArray(filteredList)) {
this.setState({
noData: false,
renderedListData: filteredList
})
}
}
Make Search Bar Filter for List View Data in React Native
For Real-Time Searching in List View using Search Bar Filter
We will load the list from the network call and then show it to the user.
The user can search the data by entering the text in TextInput.
After inserting the text SearchFilterFunction will be called We will
compare the list data with the inserted data and will make a new Data
source.
We will update the data source attached to the ListView.
It will re-render the list and the user will be able to see the
filtered data.
//This is an example code to Add Search Bar Filter on Listview//
import React, { Component } from 'react';
//import react in our code.
import {
Text,
StyleSheet,
View,
FlatList,
TextInput,
ActivityIndicator,
Alert,
} from 'react-native';
//import all the components we are going to use.
export default class App extends Component {
constructor(props) {
super(props);
//setting default state
this.state = { isLoading: true, text: '' };
this.arrayholder = [];
}
componentDidMount() {
return fetch('https://jsonplaceholder.typicode.com/posts')
.then(response => response.json())
.then(responseJson => {
this.setState(
{
isLoading: false,
dataSource: responseJson
},
function() {
this.arrayholder = responseJson;
}
);
})
.catch(error => {
console.error(error);
});
}
SearchFilterFunction(text) {
//passing the inserted text in textinput
const newData = this.arrayholder.filter(function(item) {
//applying filter for the inserted text in search bar
const itemData = item.title ? item.title.toUpperCase() : ''.toUpperCase();
const textData = text.toUpperCase();
return itemData.indexOf(textData) > -1;
});
this.setState({
//setting the filtered newData on datasource
//After setting the data it will automatically re-render the view
dataSource: newData,
text: text,
});
}
ListViewItemSeparator = () => {
//Item sparator view
return (
<View
style={{
height: 0.3,
width: '90%',
backgroundColor: '#080808',
}}
/>
);
};
render() {
if (this.state.isLoading) {
//Loading View while data is loading
return (
<View style={{ flex: 1, paddingTop: 20 }}>
<ActivityIndicator />
</View>
);
}
return (
//ListView to show with textinput used as search bar
<View style={styles.viewStyle}>
<TextInput
style={styles.textInputStyle}
onChangeText={text => this.SearchFilterFunction(text)}
value={this.state.text}
underlineColorAndroid="transparent"
placeholder="Search Here"
/>
<FlatList
data={this.state.dataSource}
ItemSeparatorComponent={this.ListViewItemSeparator}
renderItem={({ item }) => (
<Text style={styles.textStyle}>{item.title}</Text>
)}
enableEmptySections={true}
style={{ marginTop: 10 }}
keyExtractor={(item, index) => index.toString()}
/>
</View>
);
}
}
const styles = StyleSheet.create({
viewStyle: {
justifyContent: 'center',
flex: 1,
marginTop: 40,
padding: 16,
},
textStyle: {
padding: 10,
},
textInputStyle: {
height: 40,
borderWidth: 1,
paddingLeft: 10,
borderColor: '#009688',
backgroundColor: '#FFFFFF',
},
});
Click Hear for more idea
Here is my solution:
You need to have a backup of your data
this.state = {
data: [],
backup: []
}
on search method
search = txt => {
let text = txt.toLowerCase()
let tracks = this.state.backup
let filterTracks = tracks.filter(item => {
if(item.name.toLowerCase().match(text)) {
return item
}
})
this.setState({ data: filterTracks })
}
Explanation: when calling setState on your data it will changed to current state and cannot be changed again.
So backup data will handle to filter your data.
ref - https://medium.freecodecamp.org/how-to-build-a-react-native-flatlist-with-realtime-searching-ability-81ad100f6699
constructor(props) {
super(props);
this.state = {
data: [],
value: ""
};
this.arrayholder = [];
}
Next fetching data :-
_fetchdata = async () => {
const response = await fetch("https://randomuser.me/api?results=10");
const json = await response.json();
this.setState({ data: json.results });
this.arrayholder = json.results;
};
Next define searchFilterFunction :-
searchFilterFunction = text => {
this.setState({
value: text
});
const newData = this.arrayholder.filter(item => {
const itemData = item.email.toLowerCase();
const textData = text.toLowerCase();
return itemData.indexOf(textData) > -1;
});
this.setState({ data: newData });
};
rendering searchView:-
<TextInput
style={{ height: 40, borderColor: "gray", borderWidth: 1 }}
onChangeText={text => this.searchFilterFunction(text)}
/>
Don't forget to import TextInput from "react-native";
You can Search your data by following these steps :
<TextInput onChangeText={(text) => searchData(text)} value={input} />
***Please Note *searchData is my function whom I passing a text prop***
const searchData = (text) => {
const newData = restaurantsData.filter((item) => {
return item.title.search(text) > -1;
});
setRestaurantsData(newData);
setInput(text);
};
Note RestaurantsData is my data array
FYI : data is the subtext to be searched, this is a basic search implemented as the data to be searched is looked into every list item of an array which is a copy of the actual array/array of objects and finally its state is set whether match found or not between 0 to (actualArray.length-1) and the temporary arrayData is rendered if there is at least one match else actualArray is rendered
implementSearch(data) {
temp = [];
var count = 0;
var searchData = data.toUpperCase();
var arr = this.state.personDetail;
for (var i = 0; i < arr.length; i++) {
var actualData = arr[i].name.toUpperCase();
if (actualData.includes(searchData)) {
temp.push(arr[i]);
count++;
}
}
this.setState({
tempArray: temp,
matches: count,
searchValue: data
});
}
Hope this helps
My search method; from #metehan-senol
search = (searchText) => {
this.setState({searchText: searchText});
let filteredData = this.state.data.filter(function (item) {
return item.description.includes(searchText);
});
this.setState({filteredData: filteredData});
};
the search method of could be simplify and Eslint proof like so
search = (searchText) => {
const searched = searchText.toLowerCase();
this.setState(prevState => ({
searchText: searched,
filteredData: prevState.data.filter(item =>
item.description.toLowerCase().includes(searched)
),
}));
};
Do filter by applying
let filterData= data.filter((item) => {
return item.name.toLowerCase().match(text)
})
if (!text || text === '') {
this.setState({
datasource: initial
})
} else if (!Array.isArray(filterData) && !filterData.length) {
// set no data flag to true so as to render flatlist conditionally
this.setState({
noData: true
})
} else if (Array.isArray(filterData)) {
this.setState({
noData: false,`enter code here`
dataSource: filterData
})`enter code here`
}
This is not the best solution in terms of performance, but if you do not have a large amount of data, then feel free to use this function:
searchFilter () {
return this.props.data.filter((item) => {
const regex = new RegExp(this.state.searchInput, "gi")
return item.label.match(regex);
})
}
And then in your FlatList component:
<FlatList
data={this.searchFilter()}
renderItem={this.renderItem}
keyExtractor={(item) => item.value}
/>
const SearchUser = (e) =>{
console.log(e)
const setProject = Project.filter(item => item.name.toLowerCase().includes(e.toLowerCase()) )
console.log(setProject)
setfetch(setProject)
}