mirror of
https://github.com/Choices-js/Choices.git
synced 2024-06-04 15:02:23 +02:00
Ensure destroying instance reinstates options + tests
This commit is contained in:
parent
beeeeb87ad
commit
9777287b92
|
@ -15,7 +15,6 @@ import { clearAll } from './actions/misc';
|
||||||
import {
|
import {
|
||||||
isScrolledIntoView,
|
isScrolledIntoView,
|
||||||
getAdjacentEl,
|
getAdjacentEl,
|
||||||
wrap,
|
|
||||||
getType,
|
getType,
|
||||||
isType,
|
isType,
|
||||||
isElement,
|
isElement,
|
||||||
|
@ -220,6 +219,10 @@ class Choices {
|
||||||
this.passedElement.reveal();
|
this.passedElement.reveal();
|
||||||
this.containerOuter.unwrap(this.passedElement.element);
|
this.containerOuter.unwrap(this.passedElement.element);
|
||||||
|
|
||||||
|
if (this.isSelectElement) {
|
||||||
|
this.passedElement.setOptions(this.presetChoices);
|
||||||
|
}
|
||||||
|
|
||||||
// Clear data store
|
// Clear data store
|
||||||
this.clearStore();
|
this.clearStore();
|
||||||
|
|
||||||
|
@ -388,25 +391,11 @@ class Choices {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.isTextElement) {
|
if (this.isTextElement) {
|
||||||
// Simplify store data to just values
|
|
||||||
const itemsFiltered = this.store.getItemsReducedToValues(items);
|
|
||||||
const itemsFilteredString = itemsFiltered.join(this.config.delimiter);
|
|
||||||
|
|
||||||
// Update the value of the hidden input
|
// Update the value of the hidden input
|
||||||
this.passedElement.setValue(itemsFilteredString);
|
this.passedElement.setValue(items);
|
||||||
} else {
|
} else {
|
||||||
const selectedOptionsFragment = document.createDocumentFragment();
|
|
||||||
const addOptionToFragment = (item) => {
|
|
||||||
// Create a standard select option
|
|
||||||
const option = this._getTemplate('option', item);
|
|
||||||
// Append it to fragment
|
|
||||||
selectedOptionsFragment.appendChild(option);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Add each list item to list
|
|
||||||
items.forEach(item => addOptionToFragment(item));
|
|
||||||
// Update the options of the hidden input
|
// Update the options of the hidden input
|
||||||
this.passedElement.setOptions(selectedOptionsFragment);
|
this.passedElement.setOptions(items);
|
||||||
}
|
}
|
||||||
|
|
||||||
const addItemToFragment = (item) => {
|
const addItemToFragment = (item) => {
|
||||||
|
|
|
@ -152,17 +152,16 @@ export default class Container {
|
||||||
}
|
}
|
||||||
|
|
||||||
wrap(element) {
|
wrap(element) {
|
||||||
this.wrappedElement = element;
|
wrap(element, this.element);
|
||||||
wrap(this.wrappedElement, this.element);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unwrap() {
|
unwrap(element) {
|
||||||
// Move passed element back to original position
|
// Move passed element outside this element
|
||||||
this.element.parentNode.insertBefore(
|
this.element.parentNode.insertBefore(
|
||||||
this.wrappedElement,
|
element,
|
||||||
this.element,
|
this.element,
|
||||||
);
|
);
|
||||||
// Remove container
|
// Remove this element
|
||||||
this.element.parentNode.removeChild(this.element);
|
this.element.parentNode.removeChild(this.element);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,14 @@ describe('components/container', () => {
|
||||||
};
|
};
|
||||||
element = document.createElement('div');
|
element = document.createElement('div');
|
||||||
element.id = 'container';
|
element.id = 'container';
|
||||||
instance = new Container(choicesInstance, element, DEFAULT_CLASSNAMES);
|
document.body.appendChild(element);
|
||||||
|
instance = new Container(choicesInstance, document.getElementById('container'), DEFAULT_CLASSNAMES);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
document.body.innerHTML = '';
|
||||||
|
element = null;
|
||||||
|
instance = null;
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('constructor', () => {
|
describe('constructor', () => {
|
||||||
|
@ -351,21 +358,15 @@ describe('components/container', () => {
|
||||||
instance.wrap(document.querySelector('div#wrap-test'));
|
instance.wrap(document.querySelector('div#wrap-test'));
|
||||||
expect(instance.element.querySelector('div#wrap-test')).to.equal(elementToWrap);
|
expect(instance.element.querySelector('div#wrap-test')).to.equal(elementToWrap);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('assigns reference to element to instance', () => {
|
|
||||||
expect(instance.wrappedElement).to.equal(undefined);
|
|
||||||
instance.wrap(document.querySelector('div#wrap-test'));
|
|
||||||
expect(instance.wrappedElement).to.equal(elementToWrap);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('unwrap', () => {
|
describe('unwrap', () => {
|
||||||
let elementToWrap;
|
let elementToUnwrap;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
elementToWrap = document.createElement('div');
|
elementToUnwrap = document.createElement('div');
|
||||||
elementToWrap.id = 'unwrap-test';
|
elementToUnwrap.id = 'unwrap-test';
|
||||||
document.body.appendChild(elementToWrap);
|
document.body.appendChild(elementToUnwrap);
|
||||||
instance.wrap(document.getElementById('unwrap-test'));
|
instance.wrap(document.getElementById('unwrap-test'));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -375,16 +376,16 @@ describe('components/container', () => {
|
||||||
|
|
||||||
it('moves wrapped element outside of element', () => {
|
it('moves wrapped element outside of element', () => {
|
||||||
expect(instance.element.querySelector('div#unwrap-test')).to.be.instanceof(HTMLElement);
|
expect(instance.element.querySelector('div#unwrap-test')).to.be.instanceof(HTMLElement);
|
||||||
instance.unwrap(elementToWrap);
|
instance.unwrap(elementToUnwrap);
|
||||||
expect(instance.element.querySelector('div#unwrap-test')).to.equal(null);
|
expect(instance.element.querySelector('div#unwrap-test')).to.equal(null);
|
||||||
expect(document.querySelector('div#unwrap-test')).to.be.instanceof(HTMLElement);
|
expect(document.querySelector('div#unwrap-test')).to.be.instanceof(HTMLElement);
|
||||||
});
|
});
|
||||||
|
|
||||||
// it('removes element from DOM', () => {
|
it('removes element from DOM', () => {
|
||||||
// expect(document.getElementById('container')).to.not.equal(null);
|
expect(document.getElementById('container')).to.not.equal(null);
|
||||||
// instance.unwrap(elementToWrap);
|
instance.unwrap(elementToUnwrap);
|
||||||
// expect(document.getElementById('container')).to.equal(null);
|
expect(document.getElementById('container')).to.equal(null);
|
||||||
// });
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('addLoadingState', () => {
|
describe('addLoadingState', () => {
|
||||||
|
|
|
@ -20,6 +20,11 @@ describe('components/dropdown', () => {
|
||||||
instance = new Dropdown(choicesInstance, choicesElement, DEFAULT_CLASSNAMES);
|
instance = new Dropdown(choicesInstance, choicesElement, DEFAULT_CLASSNAMES);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
document.body.innerHTML = '';
|
||||||
|
instance = null;
|
||||||
|
});
|
||||||
|
|
||||||
describe('constructor', () => {
|
describe('constructor', () => {
|
||||||
it('assigns choices instance to instance', () => {
|
it('assigns choices instance to instance', () => {
|
||||||
expect(instance.parentInstance).to.eql(choicesInstance);
|
expect(instance.parentInstance).to.eql(choicesInstance);
|
||||||
|
|
|
@ -18,6 +18,11 @@ describe('components/input', () => {
|
||||||
instance = new Input(choicesInstance, choicesElement, DEFAULT_CLASSNAMES);
|
instance = new Input(choicesInstance, choicesElement, DEFAULT_CLASSNAMES);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
document.body.innerHTML = '';
|
||||||
|
instance = null;
|
||||||
|
});
|
||||||
|
|
||||||
describe('constructor', () => {
|
describe('constructor', () => {
|
||||||
it('assigns choices instance to class', () => {
|
it('assigns choices instance to class', () => {
|
||||||
expect(instance.parentInstance).to.eql(choicesInstance);
|
expect(instance.parentInstance).to.eql(choicesInstance);
|
||||||
|
|
|
@ -17,6 +17,11 @@ describe('components/list', () => {
|
||||||
instance = new List(choicesInstance, choicesElement, DEFAULT_CLASSNAMES);
|
instance = new List(choicesInstance, choicesElement, DEFAULT_CLASSNAMES);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
document.body.innerHTML = '';
|
||||||
|
instance = null;
|
||||||
|
});
|
||||||
|
|
||||||
describe('constructor', () => {
|
describe('constructor', () => {
|
||||||
it('assigns choices instance to class', () => {
|
it('assigns choices instance to class', () => {
|
||||||
expect(instance.parentInstance).to.eql(choicesInstance);
|
expect(instance.parentInstance).to.eql(choicesInstance);
|
||||||
|
|
|
@ -18,6 +18,11 @@ describe('components/wrappedElement', () => {
|
||||||
instance = new WrappedElement(choicesInstance, choicesElement, DEFAULT_CLASSNAMES);
|
instance = new WrappedElement(choicesInstance, choicesElement, DEFAULT_CLASSNAMES);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
document.body.innerHTML = '';
|
||||||
|
instance = null;
|
||||||
|
});
|
||||||
|
|
||||||
describe('getElement', () => {
|
describe('getElement', () => {
|
||||||
it('returns DOM reference of element', () => {
|
it('returns DOM reference of element', () => {
|
||||||
expect(instance.getElement()).to.eql(choicesElement);
|
expect(instance.getElement()).to.eql(choicesElement);
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import WrappedElement from './wrapped-element';
|
import WrappedElement from './wrapped-element';
|
||||||
|
import { reduceToValues } from './../lib/utils';
|
||||||
|
|
||||||
export default class WrappedInput extends WrappedElement {
|
export default class WrappedInput extends WrappedElement {
|
||||||
constructor(instance, element, classNames) {
|
constructor(instance, element, classNames) {
|
||||||
|
@ -28,8 +29,11 @@ export default class WrappedInput extends WrappedElement {
|
||||||
super.enable();
|
super.enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
setValue(value) {
|
setValue(items) {
|
||||||
this.element.setAttribute('value', value);
|
const itemsFiltered = reduceToValues(items);
|
||||||
this.element.value = value;
|
const itemsFilteredString = itemsFiltered.join(this.parentInstance.config.delimiter);
|
||||||
|
|
||||||
|
this.element.setAttribute('value', itemsFilteredString);
|
||||||
|
this.element.value = itemsFilteredString;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,4 +16,32 @@ describe('components/wrappedInput', () => {
|
||||||
choicesElement = document.createElement('input');
|
choicesElement = document.createElement('input');
|
||||||
instance = new WrappedInput(choicesInstance, choicesElement, DEFAULT_CLASSNAMES);
|
instance = new WrappedInput(choicesInstance, choicesElement, DEFAULT_CLASSNAMES);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
document.body.innerHTML = '';
|
||||||
|
instance = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('setValue', () => {
|
||||||
|
const data = [
|
||||||
|
{
|
||||||
|
id: 'ID 1',
|
||||||
|
value: 'Value 1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'ID 2',
|
||||||
|
value: 'Value 2',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'ID 3',
|
||||||
|
value: 'Value 3',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
it('sets delimited value of element based on passed data', () => {
|
||||||
|
expect(instance.element.value).to.equal('');
|
||||||
|
instance.setValue(data);
|
||||||
|
expect(instance.element.value).to.equal('Value 1,Value 2,Value 3');
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import WrappedElement from './wrapped-element';
|
import WrappedElement from './wrapped-element';
|
||||||
|
import templates from './../templates';
|
||||||
|
|
||||||
export default class WrappedSelect extends WrappedElement {
|
export default class WrappedSelect extends WrappedElement {
|
||||||
constructor(instance, element, classNames) {
|
constructor(instance, element, classNames) {
|
||||||
|
@ -28,11 +29,6 @@ export default class WrappedSelect extends WrappedElement {
|
||||||
super.enable();
|
super.enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
setOptions(options) {
|
|
||||||
this.element.innerHTML = '';
|
|
||||||
this.element.appendChild(options);
|
|
||||||
}
|
|
||||||
|
|
||||||
getPlaceholderOption() {
|
getPlaceholderOption() {
|
||||||
return this.element.querySelector('option[placeholder]');
|
return this.element.querySelector('option[placeholder]');
|
||||||
}
|
}
|
||||||
|
@ -44,4 +40,24 @@ export default class WrappedSelect extends WrappedElement {
|
||||||
getOptionGroups() {
|
getOptionGroups() {
|
||||||
return Array.from(this.element.getElementsByTagName('OPTGROUP'));
|
return Array.from(this.element.getElementsByTagName('OPTGROUP'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setOptions(options) {
|
||||||
|
const fragment = document.createDocumentFragment();
|
||||||
|
const addOptionToFragment = (data) => {
|
||||||
|
// Create a standard select option
|
||||||
|
const template = templates.option(data);
|
||||||
|
// Append it to fragment
|
||||||
|
fragment.appendChild(template);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add each list item to list
|
||||||
|
options.forEach(optionData => addOptionToFragment(optionData));
|
||||||
|
|
||||||
|
this.appendDocFragment(fragment);
|
||||||
|
}
|
||||||
|
|
||||||
|
appendDocFragment(fragment) {
|
||||||
|
this.element.innerHTML = '';
|
||||||
|
this.element.appendChild(fragment);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,4 +16,9 @@ describe('components/wrappedSelect', () => {
|
||||||
choicesElement = document.createElement('select');
|
choicesElement = document.createElement('select');
|
||||||
instance = new WrappedSelect(choicesInstance, choicesElement, DEFAULT_CLASSNAMES);
|
instance = new WrappedSelect(choicesInstance, choicesElement, DEFAULT_CLASSNAMES);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
document.body.innerHTML = '';
|
||||||
|
instance = null;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -593,4 +593,13 @@ export const getWindowHeight = () => {
|
||||||
html.scrollHeight,
|
html.scrollHeight,
|
||||||
html.offsetHeight,
|
html.offsetHeight,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const reduceToValues = (items, key = 'value') => {
|
||||||
|
const values = items.reduce((prev, current) => {
|
||||||
|
prev.push(current[key]);
|
||||||
|
return prev;
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return values;
|
||||||
|
}
|
56
src/scripts/src/lib/utils.test.js
Normal file
56
src/scripts/src/lib/utils.test.js
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
import { expect } from 'chai';
|
||||||
|
import { reduceToValues } from './utils';
|
||||||
|
|
||||||
|
describe('utils', () => {
|
||||||
|
describe('reduceToValues', () => {
|
||||||
|
const items = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
choiceId: 1,
|
||||||
|
groupId: -1,
|
||||||
|
value: 'Item one',
|
||||||
|
label: 'Item one',
|
||||||
|
active: false,
|
||||||
|
highlighted: false,
|
||||||
|
customProperties: null,
|
||||||
|
placeholder: false,
|
||||||
|
keyCode: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
choiceId: 2,
|
||||||
|
groupId: -1,
|
||||||
|
value: 'Item two',
|
||||||
|
label: 'Item two',
|
||||||
|
active: true,
|
||||||
|
highlighted: false,
|
||||||
|
customProperties: null,
|
||||||
|
placeholder: false,
|
||||||
|
keyCode: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
choiceId: 3,
|
||||||
|
groupId: -1,
|
||||||
|
value: 'Item three',
|
||||||
|
label: 'Item three',
|
||||||
|
active: true,
|
||||||
|
highlighted: true,
|
||||||
|
customProperties: null,
|
||||||
|
placeholder: false,
|
||||||
|
keyCode: null,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
it('returns an array of item values', () => {
|
||||||
|
const expectedResponse = [
|
||||||
|
items[0].value,
|
||||||
|
items[1].value,
|
||||||
|
items[2].value,
|
||||||
|
];
|
||||||
|
|
||||||
|
const actualResponse = reduceToValues(items);
|
||||||
|
expect(actualResponse).to.eql(expectedResponse);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -68,19 +68,6 @@ export default class Store {
|
||||||
return values;
|
return values;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get items from store reduced to just their values
|
|
||||||
* @return {Array} Item objects
|
|
||||||
*/
|
|
||||||
getItemsReducedToValues(items) {
|
|
||||||
const values = items.reduce((prev, current) => {
|
|
||||||
prev.push(current.value);
|
|
||||||
return prev;
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return values;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get choices from store
|
* Get choices from store
|
||||||
* @return {Array} Option objects
|
* @return {Array} Option objects
|
||||||
|
|
|
@ -177,17 +177,6 @@ describe('reducers/store', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('getItemsReducedToValues', () => {
|
|
||||||
it('returns an array of item values', () => {
|
|
||||||
const expectedResponse = state.items.reduce((items, item) => {
|
|
||||||
items.push(item.value);
|
|
||||||
return items;
|
|
||||||
}, []);
|
|
||||||
const actualResponse = instance.getItemsReducedToValues(state.items);
|
|
||||||
expect(actualResponse).to.eql(expectedResponse);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('getChoices', () => {
|
describe('getChoices', () => {
|
||||||
it('returns choices', () => {
|
it('returns choices', () => {
|
||||||
const expectedResponse = state.choices;
|
const expectedResponse = state.choices;
|
||||||
|
|
|
@ -226,9 +226,9 @@ export const TEMPLATES = {
|
||||||
</div>
|
</div>
|
||||||
`);
|
`);
|
||||||
},
|
},
|
||||||
option(globalClasses, data) {
|
option(data) {
|
||||||
return strToEl(`
|
return strToEl(`
|
||||||
<option value="${data.value}" selected>${data.label}</option>
|
<option value="${data.value}" ${data.selected ? 'selected' : ''} ${data.disabled ? 'disabled' : ''}>${data.label}</option>
|
||||||
`);
|
`);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue