React-select: Create new option on blur with Creatable

Created on 29 May 2017  路  17Comments  路  Source: JedWatson/react-select

First of of all, thanks for the great work on react-select.

So, I needed to create a new option on blur with the Creatable component, even if the the user didn't executed one of the defaults triggers for the creation (e.g: click on"Create option 'foo'", hit TAB or ENTER).

I was able to achieve this using refs and invoking createNewOption in my parent component, something like this:

...
handleBlur(){
    let { inputValue } = this.selector;
    this.selector.createNewOption(inputValue)
}

render(){
   <Creatable props={...this.props} onBlur={this.handleBlur} onBlurResetsInput={false} 
   ref={s => this.selector = s}/>
}

I'd like to know if there is any intention of adding a more intuitive support for this, like a createNewOptionOnBlur prop for the Creatable. I will be glad to open a PR if that's the case.

issuenhancement issureviewed

Most helpful comment

Plus one for this... would also use it

All 17 comments

Hi @frfroes, this behavior could be confusing for some. For example what if the user blurred from the input, but did not want to create an option? With your proposal they would have to delete the entry before they could blur or they would have to remove the entry after it being selected.

Well, @agirton the default behavior would still be to blur from the input without creating an option. The implementer would have to explicitly pass the createNewOptionOnBlur={true} prop to the Creatable element in question, therefore taking the responsibility of creating a new option on every blur.

In this case he would only do so if his businesses logic required such behavior, as mine required.

I would also love to see this implemented, I currently use autocomplete just as nice addition, not main feature. user should be able to enter anything he likes, blur the field and just forget about it

Same usecase here, the autocomplete is used as an addition. Love to see this implemented. Thoughts on how to proceed would be welcome, i could then contribute on this.

Plus one for this... would also use it

A strange minor bug in @frfroes 's solution: if you enter an _exact_ value found in the dropdown, it won't add it. (possibly due to the isOptionUnique check?)

@frfroes On your code above, what is this.selector? I'd like to implement this in my code too. Thanks!

This doesn't seem to work on v2 or is it just me? @jamcreencia Did you use v1 or v2?

Hi @martimarkov , I'm using v1.

Hi guys, sorry for the absence. I have been very busy with work and college these last months and I have not given the proper attention to the issue which I opened myself. Anyway, I would like to be more engaged with the community from now on and I guess this is a good place to start.

@agirton This issue have gotten some popularity over time, so I guess it's worth opening to PR. I do not have experience contributing to open source, so I have some doubts on how to get started. Should I just clone the repo, do the changes, test everything and open the PR? At least that was what I understood from reading the CONTRIBUTING.md, please correct me if I'm missing something.

@jamcreencia Really sorry for letting you hang. You probably figured it out or got it working somehow by now. Just in case, the answer to your question is:
In React, when you're doing something like ref = {s => this.selector = s} it's called [callback refs] (https://reactjs.org/docs/refs-and-the-dom.html # callback-refs). Basically you're passing the component instance which you are using the callback ref to attribute in the parent component. So this.selector is the reference for the instance of Creatable, that way I can invokecreateNewOption ()imperatively from the instance's API.

Just a note on this, in V2 the onBlur event arg is a synthetic event that has a handle to the input, so you should be able to do this easily on your own with a thin wrapper over your onCreateOption handler: (I haven't fully verified this): The handleBlur functions in your component needs to be:

handleCreate = (value) => {
   //Do what you need here to create an new object and set your state
}

handleBlur(event){
    this.handleCreate(event.target.value)
}

<Creatable onBlur={this.handleBlur} onBlurResetsInput={false} onCreateOption={this.handleCreate} />

Assuming this works, I wouldn't see the need to add anything more to the new API.

Are there plans to have an option for that?

Hi all,

Thank you everyone who had a part in addressing this question.

I'm now closing this issue as it appears to have been resolved via community comments.

However, if you feel this issue is still relevant and you'd like us to review it, or have any suggestions regarding this going forward - please leave a comment and we'll do our best to get back to you!

@bladey - The option suggested by @andoq doesn't handle use cases of multi-select.

There are a bunch of edge cases around it (when the value already exists, the fact null is returned instead of an empty array, etc).

It would be great if onBlur was passed was also passed the current values (or better yet the same params as onChange). This would make it much easier to implement in user land.

FYI for anyone using multiselect and create on blur. This is our solution, although there are still some edge cases that may be missed

  const onBlur = (event) => {
    const name = event.target.value
    if (name) {
      const newValue = {label: name, value: name}
      if (Array.isArray(props.value) ) {
        // Dont allow duplciate values
        if (props.value.find(v => v.value === name)) { return props.onChange(props.value) }
        props.onChange([ ...props.value, newValue ])
      } else if (props.isMulti) {
        props.onChange([ newValue ])
      } else {
        props.onChange(newValue)
      }
    }
  }

Thanks for your feedback @ro-savage, I appreciate it.

It would be great if onBlur was passed was also passed the current values (or better yet the same params as onChange). This would make it much easier to implement in user land.

Greetings @ro-savage ,

When using onInputChange, there is an action meta event named input-blur which would enable you to do exactly as you are suggesting.

  const onInputChange = (textInput, { action }) => {
    if (action === "input-blur" && !!textInput) {
      handleChange(textInput);
    }
  };

  const handleChange = (label) => {
    if (options.find((opt) => opt.value === label)) {
      return;
    }

    const option = { label, value: label };
    setOptions([...options, option]);
    isMulti ? setValue([...(value || []), option]) : setValue(option);
  };

Here is the example as a codesandbox: Create Option onBlur

Here is a similar example: Create Option on comma input

Given that the issue is over 3 yrs old and that we have an adequate api to solve this use case as of v2, I will close this issue. If anyone has any other questions or concerns please feel free to share and we can always reopen this and/or work through anything that is unresolved for you.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

pashap picture pashap  路  3Comments

ericj17 picture ericj17  路  3Comments

coder-guy22296 picture coder-guy22296  路  3Comments

AchinthaReemal picture AchinthaReemal  路  3Comments

steida picture steida  路  3Comments