React-select: Select.Async isn't using the options passed

Created on 13 Sep 2016  路  7Comments  路  Source: JedWatson/react-select

I can't have an actual example because the API I'm using isn't public, but I've simplified the code as much as I could.
Basically, the options I pass to the getOptions callback isn't always showing properly in the select. My api returns a maximum of 5 items, e.g:

  • Pitt st would render 5 items in the select
  • Pitt st ma would render 1 items in the select even though the console.log before the callback has 5 items.
    To properly show those items, I have to close the dropdown and open it again.
    I tried with cache={false} & complete: false/true (yeah, both) and every possible combination but it didn't change anything.

Am I doing anything wrong or it's expected since it's in rc ?

Cheers

import React, { Component, PropTypes } from 'react'
import Select from 'react-select'

let timeout
const getOptions = (text, cb) => {
  if (text.length <= 3) return cb()

  if (timeout) clearTimeout(timeout)
  timeout = setTimeout(() => {
    fetch(`api/${text}.json`)
      .then((res) => res.json())
      .then((data) => {
        const options = data.map((d) => ({
          value: d,
          label: d.label,
        }))

        console.log(options)
        cb(null, { options })
      })
  }, 500)
}

export default ({ value, onChange }) => (
  <Select.Async
    value={value}
    loadOptions={this.getOptions}
    onChange={onChange()}
  />
)

Most helpful comment

Ah. If you just want to _disable_ filtering and let the Api handle it- then just provide your own filterOptions function that returns the full options array every time. 馃槃

function filterOptions(options) {
  return options;
}

All 7 comments

The above code looks strange to me. Perhaps I'm misreading it. What is the cb function? (Where is it coming from?) Shouldn't your chained promise return the mapped options array? Why not something more like this...

import React, { Component, PropTypes } from 'react'
import Select from 'react-select'

let cachedOptions = []
let timeout

const getOptions = (text) => {
  if (text.length <= 3) return cachedOptions

  return fetch(`api/${text}.json`)
    .then((res) => res.json())
    .then((data) => {
      cachedOptions = data.map((d) => ({
        value: d,
        label: d.label,
      }))

      return cachedOptions
    })
}

export default ({ value, onChange }) => (
  <Select.Async
    value={value}
    loadOptions={this.getOptions}
    onChange={onChange()}
  />
)

Sorry. I'm still not very familiar with Async. Looking at it again, I believe cb is meant to be the 2nd, callback parameter but your example code omits it. In that case, your example works if you change it to be like so:

let timeoutId;

const options = [
  { label: 'one', value: 1 },
  { label: 'two', value: 2 },
  { label: 'three', value: 3 }
];

// Callback based example
function getOptionsCallback (text, callback) {
  clearTimeout(timeoutId);

  if (text.length < 2) {
    return callback(null, { options: [] });
  }

  timeoutId = setTimeout(() => {
    callback(null, { options });
  }, 500);
}

// Promise based example
function getOptionsPromise (text) {
  clearTimeout(timeoutId);

  if (text.length < 2) {
    return Promise.resolve({ options: [] });
  }

  return new Promise((resolve) => {
    timeoutId = setTimeout(() => {
      resolve({
        options
      });
    }, 500);
  });
}

Closing this issue for now as I believe the error is in your application code (based on the example provided).

I forgot to add cb when I simplified the example, but I do have it in my actual code.

Here's screenshots of the weird behavior I'm experiencing:

  • Type pitt st
  • The console logs 5 items, the dropdown show 5 items
    image
  • Without leaving the input, add mall to the search
  • The console logs 5 items, the dropdown shows nothing
    image
  • Click out of the input and back in
  • The dropdown shows the 5 items it previously didn't show
    image

It seems like you're mixing up _loaded_ options and _filtered_ options.

react-select's default filter function does not support multi-word filtering like you're using above (eg "_pitt st mall_"). The only reason "_pitt st_" matches options is because it's an exact substring of the option text (eg "_pitt street mall_"). However "_pitt st mall_" is not an exact substring and so it will fail.

If you want that kind of prefix matching, check out the bvaughn/react-select-fast-filter-options.

That's what I thought, is there a way to remove the _filtered_ options ? Since the API is already taking care of it.

Ah. If you just want to _disable_ filtering and let the Api handle it- then just provide your own filterOptions function that returns the full options array every time. 馃槃

function filterOptions(options) {
  return options;
}

Perfect, that's exactly what I needed, thank you :+1:

Was this page helpful?
0 / 5 - 0 ratings