Choices-js / Choices

A vanilla JS customisable select box/text input plugin ⚡️
https://choices-js.github.io/Choices/
MIT License
6.19k stars 610 forks source link

Remove placeholder when active selected items #1029

Open Timwillems opened 2 years ago

Timwillems commented 2 years ago

Whenever there is an item selected in the "multiple" dropdown, i'd like to have the placeholder option removed from the list.

This is to have a indicator like "Please select your ...."

Now it always shows this placeholder, even if there are selected items

ggsp commented 2 years ago

You can achieve this with CSS, e.g.:

.choices__list--multiple:not(:empty) + .choices__input::placeholder {
  opacity: 0;
}

Should you want to achieve something similar with a single select, you could do it like so:

.choices__list--dropdown > .choices__list > .choices__placeholder {
  display: none;
}
dphaas2004 commented 1 year ago

@ggsp Thanks for the css magic. it does indeed hide the placeholder. This only kind of worked for me as the placeholder is still taking up space. For me both the base implementation and this workaround do not function like a normal element placeholder would which is what I am going for. I'm sure there's a way to do it in css but for those who want to handle via JS this is how I ended up handling it:

const element = document.querySelector('#test');
const choices = new Choices(element,{
  allowHTML: true,
  placeholder: true,
  placeholderValue: "This is my Placeholder"
  });
const Inner = document.querySelector("div.choices__inner"); //Get the inner Container
const search = document.querySelector("div.choices__inner input[name='search_terms']"); //Get the search element (this is where the placeholder is)
const Width = Inner.offsetWidth;
element.addEventListener('change', (evnet)=> {
  //Add or remove the placeholder
  element.selectedOptions.length ? search.removeAttribute('placeholder') : search.setAttribute('placeholder',choices.config.placeholderValue);  
  //optionally keep the initial width of the container
  Inner.style.minWidth = `${Width}px`;
  search.removeAttribute('style');
});
<select id='test'  multiple>
    <option></option>
    <option>option 1</option>
    <option>option 2</option>
    <option>option 3</option>
</select>
nitinatvaluelabs commented 1 year ago

You can achieve this with CSS, e.g.:

.choices__list--multiple:not(:empty) + .choices__input::placeholder {
  opacity: 0;
}

Should you want to achieve something similar with a single select, you could do it like so:

.choices__list--dropdown > .choices__list > .choices__placeholder {
  display: none;
}

Thanks @ggsp You saved a tone of time ❤️

ThijsAnouchka commented 4 months ago

dphaas2004's solution did not work for me but it did put me on the path towards finding it (for my project) so I thought I'd include it on this post

HTML Filter:

<div class="c-filter">
                    <label for="datum">Datum</label>
                    <select class="js-filter-date js-searchfield" id="datum" multiple>
                    </select>
                </div>

JS code:

const listenToSearchFields = function () {
    const searchFields = document.querySelectorAll('.js-searchfield');
    for (const field of searchFields) {
      field.addEventListener('change', function () {
        handleSearchFields(); // search request for my api
        const inner = field.closest('.choices__inner'); // get the container of the current filter selected
        const search = inner.querySelector('input[name="search_terms"]'); // in that container, get the placeholder
        const arrSelections = inner.querySelectorAll('.choices__item'); // array of selected filters
        if (arrSelections.length > 0) {
// if there are filters detected, hide placeholder
          search.style = 'display:none;';
        } else {
// else show the placeholder again
          search.style = 'display:inline-block;';
        }
      });
    }
};

Hopefully this is helpful to anyone else!

pandarek commented 1 month ago

My solution:

let formSelects = document.querySelectorAll('select.form-select-choices')
choices = []
formSelects.forEach((item) => {
    let choicesItem = new Choices(item, {
        allowHTML: true,
        removeItems: true,
        removeItemButton: true,
        placeholder: true,
        placeholderValue: item.dataset.formPlaceholder
    });
    choicesItem.passedElement.element.addEventListener('addItem', () => {
            choicesRemovePlaceholder(choicesItem)
        }, false,
    );
    choicesItem.passedElement.element.addEventListener('removeItem', () => {
            choicesRemovePlaceholder(choicesItem)
        }, false,
    );

    choices.push(choicesItem)
})

function choicesRemovePlaceholder(choicesItem) {
    let selected = choicesItem.passedElement.element.selectedOptions.length
    let placeholder = choicesItem.containerInner.element.querySelector('input[type=search]')
    if (selected > 0) {
        placeholder.style.display = 'none'
    } else {
        placeholder.style.display = 'inline-block'
    }
}
jairmedeiros commented 6 days ago

Using scss:

.#{$choices-selector}__list--multiple {
  &:not(:empty) + .#{$choices-selector}__input {
    min-width: auto !important;

    &::placeholder {
      opacity: 0;
    }
  }
}