npm.io
1.2.5 • Published 4 years ago

react-native-autocomplete-1060

Licence
MIT
Version
1.2.5
Deps
5
Size
35 kB
Vulns
0
Weekly
0
Stars
244

react-native-autocomplete-dropdown

Dropdown Item picker with search and autocomplete (typeahead) functionality for react native

license npm npm

Demo

Run expo snack demo @onmotion/react-native-autocomplete-dropdown

Nav

Installation

Run: npm install --save react-native-autocomplete-dropdown or yarn add react-native-autocomplete-dropdown

Post-install Steps

Make sure react-native-vector-icons is installed. Follow the guides https://github.com/oblador/react-native-vector-icons

yarn add react-native-vector-icons

iOS

Run: npx pod-install for install react-native-vector-icons dependency (if not installed yet).

Android

Follow the guides from https://github.com/oblador/react-native-vector-icons#android for install react-native-vector-icons dependency (if not installed yet).

Usage

import the package

import { AutocompleteDropdown } from 'react-native-autocomplete-dropdown';
Dataset item format

dataSet property must be an array of objects or null. Object required keys are:

{
    id: 'some uniq string id',
    title: 'list item title'
}
Example with local Dataset
const [selectedItem, setSelectedItem] = useState(null);

<AutocompleteDropdown
  clearOnFocus={false}
  closeOnBlur={true}
  closeOnSubmit={false}
  initialValue={{ id: '2' }} // or just '2'
  onSelectItem={setSelectedItem}
  dataSet={[
    { id: '1', title: 'Alpha' },
    { id: '2', title: 'Beta' },
    { id: '3', title: 'Gamma' },
  ]}
/>;
Example with remote requested Dataset
import React, { memo, useCallback, useRef, useState } from 'react'
import { Button, Dimensions, Text, View, Platform } from 'react-native'
import { AutocompleteDropdown } from 'react-native-autocomplete-dropdown'

import Feather from 'react-native-vector-icons/Feather'
Feather.loadFont()

export const RemoteDataSetExample2 = memo(() => {
  const [loading, setLoading] = useState(false)
  const [suggestionsList, setSuggestionsList] = useState(null)
  const [selectedItem, setSelectedItem] = useState(null)
  const dropdownController = useRef(null)

  const searchRef = useRef(null)

  const getSuggestions = useCallback(async q => {
    const filterToken = q.toLowerCase()
    console.log('getSuggestions', q)
    if (typeof q !== 'string' || q.length < 3) {
      setSuggestionsList(null)
      return
    }
    setLoading(true)
    const response = await fetch('https://jsonplaceholder.typicode.com/posts')
    const items = await response.json()
    const suggestions = items
      .filter(item => item.title.toLowerCase().includes(filterToken))
      .map(item => ({
        id: item.id,
        title: item.title,
      }))
    setSuggestionsList(suggestions)
    setLoading(false)
  }, [])

  const onClearPress = useCallback(() => {
    setSuggestionsList(null)
  }, [])

  const onOpenSuggestionsList = useCallback(isOpened => {}, [])

  return (
    <>
      <View
        style={[
          { flex: 1, flexDirection: 'row', alignItems: 'center' },
          Platform.select({ ios: { zIndex: 1 } }),
        ]}>
        <AutocompleteDropdown
          ref={searchRef}
          controller={controller => {
            dropdownController.current = controller
          }}
          // initialValue={'1'}
          direction={Platform.select({ ios: 'down' })}
          dataSet={suggestionsList}
          onChangeText={getSuggestions}
          onSelectItem={item => {
            item && setSelectedItem(item.id)
          }}
          debounce={600}
          suggestionsListMaxHeight={Dimensions.get('window').height * 0.4}
          onClear={onClearPress}
          //  onSubmit={(e) => onSubmitSearch(e.nativeEvent.text)}
          onOpenSuggestionsList={onOpenSuggestionsList}
          loading={loading}
          useFilter={false} // set false to prevent rerender twice
          textInputProps={{
            placeholder: 'Type 3+ letters (dolo...)',
            autoCorrect: false,
            autoCapitalize: 'none',
            style: {
              borderRadius: 25,
              backgroundColor: '#383b42',
              color: '#fff',
              paddingLeft: 18,
            },
          }}
          rightButtonsContainerStyle={{
            right: 8,
            height: 30,

            alignSelf: 'center',
          }}
          inputContainerStyle={{
            backgroundColor: '#383b42',
            borderRadius: 25,
          }}
          suggestionsListContainerStyle={{
            backgroundColor: '#383b42',
          }}
          containerStyle={{ flexGrow: 1, flexShrink: 1 }}
          renderItem={(item, text) => <Text style={{ color: '#fff', padding: 15 }}>{item.title}</Text>}
          ChevronIconComponent={<Feather name="chevron-down" size={20} color="#fff" />}
          ClearIconComponent={<Feather name="x-circle" size={18} color="#fff" />}
          inputHeight={50}
          showChevron={false}
          closeOnBlur={false}
          //  showClear={false}
        />
        <View style={{ width: 10 }} />
        <Button style={{ flexGrow: 0 }} title="Toggle" onPress={() => dropdownController.current.toggle()} />
      </View>
      <Text style={{ color: '#668', fontSize: 13 }}>Selected item id: {JSON.stringify(selectedItem)}</Text>
    </>
  )
})

