Choices icon indicating copy to clipboard operation
Choices copied to clipboard

Allow user-created choices for selects

Open kittee opened this issue 5 years ago • 29 comments

Description

  • Added a new configuration option called addChoices which affects selects. It is false by default to maintain old behavior.
  • When addChoices is set to true, the user can type an option into the field and press enter, and it will be added as a new option and selected.

Motivation and Context

This addresses #39 which is allowing users to add choices to selects.

How Has This Been Tested?

It works on the project I'm working on. The existing tests and new tests that I added pass.

Screenshots (if appropriate):

add-choices-demo

Types of changes

  • [ ] Bug fix (non-breaking change which fixes an issue)
  • [x] New feature (non-breaking change which adds functionality)
  • [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)

Checklist:

  • [x] My code follows the code style of this project.
  • [x] My change requires a change to the documentation.
  • [x] I have updated the documentation accordingly.

kittee avatar Feb 21 '19 00:02 kittee

I have rebased with master to fix merge conflicts since I opened this PR, added tests, added a gif demo, and updated the readme. Please let me know if there's anything else I can address so this can be considered for merging. ✧・゚:*╰(◕‿◕。╰)

kittee avatar Mar 15 '19 21:03 kittee

Is there any chance that this feature could be added?

AdamWills avatar Apr 18 '19 19:04 AdamWills

Sorry, I've been really busy recently. Will get this reviewed and merged ASAP

jshjohnson avatar Jun 03 '19 08:06 jshjohnson

Hi, just wondering if/when this will be reviewed and merged? Very keen on using this feature :)

jayraydon avatar Jun 18 '19 14:06 jayraydon

@caramiki @jshjohnson guys any news about this amazing feature? thanks

mlshvdv avatar Jul 08 '19 16:07 mlshvdv

Is there anything we can do to help with getting this feature added?

AdamWills avatar Jul 15 '19 20:07 AdamWills

Please add this. I had to develop it on my own.

userchoice

Ended up with a makeshift workaround code.

const choicesIssue39Fix = (choicesElement) => {
    choicesElement.input.element.addEventListener('keydown', (keypressEvent) => {
        if (keypressEvent.keyCode === 13 && keypressEvent.target.value) {
            let keywordHits = 0;
            [...choicesElement.choiceList.element.children].forEach((element) => {
                if (element.innerText.includes(keypressEvent.target.value)) {
                    keywordHits += 1;
                }
            });
            if (!keywordHits) {
                keypressEvent.stopPropagation();
                choicesElement.setChoices([
                    {
                        value: keypressEvent.target.value,
                        label: keypressEvent.target.value,
                        selected: true,
                    },
                ], 'value', 'label', false);
                const linterEvent = keypressEvent;
                linterEvent.target.value = '';
            }
        }
    });
};

Edit: I've just now realized I forgot to change the "No results found" caption to "Press enter to add" like the OP

GoldenMaximo avatar Jul 26 '19 14:07 GoldenMaximo

As far as I can tell pressing enter always adds the content of the search field as new item, even when I try to select another element in the list via cursor keys.

That's kind of counterintuitive to me.

press-enter

BlaM avatar Aug 30 '19 14:08 BlaM

As far as I can tell pressing enter always adds the content of the search field as new item, even when I try to select another element in the list via cursor keys.

That's kind of counterintuitive to me.

press-enter

I don't know if this issue has been fixed already or if you were using the code I've made but my fix is pretty modifiable and it's working fine in production, I'm pretty sure you can come up with a reasonable solution based on it.

GoldenMaximo avatar Aug 30 '19 14:08 GoldenMaximo

I don't know if this issue has been fixed already or if you were using the code I've made but my fix is pretty modifiable and it's working fine in production, I'm pretty sure you can come up with a reasonable solution based on it.

I tried to use the pull request implementation, not yours. That'll be the next step for me ;)

... Few moments later:

@GoldenMaximo: Your implementation feels more like what I would expect.

BlaM avatar Aug 30 '19 15:08 BlaM

As far as I can tell pressing enter always adds the content of the search field as new item, even when I try to select another element in the list via cursor keys.

That's kind of counterintuitive to me.

I agree this is counterintuitive - a solution to add choices dynamically needs to be able to differentiate between selecting an existing choice and adding a non-existent choice

jshjohnson avatar Nov 18 '19 13:11 jshjohnson

Hi! Is there any update about this feature? Thanks

vitobotta avatar Feb 17 '20 18:02 vitobotta

Hi @GoldenMaximo , I am trying your workaround but I get Cannot read property 'element' of undefined. I have tried with both the Choices object and the select element on which I initialise Choices. Can you clarify how to use the workaround? Thanks!

vitobotta avatar Feb 17 '20 18:02 vitobotta

You may have to use an older Version of this library to use the exact code example. I can confirm, that it worked for me, but back then choices.js was at version 7.x.x 6 months ago, now it is at 9.x.x.

