diff --git a/README.md b/README.md
index b5d5b9a..d0eef2d 100644
--- a/README.md
+++ b/README.md
@@ -92,6 +92,7 @@ will be returned. If you target one element, that instance will be returned.
position: 'auto',
resetScrollPosition: true,
regexFilter: null,
+ addItemFilter: null,
shouldSort: true,
shouldSortItems: false,
sortFn: () => {...},
@@ -339,6 +340,24 @@ Pass an array of objects:
**Usage:** Whether the scroll position should reset after adding an item.
+### addItemFilter
+**Type:** `Function` **Default:** `null`
+
+**Input types affected:** `text`
+
+**Usage:** A callback function that will need to return `true` for a user to successfully add an item.
+
+**Example:**
+
+```js
+// Only adds items matching the text test
+new Choices(element, {
+ addItemFilter: function (value) {
+ return (value !== 'test')
+ }
+});
+```
+
### regexFilter
**Type:** `Regex` **Default:** `null`
diff --git a/cypress/integration/text.spec.js b/cypress/integration/text.spec.js
index b65ce34..abdc4a2 100644
--- a/cypress/integration/text.spec.js
+++ b/cypress/integration/text.spec.js
@@ -293,6 +293,39 @@ describe('Choices - text element', () => {
});
});
+ describe('custom add item callback', () => {
+ describe('inputting a value that satisfies the addItemFilter', () => {
+ const input = 'test';
+
+ it('allows me to add choice', () => {
+ cy.get('[data-test-hook=add-item-callback]')
+ .find('.choices__input--cloned')
+ .type(input)
+ .type('{enter}');
+
+ cy.get('[data-test-hook=add-item-callback]')
+ .find('.choices__list--multiple .choices__item')
+ .last()
+ .should($choice => {
+ expect($choice.text().trim()).to.equal(input);
+ });
+ });
+ });
+
+ describe('inputting a value that does not satisfy the callback', () => {
+ it('displays dropdown prompt', () => {
+ cy.get('[data-test-hook=add-item-callback]')
+ .find('.choices__input--cloned')
+ .type(`this is not the allowed text`)
+ .type('{enter}');
+
+ cy.get('[data-test-hook=add-item-callback]')
+ .find('.choices__list--dropdown')
+ .should('not.be.visible');
+ });
+ });
+ });
+
describe('disabled via attribute', () => {
it('does not allow me to input data', () => {
cy.get('[data-test-hook=disabled-via-attr]')
diff --git a/public/test/text.html b/public/test/text.html
index cc5d648..dd7427f 100644
--- a/public/test/text.html
+++ b/public/test/text.html
@@ -64,6 +64,11 @@
+
+
+
+
+
@@ -120,6 +125,12 @@
addItems: false,
});
+ new Choices('#choices-add-item-callback', {
+ addItemFilter: function (value) {
+ return (value !== 'test')
+ }
+ });
+
new Choices('#choices-disabled-via-attr');
new Choices('#choices-prepend-append', {
diff --git a/src/scripts/choices.js b/src/scripts/choices.js
index d8e2155..170c968 100644
--- a/src/scripts/choices.js
+++ b/src/scripts/choices.js
@@ -987,6 +987,19 @@ class Choices {
? this.config.uniqueItemText(value)
: this.config.uniqueItemText;
}
+
+ if (
+ isType('Function', this.config.addItemFilter) &&
+ this.config.addItemFilter(value) &&
+ this._isTextElement &&
+ this.config.addItems &&
+ canAddItem
+ ) {
+ canAddItem = false;
+ notice = isType('Function', this.config.customAddItemText)
+ ? this.config.customAddItemText(value)
+ : this.config.customAddItemText;
+ }
}
return {
diff --git a/src/scripts/constants.js b/src/scripts/constants.js
index 1f844c3..64aac00 100644
--- a/src/scripts/constants.js
+++ b/src/scripts/constants.js
@@ -64,6 +64,7 @@ export const DEFAULT_CONFIG = {
noChoicesText: 'No choices to choose from',
itemSelectText: 'Press to select',
uniqueItemText: 'Only unique values can be added',
+ customAddItemText: 'Only values matching specific conditions can be added.',
addItemText: value => `Press Enter to add "${stripHTML(value)}"`,
maxItemText: maxItemCount => `Only ${maxItemCount} values can be added`,
itemComparer: (choice, item) => choice === item,
@@ -71,6 +72,7 @@ export const DEFAULT_CONFIG = {
includeScore: true,
},
callbackOnInit: null,
+ addItemFilter: null,
callbackOnCreateTemplates: null,
classNames: DEFAULT_CLASSNAMES,
};
diff --git a/src/scripts/constants.test.js b/src/scripts/constants.test.js
index f52dc81..01a1f6e 100644
--- a/src/scripts/constants.test.js
+++ b/src/scripts/constants.test.js
@@ -82,9 +82,11 @@ describe('constants', () => {
expect(DEFAULT_CONFIG.noChoicesText).to.be.a('string');
expect(DEFAULT_CONFIG.itemSelectText).to.be.a('string');
expect(DEFAULT_CONFIG.uniqueItemText).to.be.a('string');
+ expect(DEFAULT_CONFIG.customAddItemText).to.be.a('string');
expect(DEFAULT_CONFIG.addItemText).to.be.a('function');
expect(DEFAULT_CONFIG.maxItemText).to.be.a('function');
expect(DEFAULT_CONFIG.fuseOptions).to.be.an('object');
+ expect(DEFAULT_CONFIG.addItemFilter).to.equal(null);
expect(DEFAULT_CONFIG.callbackOnInit).to.equal(null);
expect(DEFAULT_CONFIG.callbackOnCreateTemplates).to.equal(null);
});