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

Input field of mutiselect creatable field is not cleared after new tag cration #1663

Closed
Falenos opened this issue Apr 12, 2017 · 12 comments
Closed

Comments

@Falenos
Copy link

Falenos commented Apr 12, 2017

For reasons unknown the input field of a mutiselect creatable field is not cleared after new tag creation.
I click on create newTag, newTag is displayed on the field and next to it the input stays as is

Is there a method I can call when a new tag is stored to clear the input?

I know its supposed to work by default, but in my case it is not happening.

@arackaf
Copy link

arackaf commented Apr 14, 2017

@Falenos Same here. Here's a gnarly workaround for you - this is MobX code, so yours may be a bit different.

Grab a ref to the creatable component like so

<Creatable 
    disabled={saving || frozen} 
    placeholder="Tag this section" 
    ref={el => this.creatableEl = el}   // <-------- here
    onNewOptionClick={obj => store.addNewTag(obj, this.creatableEl)} 
    onChange={store.setTags} 
    value={store.rawTags} 
    multi={true} 
    options={sectionTagStore.allTags} />

and then

@action addNewTag = (obj, creatableEl) => {
    this.tags.push(sectionTagStore.createTag(obj));
    creatableEl.select.setState({inputValue: ''});  // <------- clears the input text
}

So the ref to the Creatable component has a select property on it which (I assume) is the underlying multi component. Set its state's inputValue to empty string to clear the input text. And done.

@Falenos
Copy link
Author

Falenos commented Apr 22, 2017

@arackaf thanks a lot for the tip. It got me really close but still not there, it really is a bit gnarly though. I am relatively new in react and from your suggestion I checked out refs for the first time...

What happened is that my component that renders the "Select" is stateless and is not declared as a Class maybe that's why it's not working, but I need to research further. The creatableEl.select.setState(); gives me nothing. There is a State object in Select so creatableEl.select.State exists but the .setState() method is not available. The code is below, if you have any suggestions...

import React, { PropTypes } from "react";
import Select from "react-select";

function TagSelect(props) {
  const handleNewCategoryTagSave = (tag)=> {
    // Blank tags cannot be saved
    if ((!tag || !tag.value) ||
      (typeof tag.value === "string" && tag.value.trim().length === 0)) {
      return false;
    }

    props.onNewCategoryTagSave(props.productId, tag.value, props.name);
  };
  const selectValue = ()=> {
    const value = props.value;
    const multiSelect = props.multi;
    if (!multiSelect && Array.isArray(value)) {
      return props.value[0];
    }

    return value;
  }

  return (
    <Select.Creatable
      multi={props.multi}
      name={props.name}
      options={props.options}
      placeholder={props.placeholder}
      value={selectValue()}
      onChange={(value) => props.onChange(value, props.name)}
      onNewOptionClick={handleNewCategoryTagSave}
    />
  );
}

TagSelect.propTypes = {
  multi: PropTypes.bool,
  name: PropTypes.string,
  onChange: PropTypes.func,
  onNewOptionClick: PropTypes.func,
  options: PropTypes.arrayOf(PropTypes.object),
  placeholder: PropTypes.string,
  value: PropTypes.any
};

export default TagSelect;

@arackaf
Copy link

arackaf commented Apr 22, 2017

@Falenos not sure. You should be able to add the ref to the Creatable in your SFC, and then whatever event handler that needs to use it would be called from within the closure, with access to the ref.

At this point though I'd just make your component a class; I don't see any real value to making an SFC bloated like that. imo SFCs fit better with simpler components that aren't doing very much.

@Falenos
Copy link
Author

Falenos commented Apr 22, 2017

@arackaf will do and get back on you, thanks

@ghost
Copy link

ghost commented Jun 3, 2017

Just ran into this issue, the suggestion worked perfectly. Thanks for that, @arackaf. Would be neat if the input was cleared automatically by default, but not sure what other kinds of issues that might create.