BlaM avatar Feb 17 '20 23:02 BlaM

Thanks @BlaM . I ended up using Tagify for tags.

vitobotta avatar Feb 18 '20 12:02 vitobotta

why is a new option introduced? Why not just checking if the type is a multiple-select and addItems is set?

Edit: I misunderstood the addItems flag

devkral avatar Apr 15 '20 10:04 devkral

I reworked this PR and made an other PR: https://github.com/jshjohnson/Choices/pull/856

There are many edge cases which need to be handled (like disabled options).

devkral avatar Apr 16 '20 12:04 devkral

I'm confused, isn't this in the demo? Look at the first example here https://joshuajohnson.co.uk/Choices/

Is or isn't this actually supported?

maxp-hover avatar Jun 28 '20 17:06 maxp-hover

Ok sorry, I understand now. Adding new elements only works for input types, not select. That wasn't very well documented.

maxp-hover avatar Jun 28 '20 17:06 maxp-hover

Excuse me, when is this feature implemented ? I want to use this feature in my project. Can you implement this feature soon, please ? Thanks.

joe-nghiem-goldenowl avatar Jun 03 '21 04:06 joe-nghiem-goldenowl

Please, I'm waiting for this feature too. I would like to keep using this awesome select box, but I need to add the user input when it's a select.

helenatxu avatar Jul 14 '21 18:07 helenatxu

I think we need this feature for single select too, not just on tags select

rizkhal avatar Dec 27 '21 18:12 rizkhal

Like @rizkhal, I really need this feature in single select. Any news on when and if this will be merged? How can i help in speeding up this MR?

kabirpathak avatar Dec 06 '22 12:12 kabirpathak

Sadly, this PR would need to be completely redone. This library has been completely revamped into TS. Merging this PR isn't possible without redoing most of it.

joeworkman avatar Apr 28 '23 19:04 joeworkman

I re-implemented this PR under the new code base. #1117

joeworkman avatar May 24 '23 15:05 joeworkman

@GoldenMaximo I like the workaround you've come out with. Will it be possible that you can share the full example as I'm newbie to javascript and not sure where should I include the "const choicesIssue39Fix" you've developed. Much Appreciated!

SieSiongWong avatar Jul 20 '23 13:07 SieSiongWong

Waiting for this feature, are there any updates ?

vstruk01 avatar Aug 28 '23 12:08 vstruk01

I re-implemented this PR under the new code base. #1117

Thank you for your perfect implementation, and I hope the author can merge as soon as possible.

Purek avatar Dec 08 '23 06:12 Purek

Made my own implementation (read: hack)

  function choicesjs_allow_create(obj) {
  
      var addNew = document.createElement("div");
      var choiceList = obj.choiceList.element;
      addNew.addEventListener('click', function (e) {
          addItem();
      })
  
      obj.input.element.addEventListener('keyup', function (e) {
  
          if (addNewAllowed()) {
              obj.removeHighlightedItems();
              obj._currentState.choices.map(elm => elm.active = false)
              addNew.innerHTML = "Press ENTER to add: <b>" + obj._currentValue + "</b>";
              addNew.className = "choices__item choices__item--choice";
              addNew.style.display = "block";
              addNew.dataset.choiceSelectable = '';
              choiceList.append(addNew)
  
              var code = (e.keyCode ? e.keyCode : e.which);
              if (code == 13) {
                  e.preventDefault()
                  e.stopPropagation()
                  return false;
              }
  
          } else {
              addNew.style.display = "none";
          }
          if (!choiceList.querySelectorAll(".is-highlighted").length) {
              console.log("ASDF")
  
              addNew.classList.add("is-highlighted", "choices__item--selectable");
          }
      })
  
      obj.input.element.addEventListener('keydown', function (e) {
  
          var code = (e.keyCode ? e.keyCode : e.which);
  
          if (code == 13 && addNewAllowed()) {
              addItem();
              e.preventDefault()
              e.stopPropagation()
              return false;
          }
      })
  
      function addNewAllowed() {
          let choices_found = obj._currentState.choices.filter(elm => elm.label == obj._currentValue).length
          let items_found = obj._currentState.items.filter(elm => elm.label == obj._currentValue).length
          return (choices_found + items_found) == 0 && obj._currentValue != '';
      }
  
      function addItem() {
  
          obj.removeHighlightedItems();
          obj._currentState.choices.map(elm => elm.active = false)
          obj.input.element.value = ''
  
          obj._addChoice({
              value: obj._currentValue,
              label: obj._currentValue,
              isSelected: true,
              isDisabled: false
          });
  
          obj.input.element.dispatchEvent(new Event('keyup'));
  
      }
  }
  choicesjs_allow_create(choisesObjVariable) 

open-admin-org avatar Feb 24 '24 22:02 open-admin-org