Create a autocomplete search dropdown picker with tree view in React Native

December 16, 2021

Create a autocomplete search dropdown picker with tree view in React Native/React

Create a autocomplete search dropdown picker with tree view in React Native

App.js

import React,{useRef} from 'react'
import { SafeAreaView,Text,View } from 'react-native';
import AutoCompletePicker from './AutoCompletePicker';

const Data=[{"entityId":1,"name":"Test Root",
             "entityTypeName":"Test",
             "parentValueId":null},
            {"entityId":2,"name":"Test Industries",
             "entityTypeName":"Test Name",
             "parentValueId":null}]
          
const App = () => {

  const fieldRef = useRef(null);
  const FocusTextInputFxn = () =>{
     fieldRef?.current.focus()
  }
  const ClearFxn=()=>{
    fieldRef?.current.clear();
  }
  const SetItemFxn=(ItemData)=>{
      console.info(ItemData)
  }
  
const ConvertFlatToTree = (items, entityId = null, link = 'parentValueId') =>

items.filter(item => item[link] === entityId)

.map(item => ({ ...item, children: ConvertFlatToTree(items, item.entityI

d) }));

  return (
    <SafeAreaView> 
      <AutoCompletePicker
        fieldRef={fieldRef}
        label="Email"
        SetItem={(ItemData)=>SetItemFxn(ItemData)}
        focusTextInput={FocusTextInputFxn}
        Clear={ClearFxn}
        Data={ConvertFlatToTree(Data)}
      />
      <View style={{margin:10}}>
          <Text>
          Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, 
          when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries,
          </Text>
        </View>
    </SafeAreaView>
  )
}

export default App

AutoCompletePicker.js

import React,{useState} from 'react'
import { View,ScrollView,TouchableOpacity,
    Dimensions,
    StyleSheet
} from 'react-native';
import { TextInput } from 'react-native-paper'
import styled from 'styled-components/native';
import AwesomeIcon from 'react-native-vector-icons/FontAwesome';

const { width, height } = Dimensions.get('window');
const size = size => (size / 100) * width;
const hp = hp => (hp / 100) * height;
const wp = wp => (wp / 100) * width;

const styles=StyleSheet.create({
    item: {
        height: hp(5),
        paddingHorizontal: wp(5),
        justifyContent: 'center',
    },
    itemText: {
        color: 'black'
    },
    list: {
        width: wp(96),
        height: hp(30),
        maxHeight: hp(30)
    },
    listContainer: { 
        padding: size(1.75),
    }
})



  const RenderIcons=({clear,DropDownToggle})=>{
      return <View style={{flexDirection:'row',alignItems:'center'}}>
                <AwesomeIcon 
                onPress={DropDownToggle}
                name="caret-down" size={22} style={{margin:8}}/>
                <AwesomeIcon 
                onPress={clear}
                name="close" size={22} style={{margin:8}}/>
            </View>
  }

  const Item = ({item,Selected}) => {
   return  <View 
          style={styles.item}>
           <ListText 
          Selected={Selected} 
        style={styles.itemText}>{item.name}</ListText>
    </View>
  }

const CustomInput = ({value,fieldRef,right,...props}) => (
    <TextInput
      { ...props }
      ref={fieldRef}
      value={value}
      render={ (inputProps) => (
        <InputContainer>
          <Input { ...inputProps } />
          {right && (
            <AdornmentContainer>
              {right}
            </AdornmentContainer>
          )}
        </InputContainer>
      ) }
     />
  )

const AutoCompletePicker = ({Data,fieldRef,focusTextInput,Clear,label,SetItem}) => {

    const [ListData, SetListData] = useState(Data);
    const [DropDownState, SetDropDownState] = useState(false);
    const [ActiveEntityID, SetActiveEntityID] = useState(null);
    const [input, setInput] = useState(null);
    

    const OnChangeTextFxn=(text)=>{
        let textValue = text.toLowerCase();
        let StoreDataForRest = Data;
        if (!text || text === '') {
            SetListData(Data)
        }
        let FilterLabel = StoreDataForRest.filter((item) => {
          return item.name.toLowerCase().match(textValue)
        })
        SetListData(FilterLabel)
        setInput(text)
      }

  const ClearAndClose=()=>{
        Clear() 
        setInput(null)
        SetListData(Data)
  }

    return (
        <View style={{margin:6}}> 
            <CustomInput
                fieldRef={fieldRef}
                value={input}
                onFocus={()=>SetDropDownState(true)}
                onBlur={()=>SetDropDownState(false)}
                mode="outlined"
                onChangeText={(text) => OnChangeTextFxn(text)}
                label={label}
                right={ 
                <RenderIcons 
                clear={ClearAndClose} 
                 DropDownToggle={focusTextInput} 
                /> 
                 }
            />
            {DropDownState&&
            <>
            /*
            IF YOU ONLY NEED SEARCHING AND AUTOCOMPLETE THIS IS PREFRECT
            IF YOU NEED NESTED TREE VIEW JUST USED THE COMPONET THAT IS 
             https://www.npmjs.com/package/react-native-nested-listview
            You can replace with  scrollview with nested-listview
            */
            {ListData?.length!==0&&
                <ScrollView
                    keyboardShouldPersistTaps='handled'
                    style={styles.list}
                    contentContainerStyle={styles.listContainer}
                    >
                    {
                        ListData.map((item, index) => ( 
                            <TouchableOpacity 
                             onPress={()=>{ 
                                        setInput(item?.name)
                                        fieldRef?.current.blur(); 
                                        SetItem(item) 
                                        SetActiveEntityID(item?.entityId)
                                  }} 
                                key={index}>
                                 <Item item={item}
                                  Selected={ActiveEntityID==item?.entityId}
                                 />
                                {ListData.length !== (index + 1) ? <Separator/> : null}
                            </TouchableOpacity>
                        ))
                    }
                 </ScrollView>
                 }
                {ListData?.length===0&&
                    <NoItemFound>No Item Found..</NoItemFound>
                }
                </>
            }
        </View>
    )
}

export default AutoCompletePicker;


const InputContainer = styled.View`
  flex-direction: row;
`
const Input = styled.TextInput`
  flex: 1;
`
const AdornmentContainer = styled.View`
  align-items: center;
  justify-content: center;
  padding: 0 10px;
`
const Separator = styled.View`
    border-bottom-width: 1px;
    border-bottom-color:#c2c2c2
`
const ListText = styled.Text`
    font-weight: ${props=>props.Selected?"bold":'normal'};
`
const NoItemFound = styled.Text`
    font-weight:bold;
    margin: 10px;
    text-align: center;
`

Written by Manoj Bhardwaj who lives and works in Dharamshala Himachal Pradesh (India). My stackoverflow