I have missed a onSearch callback after a search was typed in. So that i can refetch data from the backend with the searched input. This is useful for large select lists and show only subsets of a list.
And i have optimized the multiselect list, for a better handling of selectedval, now it is possible to get the component defaultOptions and in the furture it is not required to put the set[State] methode inside the component. This behaivor make it hard to handle the component.
diff --git a/node_modules/react-native-dropdown-select-list/components/MultipleSelectList.tsx b/node_modules/react-native-dropdown-select-list/components/MultipleSelectList.tsx
index a3bba1d..89161be 100644
--- a/node_modules/react-native-dropdown-select-list/components/MultipleSelectList.tsx
+++ b/node_modules/react-native-dropdown-select-list/components/MultipleSelectList.tsx
@@ -1,384 +1,369 @@
import React from 'react';
import {
- View,
- Text,
- StyleSheet,
- Image,
- TouchableOpacity,
- ScrollView,
- Animated,
- TextInput,
- ViewStyle,
- Pressable,
- Keyboard
-} from 'react-native';
+ View,
+ Text,
+ StyleSheet,
+ Image,
+ TouchableOpacity,
+ ScrollView,
+ Animated,
+ TextInput,
+ ViewStyle,
+ Pressable,
+ Keyboard
+} from 'react-native';
import { MultipleSelectListProps } from '..';
type L1Keys = { key?: any; value?: any; disabled?: boolean | undefined }
const MultipleSelectList: React.FC<MultipleSelectListProps> = ({
- fontFamily,
- setSelected,
- placeholder,
- boxStyles,
- inputStyles,
- dropdownStyles,
- dropdownItemStyles,
- dropdownTextStyles,
- maxHeight,
- data,
- searchicon = false,
- arrowicon = false,
- closeicon = false,
- search = true,
- searchPlaceholder = "search",
- onSelect = () => {},
- label,
- notFoundText = "No data found",
- disabledItemStyles,
- disabledTextStyles,
- disabledCheckBoxStyles,
- labelStyles,
- badgeStyles,
- badgeTextStyles,
- checkBoxStyles,
- save = 'key',
- dropdownShown = false
- }) => {
-
- const oldOption = React.useRef(null)
- const [_firstRender,_setFirstRender] = React.useState<boolean>(true);
- const [dropdown, setDropdown] = React.useState<boolean>(dropdownShown);
- const [selectedval, setSelectedVal] = React.useState<any>([]);
- const [height,setHeight] = React.useState<number>(350)
- const animatedvalue = React.useRef(new Animated.Value(0)).current;
- const [filtereddata,setFilteredData] = React.useState(data);
-
-
- const slidedown = () => {
- setDropdown(true)
-
- Animated.timing(animatedvalue,{
- toValue:height,
- duration:500,
- useNativeDriver:false,
-
- }).start()
- }
- const slideup = () => {
-
- Animated.timing(animatedvalue,{
- toValue:0,
- duration:500,
- useNativeDriver:false,
+ onSearch,
+ selectedText,
+ fontFamily,
+ setSelected,
+ placeholder,
+ boxStyles,
+ inputStyles,
+ dropdownStyles,
+ dropdownItemStyles,
+ dropdownTextStyles,
+ maxHeight,
+ data,
+ searchicon = false,
+ arrowicon = false,
+ closeicon = false,
+ search = true,
+ searchPlaceholder = 'search',
+ onSelect = () => {},
+ label,
+ notFoundText = 'No data found',
+ disabledItemStyles,
+ disabledTextStyles,
+ disabledCheckBoxStyles,
+ defaultOptions,
+ labelStyles,
+ badgeStyles,
+ badgeTextStyles,
+ checkBoxStyles,
+ save = 'key',
+ dropdownShown = false
+}) => {
+
+ const [ _firstRender, _setFirstRender ] = React.useState<boolean>(true);
+ const [ dropdown, setDropdown ] = React.useState<boolean>(dropdownShown);
+ const [ selectedval, setSelectedVal ] = React.useState<any>(defaultOptions ?? []);
+ const [ height, setHeight ] = React.useState<number>(350);
+ const animatedvalue = React.useRef(new Animated.Value(0)).current;
+ const [ filtereddata, setFilteredData ] = React.useState(data);
+
+
+ const slidedown = () => {
+ setDropdown(true);
+
+ Animated.timing(animatedvalue, {
+ toValue: height,
+ duration: 500,
+ useNativeDriver: false,
+
+ }).start();
+ };
+ const slideup = () => {
+
+ Animated.timing(animatedvalue, {
+ toValue: 0,
+ duration: 500,
+ useNativeDriver: false,
+
+ }).start(() => setDropdown(false));
+ };
+
+ React.useEffect(() => {
+ if (maxHeight)
+ setHeight(maxHeight);
+ }, [ maxHeight ]);
+
+ React.useEffect(() => {
+ setSelectedVal(defaultOptions);
+ }, [ defaultOptions ]);
+
+ React.useEffect(() => {
+ setFilteredData(data);
+ }, [ data ]);
+
+ React.useEffect(() => {
+ if (!_firstRender) {
+ if (dropdownShown)
+ slidedown();
+ else
+ slideup();
- }).start(() => setDropdown(false))
}
- React.useEffect( () => {
- if(maxHeight)
- setHeight(maxHeight)
- },[maxHeight])
-
-
- React.useEffect(() => {
- setFilteredData(data);
- },[data])
-
-
- React.useEffect(() => {
- if(_firstRender){
- _setFirstRender(false);
- return;
- }
- onSelect()
-
- },[selectedval])
-
- React.useEffect(() => {
- if(!_firstRender){
- if(dropdownShown)
+ }, [ dropdownShown ]);
+
+
+ return (
+ <View>
+ {
+ (dropdown && search)
+ ?
+ <View style={[ styles.wrapper, boxStyles ]}>
+ <View style={{ flexDirection: 'row', alignItems: 'center', flex: 1 }}>
+ {
+ (!searchicon)
+ ?
+ <Image
+ source={require('../assets/images/search.png')}
+ resizeMode="contain"
+ style={{ width: 20, height: 20, marginRight: 7 }}
+ />
+ :
+ searchicon
+ }
+
+ <TextInput
+ placeholder={searchPlaceholder}
+ onChangeText={(val) => {
+ onSearch && onSearch(val);
+ let result = data.filter((item: L1Keys) => {
+ val.toLowerCase();
+ let row = item.value.toLowerCase();
+ return row.search(val.toLowerCase()) > -1;
+ });
+ setFilteredData(result);
+ }}
+ style={[ { padding: 0, height: 20, flex: 1, fontFamily }, inputStyles ]}
+ />
+ <TouchableOpacity onPress={() => {
+ slideup();
+ // setTimeout(() => setFilteredData(data), 800)
+ }}>
+ {
+ (!closeicon)
+ ?
+ <Image
+ source={require('../assets/images/close.png')}
+ resizeMode="contain"
+ style={{ width: 17, height: 17 }}
+ />
+ :
+ closeicon
+ }
+ </TouchableOpacity>
+
+
+ </View>
+
+ </View>
+ :
+
+ (selectedval?.length > 0) ?
+ <TouchableOpacity style={[ styles.wrapper, boxStyles ]} onPress={() => {
+ if (!dropdown) {
+ Keyboard.dismiss();
slidedown();
- else
+ }
+ else {
slideup();
-
- }
-
- },[dropdownShown])
-
-
-
-
-
-
- return(
- <View>
- {
- (dropdown && search)
- ?
- <View style={[styles.wrapper,boxStyles]}>
- <View style={{flexDirection:'row',alignItems:'center',flex:1}}>
- {
- (!searchicon)
- ?
- <Image
- source={require('../assets/images/search.png')}
- resizeMode='contain'
- style={{width:20,height:20,marginRight:7}}
- />
- :
- searchicon
- }
-
- <TextInput
- placeholder={searchPlaceholder}
- onChangeText={(val) => {
- let result = data.filter((item: L1Keys) => {
- val.toLowerCase();
- let row = item.value.toLowerCase()
- return row.search(val.toLowerCase()) > -1;
- });
- setFilteredData(result)
- }}
- style={[{padding:0,height:20,flex:1,fontFamily},inputStyles]}
- />
- <TouchableOpacity onPress={() => {
- slideup()
- // setTimeout(() => setFilteredData(data), 800)
- }} >
- {
- (!closeicon)
- ?
- <Image
- source={require('../assets/images/close.png')}
- resizeMode='contain'
- style={{width:17,height:17}}
- />
- :
- closeicon
- }
- </TouchableOpacity>
-
-
+ }
+ }}>
+ <View>
+ <Text style={[ { fontWeight: '600', fontFamily }, labelStyles ]}>{label}</Text>
+ <View style={{ flexDirection: 'row', marginBottom: 8, flexWrap: 'wrap' }}>
+ {
+ selectedval?.map((item, index) => {
+ return (
+ <View key={index} style={[
+ { backgroundColor: 'gray', paddingHorizontal: 20, paddingVertical: 5, borderRadius: 50, marginRight: 10, marginTop: 10 },
+ badgeStyles
+ ]}>
+ <Text style={[ { color: 'white', fontSize: 12, fontFamily }, badgeTextStyles ]}>{item?.value ?? item?.key ?? item}</Text>
</View>
-
- </View>
- :
-
- (selectedval?.length > 0 )
-
- ?
- <TouchableOpacity style={[styles.wrapper,boxStyles]} onPress={() => { if(!dropdown){ Keyboard.dismiss(); slidedown() }else{ slideup() } }} >
- <View>
- <Text style={[{fontWeight:'600',fontFamily},labelStyles]}>{ label }</Text>
- <View style={{flexDirection:'row',marginBottom:8,flexWrap:'wrap'}}>
- {
- selectedval?.map((item,index) => {
- return (
- <View key={index} style={[{backgroundColor:'gray',paddingHorizontal:20,paddingVertical:5,borderRadius:50,marginRight:10,marginTop:10}, badgeStyles]}>
- <Text style={[{color:'white',fontSize:12,fontFamily}, badgeTextStyles]}>{item}</Text>
- </View>
- )
- })
- }
+ );
+ })
+ }
+ </View>
+ </View>
+ </TouchableOpacity> :
+ <TouchableOpacity style={[ styles.wrapper, boxStyles ]} onPress={() => {
+ if (!dropdown) {
+ Keyboard.dismiss();
+ slidedown();
+ }
+ else {
+ slideup();
+ }
+ }}>
+ <Text style={[ { fontFamily }, inputStyles ]}>{(!selectedval.length) ? (placeholder) ? placeholder : 'Select option' : ''}</Text>
+ {
+ (!arrowicon)
+ ?
+ <Image
+ source={require('../assets/images/chevron.png')}
+ resizeMode="contain"
+ style={{ width: 20, height: 20 }}
+ />
+ :
+ arrowicon
+ }
+
+ </TouchableOpacity>
+ }
+
+ {
+ (dropdown)
+ ?
+ <Animated.View style={[ { maxHeight: animatedvalue }, styles.dropdown, dropdownStyles ]}>
+ <View style={[ { maxHeight: height } ]}>
+ <ScrollView contentContainerStyle={{ paddingVertical: 10 }} nestedScrollEnabled={true}>
+
+ {
+ (filtereddata.length >= 1) ?
+ filtereddata.map((item: L1Keys, index: number) => {
+ let key = item.key ?? item.value ?? item;
+ let value = item.value ?? item;
+ let disabled = item.disabled ?? false;
+ const checked = selectedval.find((item) => item.key === key);
+ if (disabled) {
+ return (
+ <TouchableOpacity style={[ styles.disabledoption, disabledItemStyles ]} key={index}>
+ <View style={[
+ {
+ width: 15,
+ height: 15,
+ marginRight: 10,
+ borderRadius: 3,
+ justifyContent: 'center',
+ alignItems: 'center',
+ backgroundColor: '#c4c5c6'
+ }, disabledCheckBoxStyles
+ ]}>
+
+ {
+ checked ?
+ <Image
+ key={index}
+ source={require('../assets/images/check.png')}
+ resizeMode="contain"
+ style={[ { width: 8, height: 8, paddingLeft: 7 } ]}
+ /> : null
+ }
</View>
- </View>
- </TouchableOpacity>
- :
- <TouchableOpacity style={[styles.wrapper,boxStyles]} onPress={() => { if(!dropdown){ Keyboard.dismiss(); slidedown() }else{ slideup() } }}>
- <Text style={[{fontFamily},inputStyles]}>{ (selectedval == "") ? (placeholder) ? placeholder : 'Select option' : selectedval }</Text>
- {
- (!arrowicon)
- ?
- <Image
- source={require('../assets/images/chevron.png')}
- resizeMode='contain'
- style={{width:20,height:20}}
- />
- :
- arrowicon
- }
-
+ <Text style={[ { fontFamily, color: '#c4c5c6' }, disabledTextStyles ]}>{value}</Text>
+ </TouchableOpacity>
+ );
+ }
+ else {
+ return (
+ <TouchableOpacity style={[ styles.option, dropdownItemStyles ]} key={index} onPress={() => {
+ let _newSelectedval: any = [];
+ if (checked) {
+ _newSelectedval = selectedval.filter((item: any) => item.key !== key);
+ }
+ else {
+ _newSelectedval = [ ...selectedval, item ];
+ }
+ setSelectedVal(_newSelectedval);
+ // @ts-ignore
+ onSelect(_newSelectedval.map((item) => item?.key ?? item?.value ?? item));
+ }}>
+ <View style={[
+ {
+ width: 15,
+ height: 15,
+ borderWidth: 1,
+ marginRight: 10,
+ borderColor: 'gray',
+ borderRadius: 3,
+ justifyContent: 'center',
+ alignItems: 'center'
+ }, checkBoxStyles
+ ]}>
+ { checked ?
+ <Image
+ key={index}
+ source={require('../assets/images/check.png')}
+ resizeMode="contain"
+ style={{ width: 8, height: 8, paddingLeft: 7 }}
+ /> : null
+ }
+ </View>
+ <Text style={[ { fontFamily }, dropdownTextStyles ]}>{value}</Text>
+ </TouchableOpacity>
+ );
+ }
+
+ }) :
+ <TouchableOpacity style={[ styles.option, dropdownItemStyles ]} onPress={() => {
+ setSelected(undefined);
+ setSelectedVal('');
+ slideup();
+ setTimeout(() => setFilteredData(data), 800);
+ }}>
+ <Text style={dropdownTextStyles}>{notFoundText}</Text>
</TouchableOpacity>
- }
-
- {
- (dropdown)
- ?
- <Animated.View style={[{maxHeight:animatedvalue},styles.dropdown, dropdownStyles]}>
- <View style={[{maxHeight:height}]}>
- <ScrollView contentContainerStyle={{paddingVertical:10}} nestedScrollEnabled={true}>
-
- {
- (filtereddata.length >= 1)
- ?
- filtereddata.map((item: L1Keys,index: number) => {
- let key = item.key ?? item.value ?? item;
- let value = item.value ?? item;
- let disabled = item.disabled ?? false;
- if(disabled){
- return(
- <TouchableOpacity style={[styles.disabledoption,disabledItemStyles]} key={index}>
- <View style={[{width:15,height:15,marginRight:10,borderRadius:3,justifyContent:'center',alignItems:'center',backgroundColor:'#c4c5c6'},disabledCheckBoxStyles]}>
-
- {
- (selectedval?.includes(value))
- ?
-
- <Image
- key={index}
- source={require('../assets/images/check.png')}
- resizeMode='contain'
- style={[{width:8,height:8,paddingLeft:7}]}
- />
-
- :
- null
-
- }
- </View>
- <Text style={[{fontFamily,color:'#c4c5c6'},disabledTextStyles]}>{value}</Text>
- </TouchableOpacity>
- )
- }else{
- return(
- <TouchableOpacity style={[styles.option,dropdownItemStyles]} key={index} onPress={ () => {
-
-
- let existing = selectedval?.indexOf(value)
-
-
- // console.log(existing);
-
- if(existing != -1 && existing != undefined){
-
- let sv = [...selectedval];
- sv.splice(existing,1)
- setSelectedVal(sv);
-
-
- setSelected((val: any) => {
- let temp = [...val];
- temp.splice(existing,1)
- return temp;
- });
-
- // onSelect()
- }else{
- if(save === 'value'){
- setSelected((val: any) => {
- let temp = [...new Set([...val,value])];
- return temp;
- })
- }else{
- setSelected((val: any) => {
- let temp = [...new Set([...val,key])];
- return temp;
- })
- }
-
- setSelectedVal((val: any )=> {
- let temp = [...new Set([...val,value])];
- return temp;
- })
-
-
- // onSelect()
- }
-
-
-
- }}>
- <View style={[{width:15,height:15,borderWidth:1,marginRight:10,borderColor:'gray',borderRadius:3,justifyContent:'center',alignItems:'center'},checkBoxStyles]}>
-
- {
- (selectedval?.includes(value))
- ?
-
- <Image
- key={index}
- source={require('../assets/images/check.png')}
- resizeMode='contain'
- style={{width:8,height:8,paddingLeft:7}}
- />
-
- :
- null
-
- }
-
-
-
-
- </View>
- <Text style={[{fontFamily},dropdownTextStyles]}>{value}</Text>
- </TouchableOpacity>
- )
- }
-
- })
- :
- <TouchableOpacity style={[styles.option,dropdownItemStyles]} onPress={ () => {
- setSelected(undefined)
- setSelectedVal("")
- slideup()
- setTimeout(() => setFilteredData(data), 800)
- }}>
- <Text style={dropdownTextStyles}>{notFoundText}</Text>
- </TouchableOpacity>
- }
-
-
-
- </ScrollView>
-
- {
- (selectedval?.length > 0)
- ?
- <Pressable>
- <View style={{flexDirection:'row', justifyContent:'space-between',alignItems:'center',paddingLeft:20}}>
- <Text style={{marginRight:20,fontWeight:'600',fontFamily}}>Selected</Text>
- <View style={{height: 1, flex: 1, backgroundColor: 'gray'}} />
- </View>
- <View style={{flexDirection:'row',paddingHorizontal:20,marginBottom:20,flexWrap:'wrap'}}>
-
- {
- selectedval?.map((item,index) => {
- return (
- <View key={index} style={[{backgroundColor:'gray',paddingHorizontal:20,paddingVertical:5,borderRadius:50,marginRight:10,marginTop:10},badgeStyles]}>
- <Text style={[{color:'white',fontSize:12,fontFamily},badgeTextStyles]}>{item}</Text>
- </View>
- )
- })
- }
-
- </View>
- </Pressable>
- :
- null
- }
-
-
-
- </View>
-
- </Animated.View>
- :
- null
- }
-
-
- </View>
- )
-}
+ }
+
+
+ </ScrollView>
+
+ { !!selectedval?.length && (
+ <Pressable>
+ <View style={{ flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', paddingLeft: 20 }}>
+ <Text style={{ marginRight: 20, fontWeight: '600', fontFamily }}>{selectedText || 'Selected'}</Text>
+ <View style={{ height: 1, flex: 1, backgroundColor: 'gray' }}/>
+ </View>
+ <View style={{ flexDirection: 'row', paddingHorizontal: 20, marginBottom: 20, flexWrap: 'wrap' }}>
+ {
+ selectedval?.map((item, index) => {
+ return (
+ <View key={index} style={[
+ {
+ backgroundColor: 'gray',
+ paddingHorizontal: 20,
+ paddingVertical: 5,
+ borderRadius: 50,
+ marginRight: 10,
+ marginTop: 10
+ }, badgeStyles
+ ]}>
+ <Text style={[ { color: 'white', fontSize: 12, fontFamily }, badgeTextStyles ]}>{item?.value ?? item?.key ?? item}</Text>
+ </View>
+ );
+ })
+ }
+
+ </View>
+ </Pressable>
+ )}
+ </View>
+
+ </Animated.View>
+ :
+ null
+ }
+
+
+ </View>
+ );
+};
export default MultipleSelectList;
const styles = StyleSheet.create({
- wrapper:{ borderWidth:1,borderRadius:10,borderColor:'gray',paddingHorizontal:20,paddingVertical:12,flexDirection:'row',justifyContent:'space-between',marginBottom:10 },
- dropdown:{ borderWidth:1,borderRadius:10,borderColor:'gray',overflow:'hidden'},
- option:{ paddingHorizontal:20,paddingVertical:8,flexDirection:'row',alignItems:'center'},
- disabledoption:{ paddingHorizontal:20,paddingVertical:8,flexDirection:'row',alignItems:'center', backgroundColor:'whitesmoke'}
-
-})
+ wrapper: {
+ borderWidth: 1,
+ borderRadius: 10,
+ borderColor: 'gray',
+ paddingHorizontal: 20,
+ paddingVertical: 12,
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ marginBottom: 10
+ },
+ dropdown: { borderWidth: 1, borderRadius: 10, borderColor: 'gray', overflow: 'hidden' },
+ option: { paddingHorizontal: 20, paddingVertical: 8, flexDirection: 'row', alignItems: 'center' },
+ disabledoption: { paddingHorizontal: 20, paddingVertical: 8, flexDirection: 'row', alignItems: 'center', backgroundColor: 'whitesmoke' }
+
+});
diff --git a/node_modules/react-native-dropdown-select-list/components/SelectList.tsx b/node_modules/react-native-dropdown-select-list/components/SelectList.tsx
index 234a7e1..9b38ceb 100644
--- a/node_modules/react-native-dropdown-select-list/components/SelectList.tsx
+++ b/node_modules/react-native-dropdown-select-list/components/SelectList.tsx
@@ -16,6 +16,7 @@ import { SelectListProps } from '..';
type L1Keys = { key?: any; value?: any; disabled?: boolean | undefined }
const SelectList: React.FC<SelectListProps> = ({
+ onSearch,
setSelected,
placeholder,
boxStyles,
@@ -139,6 +140,7 @@ const SelectList: React.FC<SelectListProps> = ({
<TextInput
placeholder={searchPlaceholder}
onChangeText={(val) => {
+ onSearch && onSearch(val)
let result = data.filter((item: L1Keys) => {
val.toLowerCase();
let row = item.value.toLowerCase()
Hi! 👋
Firstly, thanks for your work on this project! 🙂
Today I used patch-package to patch
react-native-dropdown-select-list@2.0.5for the project I'm working on.I have missed a onSearch callback after a search was typed in. So that i can refetch data from the backend with the searched input. This is useful for large select lists and show only subsets of a list.
And i have optimized the multiselect list, for a better handling of selectedval, now it is possible to get the component defaultOptions and in the furture it is not required to put the set[State] methode inside the component. This behaivor make it hard to handle the component.
Here is the diff that solved my problem:
This issue body was partially generated by patch-package.