From 0519b993979a8d5ff4d3870df8208567d67b6226 Mon Sep 17 00:00:00 2001 From: Travis Tidwell Date: Fri, 2 Feb 2018 09:09:21 -0600 Subject: [PATCH] Adding an item comparer configuration to allow custom comparisons of items. --- README.md | 10 +++++++ assets/scripts/src/choices.js | 5 +++- tests/spec/choices_spec.js | 53 +++++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 4689d4a..c7195f1 100644 --- a/README.md +++ b/README.md @@ -99,6 +99,9 @@ Or include Choices directly: maxItemText: (maxItemCount) => { return `Only ${maxItemCount} values can be added.`; }, + itemComparer: (choice, item) => { + return choice === item; + }, classNames: { containerOuter: 'choices', containerInner: 'choices__inner', @@ -458,6 +461,13 @@ const example = new Choices(element, { **Usage:** The text that is shown when a user has focus on the input but has already reached the [max item count](https://github.com/jshjohnson/Choices#maxitemcount). To access the max item count, pass a function with a `maxItemCount` argument (see the [default config](https://github.com/jshjohnson/Choices#setup) for an example), otherwise pass a string. +### itemComparer +**Type:** `Function` **Default:** `strict equality` + +**Input types affected:** `select-one`, `select-multiple` + +**Usage:** Compare choice and value in appropriate way (e.g. deep equality for objects). To compare choice and value, pass a function with a `itemComparer` argument (see the [default config](https://github.com/jshjohnson/Choices#setup) for an example). + ### classNames **Type:** `Object` **Default:** diff --git a/assets/scripts/src/choices.js b/assets/scripts/src/choices.js index a12dc05..42fc772 100644 --- a/assets/scripts/src/choices.js +++ b/assets/scripts/src/choices.js @@ -90,6 +90,9 @@ class Choices { maxItemText: (maxItemCount) => { return `Only ${maxItemCount} values can be added.`; }, + itemComparer: (choice, item) => { + return choice === item; + }, uniqueItemText: 'Only unique values can be added.', classNames: { containerOuter: 'choices', @@ -947,7 +950,7 @@ class Choices { choiceValue.forEach((val) => { const foundChoice = choices.find((choice) => { // Check 'value' property exists and the choice isn't already selected - return choice.value === val; + return this.config.itemComparer(choice.value, val); }); if (foundChoice) { diff --git a/tests/spec/choices_spec.js b/tests/spec/choices_spec.js index 778094f..3577669 100644 --- a/tests/spec/choices_spec.js +++ b/tests/spec/choices_spec.js @@ -78,6 +78,7 @@ describe('Choices', () => { expect(this.choices.config.noChoicesText).toEqual(jasmine.any(String)); expect(this.choices.config.itemSelectText).toEqual(jasmine.any(String)); expect(this.choices.config.classNames).toEqual(jasmine.any(Object)); + expect(this.choices.config.itemComparer).toEqual(jasmine.any(Function)); expect(this.choices.config.callbackOnInit).toEqual(null); expect(this.choices.config.callbackOnCreateTemplates).toEqual(null); }); @@ -1217,4 +1218,56 @@ describe('Choices', () => { expect(selectedItems[0].customProperties).toBe(expectedCustomProperties); }); }); + + describe('should allow to use object in value', function() { + beforeEach(function() { + this.input = document.createElement('select'); + this.input.className = 'js-choices'; + this.input.setAttribute('multiple', ''); + + document.body.appendChild(this.input); + + this.choicesArray = [ + { + label: 'One', + value: { + id: 1 + } + }, + { + label: 'Two', + value: { + id: 2 + } + }, + { + label: 'Three', + value: { + id: 3 + } + } + ]; + }); + + afterEach(function() { + this.choices.destroy(); + }); + + it('should allow the user to supply itemComparer via options', function() { + function comparer(choice, item) { + return choice.id === item.id; + } + + this.choices = new Choices(this.input, { + itemComparer: comparer, + choices: this.choicesArray + }); + + this.choices.setValueByChoice({ + id: 1 + }); + + expect(this.choices.currentState.items[0].label).toBe(this.choicesArray[0].label); + }); + }); });