Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[AutoComplete] Make Stateless and Composable #5062

Closed
avocadowastaken opened this issue Aug 24, 2016 · 14 comments
Closed

[AutoComplete] Make Stateless and Composable #5062

avocadowastaken opened this issue Aug 24, 2016 · 14 comments
Labels
component: autocomplete This is the name of the generic UI component, not the React module! new feature New feature or request umbrella For grouping multiple issues to provide a holistic view

Comments

@avocadowastaken
Copy link
Contributor

avocadowastaken commented Aug 24, 2016

Current api has props:

  • searchKey - Text being input to auto complete.
  • onUpdateInput - Callback function that is fired when the user updates the TextField.
  • onNewRequest - Callback function that is fired when a list item is selected, or enter is pressed in the TextField.

What if we change it with more common api:

  • value - Current value
  • onChange - Callback function that is fired when value is changed
  • options - Available values

But it's not enough, what if we want to use complex objects in options?

  • formatOption - This function is called to format option

Looks more clear, but what if we want to format option differently in input?

  • formatInput - This function is called to format input of current value (formatOption will be used if this function is not provided)

Now, what to do when user starts typing input?

  • parseInput - This function is called to parse input text to value

So, let's combine it all together.

1st example: GeoAutocomplete

function GeoAutoComplete({
  value, // {address, lat, lng}
  options, // [{address, lat, lng}]
  onChange,
}) {
  return (
    <AutoComplete
        value={value}
        options={options}
        onChange={onChange}
        parseInput={(text) => ({address: text})}
        formatOption={(value) => value.address}
    />
  )
}

And if you want to validate just use like:

function isValid(value) {
     return Boolean(value.lat && value.lng)
}

2nd example: UserAutocomplete

function UserAutocomplete({
  value, // {id, email, firstName, lastName} or {$$searchText} custom container of search text
  options, // [{id, email, firstName, lastName}]
  onChange,
}) {
  return (
    <AutoComplete
        value={value}
        options={options}
        onChange={onChange}
        // create object with some `private` field 
        parseInput={(text) => ({$$searchText: text})}
        // Format user 
        formatOption={(value) => value.id ? `${value.firstName} ${value.lastName}` : value.$$searchText}
    />
  )
}

And if you want to validate just use like:

function isValid(value) {
     return value.id > 0
}

PS Currently I use wrapper for AutoComplete that makes it work exactly like that - so I wanted to share these examples to optimise current behaviour


PPS Related to #2957 and #2784

@oliviertassinari oliviertassinari changed the title [Proposal][AutoComplete]: Make Stateless [AutoComplete] Make Stateless Sep 18, 2016
@oliviertassinari oliviertassinari added the new feature New feature or request label Sep 18, 2016
@oliviertassinari
Copy link
Member

oliviertassinari commented Sep 18, 2016

@umidbekkarimov I'm all 👍 in that direction for the next branch: #4783.
Would be interesting to have a look at the API of react-select and other popular autocomplete component.

Related issues: #2294, #3178.

@avocadowastaken
Copy link
Contributor Author

@oliviertassinari glad to here it!

Related #2294 :

onFocus and onBlur triggers on TextField focus and blur
Which is wrong as I think, because if you will use it with libraries like redux-form it will mess things up, e.g:

  1. Click/Tab to autocomplete - will trigger onFocus (that will make field visited)
  2. Typing (if we will use current proposal) will trigger onChange and show suggestions
  3. Click/Tab on suggestion will trigger onBlur first (that will make field touched and show validation errors because value is invalid) and only after that will trigger onChange (that will hide validation errors because value become valid)

So to split AutoComplete and TextField actions there are two ways:

A. Make AutoComplete composable, e.g:

<AutoComplete 
  onBlur={...}
  onFocus={...}>
  <TextField 
    onBlur={...}
    onFocus={...}
  />
  <Popup
    onBlur={...}
    onFocus={...}
  />
</AutoComplete>

B. Add props for TextField

<AutoComplete 
  onBlur={...}
  onFocus={...}
  onInputBlur={...}
  onInputFocus={...}
  onPopupBlur={...}
  onPopupFocus={...}
/>

In both cases we will need to store isInputFocused and isPopupFocused values in AutoComplete to trigger onBlur or onFocus with onInputBlur/onPopupBlur or onInputFocus/onPopupFocus events,

So AutoComplete will have to have state inside

@oliviertassinari
Copy link
Member

oliviertassinari commented Sep 20, 2016

@umidbekkarimov Your points sounds correct. I would definitely go with option A. over B.
It would also be great to simplify the API (i.e more powerful but less usable). So we can later provide powerful abstraction, like integrating with react-virtualized.

I have done quite some refactorization in this <AutoComplete /> component in the past.
I have struggled with the focus handling. The <Menu /> focus behavior design on the master branch is far from perfect. Hopefully, that's much better on the next branch.

@avocadowastaken avocadowastaken changed the title [AutoComplete] Make Stateless [AutoComplete] Make Stateless and Composable Sep 21, 2016
@avocadowastaken
Copy link
Contributor Author

@oliviertassinari That sounds great!

I forgot that I had related issue from long ago #4270

@avocadowastaken
Copy link
Contributor Author

#2340 related issue, e.g:

<AutoComplete>
  <TextField  {...textFieldProps}/>
  <Popup {...popupProps}/>
  {isLoading && (<LinearProgress mode="indeterminate" />)}
</AutoComplete>

@danielevora
Copy link

PS Currently I use wrapper for AutoComplete that makes it work exactly like that - so I wanted to share these examples to optimise current behaviour

Hi @umidbekkarimov, is there a chance you could share your wrapper for those of us who want this sort of functionality before the next official release?

@avocadowastaken
Copy link
Contributor Author

@danielevora Actually it's not hard to implement, here the gist.

But I didn't test it. (Version in my project with lot of dependencies - like immutable, rxjs, recompose, so i couldn't just copy-paste from it)

@oliviertassinari
Copy link
Member

oliviertassinari commented Nov 13, 2016

@umidbekkarimov Sorry, to hijack this thread.
You mentioned you are using rxjs with recompose. I'm really curious about the approach you are using.
(At @doctolib we are using this stack all over to handle our state management)

@avocadowastaken
Copy link
Contributor Author

@oliviertassinari np at all 👍 here working example

I use rxjs here to control focus on element, mapping data and as replacement to sCU lifecycle

@avocadowastaken
Copy link
Contributor Author

Just and idea:

Create package (e.g. rx-material-ui, material-ui-rx) for material-ui@next with "Smart" component for every "Composable" component using recompose + rxjs (as I did in #5819 workaround)

@oliviertassinari oliviertassinari added this to the v1.0.0-prerelease milestone Jul 4, 2017
@oliviertassinari oliviertassinari modified the milestone: v1.0.0-prerelease Jul 14, 2017
@oliviertassinari
Copy link
Member

Closed by #4783

@oliviertassinari
Copy link
Member

react-autosuggest is stateless and composable.

@jurandircastro
Copy link

Is this solution already available?

@oliviertassinari
Copy link
Member

@jurandircastro Yes, on the v1-beta branch.

@oliviertassinari oliviertassinari added the component: autocomplete This is the name of the generic UI component, not the React module! label Apr 29, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
component: autocomplete This is the name of the generic UI component, not the React module! new feature New feature or request umbrella For grouping multiple issues to provide a holistic view
Projects
None yet
Development

No branches or pull requests

4 participants