Implementing react-bootstrap-typeahead with react-bootstrap-table
Published on 13 December 2017
Well, this was entertaining struggle of many hours.
Long story short, I needed to implement a controlled `AsyncTypeahead` field from `react-bootstrap-typeahead` as an editable and insertable field in `react-bootstrap-table` in a redux app. Oh, and the typeahead needed to allow new values to be entered.
You Just… or Do You?
According to the instructions provided by `react-bootstrap-table` “you just”:
- Use the `customEditor` prop to pass in your custom field component which implements `focus()` and `updateData()` (see: react-bootstrap-table: custom cell edit example).
- Use the `customInsertEditor` prop to pass in another custom field component which implements `getFieldValue()`. (see: React Bootstrap Table - Customization)
- Implement a wrapped component of `AsyncTypeahead` that implements the required interfaces above, so that you can also pass in the necessary params that `customEditor` and `customInsertEditor` needs.
Sadly, “you don’t just”.
Side Effects
There were a few side-effects which made this not work quite as expected.
- Typeahead suggestions vanish inside the table cell. Resolved with some CSS.
- Using `AsyncTypeahead` as a controlled field removes focus on change. Could be the result of `blurToSave` handling by the table, as typeahead selection would fire the `onBlur` event because you’re clicking out of the field, or something hinky from using the typeahead as a controlled field. Or both.
- Once an option is selected, when you refocus on the field and hit backspace, instead of removing one letter, it clears the selected value. Makes sense, but means you can’t use it like a regular controlled field. Which you probably shouldn’t in the table anyway seeing as it handles updates separately. Note: The demo doesn’t show this side effect because it’s not a controlled field.
- Once the typeahead is no longer in focus, the table doesn’t reset the editable mode so the field still looks in focus. When using `blurToSave` and custom fields, you have to fire the `onBlur` handler yourself in the custom component. Logically it would make sense to do this in the typeahead `onChange` but that handler doesn’t pass the event at all, and the table’s `onBlur` requires the event target. Woe.
- When inserting a new row, `Uncaught TypeError: dom.getFieldValue is not a function` is thrown and the row cannot be saved. Even if you have implemented the function in your component, the way the insert modal builds the fields for value retrieval doesn’t retrieve the correct component reference. When I put debugging in the lib, the ref attribute that was being passed from the table was `undefined`. Could this be the problem? Either way, the `dom` object was broken so of course `getFieldValue` was not a function.
Solution
Here’s a gist of the applied solution. Commented where relevant changes were made.