More examples see at https://github.com/onmotion/react-native-autocomplete-dropdown/tree/main/example

Run

cd example
yarn install
yarn add react-native-vector-icons
npx pod-install
npm run ios

Options

| Option | Description | Type | Default | |--- |--- |--- |--- | | dataSet | set of list items | array | null | | initialValue | string (id) or object that contain id | string | object | null | | loading | loading state | bool | false | | useFilter | whether use local filter by dataSet (useful set to false for remote filtering to prevent rerender twice) | bool | true | | showClear | show clear button | bool | true | | showChevron | show chevron (open/close) button | bool | true | | closeOnBlur | whether to close dropdown on blur | bool | false | | closeOnSubmit | whether to close dropdown on submit | bool | false | | clearOnFocus | whether to clear typed text on focus | bool | true | | debounce | wait ms before call onChangeText | number | 0 | | suggestionsListMaxHeight | max height of dropdown | number | 200 | | direction | "up" or "down" | string | down + auto calculate | | position | "relative" or "absolute" | string | relative | | bottomOffset | for calculate dropdown direction (e.g. tabbar) | number | 0 | | onChangeText | event textInput onChangeText | function | | | onSelectItem | event onSelectItem | function | | | onOpenSuggestionsList | event onOpenSuggestionsList | function | | | onChevronPress | event onChevronPress | function | | | onClear | event on clear button press | function | | | onSubmit | event on submit KB button press | function | | | onBlur | event fired on text input blur | function | | | onFocus | event on focus text input | function | | | renderItem | JSX for render item (item, searchText) => JSX \| null if return null then the element will not be displayed | function | item.title | | controller | return reference to module controller with methods close, open, toggle, clear, setInputText, setItem | function | | | containerStyle | | ViewStyle | | | rightButtonsContainerStyle | | ViewStyle | | | suggestionsListContainerStyle | | ViewStyle | | | suggestionsListTextStyle | | TextStyle | styles of suggestions list text items | | ChevronIconComponent | | React.Component | Feather chevron icon | | ClearIconComponent | | React.Component | Feather x icon | | ScrollViewComponent | removed in 2.0.0 based on FlatList | React.Component name | ScrollView that provide suggestions content | | EmptyResultComponent | replace the default `` Component on empty result | React.Component | | | InputComponent | input element component | React.ComponentType | TextInput | | emptyResultText | replace the default "Nothing found" text on empty result | string | "Nothing found" | | textInputProps | text input props | TextInputProps | | | flatListProps | props for \ component | FlatListProps\ | |

Troubleshooting

zIndex hell on iOS

As decribed here https://docs.expo.dev/ui-programming/z-index/ on iOS for absolute positioned items we must respect the zIndex of the element parent.

So for example if you do smth like

          <View style={[styles.section]}>
            <Text style={styles.sectionTitle}>First</Text>
            <AutocompleteDropdown
              dataSet={[
                { id: '1', title: 'Alpha' },
                { id: '2', title: 'Beta' },
                { id: '3', title: 'Gamma' },
              ]}
            />
          </View>
          <View style={[styles.section]}>
            <Text style={styles.sectionTitle}>Second</Text>
            <AutocompleteDropdown
              dataSet={[
                { id: '1', title: 'Alpha' },
                { id: '2', title: 'Beta' },
                { id: '3', title: 'Gamma' },
              ]}
            />
          </View>

you would see Screenshot 2022-04-24 at 20 59 38

But if it change with calculated zIndex:

          <View
            style={[styles.section, Platform.select({ ios: { zIndex: 10 } })]}>
            <Text style={styles.sectionTitle}>First</Text>
            <AutocompleteDropdown
              dataSet={[
                { id: '1', title: 'Alpha' },
                { id: '2', title: 'Beta' },
                { id: '3', title: 'Gamma' },
              ]}
            />
          </View>
          <View
            style={[styles.section, Platform.select({ ios: { zIndex: 9 } })]}>
            <Text style={styles.sectionTitle}>Second</Text>
            <AutocompleteDropdown
              dataSet={[
                { id: '1', title: 'Alpha' },
                { id: '2', title: 'Beta' },
                { id: '3', title: 'Gamma' },
              ]}
            />
          </View>

it will be rendered as expected Screenshot 2022-04-24 at 21 03 16

And the same, if you want render dropdown list to up direction, you should switch zIndexes respectively

More info about this behaviour: https://docs.expo.dev/ui-programming/z-index/

Keywords