@smelted-code
Copy link

@arackaf I ran into this, too. I'm relatively new to the library; is this low-hanging fruit for contributors, or are there a bunch of edgy cases that would trip me up if I tried? I'm also using react-select in a stateless component, so adding this.some_ref breaks my paradigm a bit.

@arackaf
Copy link

arackaf commented Jun 9, 2017

@smelted-code there are currently 133 open pull requests. I'd advise you NOT to PR this unless the owner of this project tells you he'll accept it. I mean, if you want to try to fix it just to see if you can, and won't mind if the PR is ignored, then go for it. But don't go trying to fix it unless you're ok with the PR lingering for a bit.

No offense intended to the project's owner. We all have limited time during the week - I just don't want a new contributor to get frustrated :)

@Falenos
Copy link
Author

Falenos commented Jun 9, 2017

@arackaf I made progress on the issue with a different approach.

Because we needed some functionality that wasn't there either way, like being able to delete the Options form the dropdown Menu we forked it and we will release our enhanced version probably by the end of the month from @artlimes, in case you are interested.

Eitherway from my current knowledge of how thing work this is what I saw.

There is a method in Select.js called selectValue(). It is called whenever an Option is selected and clears the Select state property inputValue. This method is NOT called when you add a new Option.

If you decide to make your own fork or edit the core somehow like we did, my first approach was to create a new method in Select.js e.g clearInput that simply this.setState({inputValue: ''}). Then you can call it from Creatable.js at

createNewOption () {
  			if (isOptionUnique) {
  				if (onNewOptionClick) {
  					onNewOptionClick(option);
 					// Our addition. Clears the input values on click.
 					this.select.clearInput(option);
  				} else {
  					...
 				}
 			}
 		}
 	},

There are also 2 boolean props that might become handy if you pass them to Select from you app.
These are onBlurResetsInput and onCloseResetsInput. The onCloseResetsInput refers to the situations when the dropdown Menu is closing.

So, my current approach is calling the existing Select closeMenu() method from Creatable.js instead of our custom clearInput and combine it with a onCloseResetsInput={true}. This is fine for our usecase but as you can imagine, it closes the Menu when a new option is created.

My general advice would be to check the methods that setState({inputValue: ''}) and figure out which one you want to use. Hope this helped, cheers

@arackaf
Copy link

arackaf commented Jun 11, 2017

@Falenos - thanks a ton for the info. This project is great - look forward to seeing what's ahead for it.

@faniva
Copy link

faniva commented Jul 18, 2017

The following worked for me :

<Select.Creatable
   name="sticker_categories"
   value={this.state.categories}
   options={this.state.categoriesSuggestions}
   multi={true}
   simpleValue={false}
    joinValues={true}
   // loadOptions={this.getTags}
   onChange={this.onCategoriesSelectChange.bind(this)}
   promptTextCreator={ label => `Create category "${label}"`}
   onNewOptionClick={this.onCreateNewCategory.bind(this)}
   newOptionCreator={ o => { return {label: o.label, value: o.label.toLowerCase()  } } }
    ref={ s => this.selector = s}
 />

Notice the ref attribute is a function that stores the component into this.selector variable
Then I have something like this for the onNewOptionClick handler:

onCreateNewCategory(newCatg){
        console.log(this.selector);
        console.log(newCatg);

        const catgs = [].concat(this.state.categories, newCatg);

        this.setState({ categories : catgs})

        this.selector.select.selectValue(); // this.selector points to the component itself and makes its methods available
    }

@hsimah
Copy link

hsimah commented Jul 25, 2017

@josefano thanks for that, it almost entirely worked for me. I found that in my onChange function the value included an undefined element. Easy to filter that out and work around this annoying issue!

@Falenos
Copy link
Author

Falenos commented Jun 6, 2019

I am closing this :) i think the discussion is obsolete at this point

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants