8

I am using Choices.js to create a multi select option menu.

In the <select> menu it is required to be able to select the same <option> multiple times. This issue has been resolved by using the addEventListener function from Choices.js.

The Issue

When i want to load the selected options from a string or ajax call the <option> are only selected one time instead of multiple times.

For example: the values 1 - 1 - 2 - 3 - 3 will need to display in the <select> menu ONE - ONE - TWO - THREE - THREE.

But currently it only shows ONE - TWO - THREE.

The issue is that the addEventListener is not working when the setChoiceByValue is being used.

document.addEventListener("DOMContentLoaded", function() {
  const query_task = new Choices(document.querySelector('#query_task'), {
    removeItemButton: true,
    maxItemCount: 10,
  });
  query_task.passedElement.element.addEventListener('addItem', function(e) {
    query_task.setChoices([{
      value: e.detail.value,
      label: e.detail.label
    }, ], 'value', 'label', false, );
  }, false, );

  $(document).on('click', '.ajax_data', function() {
    let data = '1,1,2,3,3';
    query_task.removeActiveItems();
    query_task.setChoiceByValue(data.split(','));
    console.log('Ajax data loaded');
  });
});
<link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.1.3/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://choices-js.github.io/Choices/assets/styles/choices.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.1.3/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/choices.js/9.1.0/choices.min.js"></script>

<div class="row pt-2 px-5">
    <div class="col-12 px-5">
        <label for="query_task" class="form-label">SELECT TASKS</label>
        <select id="query_task" class="form-control choices-multiple" multiple>
            <option value="0">ZERO</option>
            <option value="1">ONE</option>
            <option value="2">TWO</option>
            <option value="3">THREE</option>
            <option value="4">FOUR</option>
        </select>
    <div>
    <div>
        <button type="button" class="ajax_data btn btn-primary">Load AJAX data</button>
    </div>
</div>

Solved - Solution:

let query_data = [
  { value: "0", label: "ZERO" },
  { value: "1", label: "ONE" },
  { value: "2", label: "TWO" },
  { value: "3", label: "THREE" },
  { value: "4", label: "FOUR" }
];

document.addEventListener("DOMContentLoaded", function() {
  const query_task = new Choices(document.querySelector('#query_task'), {
    removeItemButton: true,
    maxItemCount: 10,
    choices: query_data
  });
  query_task.passedElement.element.addEventListener('addItem', () => reset(), false);
  query_task.passedElement.element.addEventListener('removeItem', () => reset(), false);

  function reset() {
    query_task.clearChoices();
    query_task.setChoices(query_data, "value", "label", false);
  }

  $(document).on('click', '.ajax_data', function() {
    query_task.removeActiveItems();
    let data = '1,1,2,3,3';
    let selected_values = data.split(',')
    $.each(selected_values, function(key, value) {
      query_task.setChoiceByValue(value);
      reset();
    });
  });
});
<link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.1.3/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://choices-js.github.io/Choices/assets/styles/choices.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.1.3/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/choices.js/9.1.0/choices.min.js"></script>

<div class="row pt-2 px-5">
  <div class="col-12 px-5">
    <label for="query_task" class="form-label">SELECT TASKS</label>
    <select id="query_task" class="form-control choices-multiple" multiple>
    </select>
    <div>
      <div>
        <button type="button" class="ajax_data btn btn-primary">Load AJAX data</button>
      </div>
    </div>
Crezzur
  • 1,303
  • 2
  • 18
  • 37

2 Answers2

4

The documentation is bit confusing . There are two issues to fix:

  • To add duplicates you need to use setValue(items) method. Next point explains how to get rid of duplicates.
  • After you unselect an item it gets added back to the options list. This creates duplicate items. I couldn't find method to remove a single choice from options list. So as a workaround I am resetting entire options list.

Demo:

let labels = ['ZERO', 'ONE', 'TWO', 'THREE', 'FOUR'];
let query_task = null;

document.addEventListener("DOMContentLoaded", function() {
  query_task = new Choices(document.querySelector('#query_task'), {
    removeItemButton: true,
    maxItemCount: 10,
    duplicateItemsAllowed: true,
    choices: defaults()
  });

  query_task.passedElement.element.addEventListener('addItem', function(e) {
    query_task.setChoices([{
      value: e.detail.value,
      label: e.detail.label
    }, ], 'value', 'label', false);
  }, false);

  query_task.passedElement.element.addEventListener('removeItem', () => reset(), false);

  $(document).on('click', '.ajax_data', function() {
    let data = '1,1,2,3,3';
    query_task.removeActiveItems();
    query_task.setValue(data.split(',').map((v) => ({value: v, label: labels[+v]})));

    reset();
    console.log('Ajax data loaded');
  });
});

function defaults() {
  return labels.map((lbl, i) => ({value: i, label: lbl}));
}

function reset() {
  query_task.clearChoices();
  query_task.setChoices(defaults(), 'value', 'label', false);
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.1.3/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://choices-js.github.io/Choices/assets/styles/choices.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.1.3/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/choices.js/9.1.0/choices.min.js"></script>

<div class="row pt-2 px-5">
  <div class="col-12 px-5">
    <label for="query_task" class="form-label">SELECT TASKS</label>
    <select id="query_task" class="form-control choices-multiple" multiple></select>
    <div>
      <div>
        <button type="button" class="ajax_data btn btn-primary">Load AJAX data</button>
      </div>
    </div>
  </div>
</div>
the Hutt
  • 16,980
  • 2
  • 14
  • 44
  • Using your code we can also call the `reset()` function on `additem` : `query_task.passedElement.element.addEventListener('addItem', () => reset(), false);`. furthermore the value of `duplicateItemsAllowed` is by default set to `true` so there is no point for a declare. Your code pointed me to the possibility to use `query_task.setChoiceByValue(value); ` in a `$.each` loop to select a value followed by `reset()`. Your answer was not 100% what i searched but it pointed me in the correct direction therefor i will accept it as an answer. – Crezzur Feb 01 '22 at 14:52
1

Hi @Crezzur,

Thanks for posting the question, I got to know this tiny yet useful library.(I am definitely using this in my next project)

I did some digging and it seems you can not use setChoicesByValue() for your requirement due to a check in the library reference code:here

However I achieved it by using setValue() instead. Here is a working stackblitz link for you

Dharman
  • 30,962
  • 25
  • 85
  • 135
  • 1
    Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jan 29 '22 at 09:56
  • Thank you for your answer. The problem of `setValue` is that it will be added to the select list and causes to create multiple duplicates in the select list. Therefor i cannot accept this as an answer. – Crezzur Jan 29 '22 at 10:47