mirror of
https://github.com/Choices-js/Choices.git
synced 2024-05-15 20:16:39 +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 {
|
||||
isScrolledIntoView,
|
||||
getAdjacentEl,
|
||||
wrap,
|
||||
getType,
|
||||
isType,
|
||||
isElement,
|
||||
|
@ -220,6 +219,10 @@ class Choices {
|
|||
this.passedElement.reveal();
|
||||
this.containerOuter.unwrap(this.passedElement.element);
|
||||
|
||||
if (this.isSelectElement) {
|
||||
this.passedElement.setOptions(this.presetChoices);
|
||||
}
|
||||
|
||||
// Clear data store
|
||||
this.clearStore();
|
||||
|
||||
|
@ -388,25 +391,11 @@ class Choices {
|
|||
}
|
||||
|
||||
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
|
||||
this.passedElement.setValue(itemsFilteredString);
|
||||
this.passedElement.setValue(items);
|
||||
} 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
|
||||
this.passedElement.setOptions(selectedOptionsFragment);
|
||||
this.passedElement.setOptions(items);
|
||||
}
|
||||
|
||||
const addItemToFragment = (item) => {
|
||||
|
|
|
@ -152,17 +152,16 @@ export default class Container {
|
|||
}
|
||||
|
||||
wrap(element) {
|
||||
this.wrappedElement = element;
|
||||
wrap(this.wrappedElement, this.element);
|
||||
wrap(element, this.element);
|
||||
}
|
||||
|
||||
unwrap() {
|
||||
// Move passed element back to original position
|
||||
unwrap(element) {
|
||||
// Move passed element outside this element
|
||||
this.element.parentNode.insertBefore(
|
||||
this.wrappedElement,
|
||||
element,
|
||||
this.element,
|
||||
);
|
||||
// Remove container
|
||||
// Remove this element
|
||||
this.element.parentNode.removeChild(this.element);
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,14 @@ describe('components/container', () => {
|
|||
};
|
||||
element = document.createElement('div');
|
||||
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', () => {
|
||||
|
@ -351,21 +358,15 @@ describe('components/container', () => {
|
|||
instance.wrap(document.querySelector('div#wrap-test'));
|
||||
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', () => {
|
||||
let elementToWrap;
|
||||
let elementToUnwrap;
|
||||
|
||||
beforeEach(() => {
|
||||
elementToWrap = document.createElement('div');
|
||||
elementToWrap.id = 'unwrap-test';
|
||||
document.body.appendChild(elementToWrap);
|
||||
elementToUnwrap = document.createElement('div');
|
||||
elementToUnwrap.id = 'unwrap-test';
|
||||
document.body.appendChild(elementToUnwrap);
|
||||
instance.wrap(document.getElementById('unwrap-test'));
|
||||
});
|
||||
|
||||
|
@ -375,16 +376,16 @@ describe('components/container', () => {
|
|||
|
||||
it('moves wrapped element outside of element', () => {
|
||||
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(document.querySelector('div#unwrap-test')).to.be.instanceof(HTMLElement);
|
||||
});
|
||||
|
||||
// it('removes element from DOM', () => {
|
||||
// expect(document.getElementById('container')).to.not.equal(null);
|
||||
// instance.unwrap(elementToWrap);
|
||||
// expect(document.getElementById('container')).to.equal(null);
|
||||
// });
|
||||
it('removes element from DOM', () => {
|
||||
expect(document.getElementById('container')).to.not.equal(null);
|
||||
instance.unwrap(elementToUnwrap);
|
||||
expect(document.getElementById('container')).to.equal(null);
|
||||
});
|
||||
});
|
||||
|
||||
describe('addLoadingState', () => {
|
||||
|
|
|
@ -20,6 +20,11 @@ describe('components/dropdown', () => {
|
|||
instance = new Dropdown(choicesInstance, choicesElement, DEFAULT_CLASSNAMES);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
document.body.innerHTML = '';
|
||||
instance = null;
|
||||
});
|
||||
|
||||
describe('constructor', () => {
|
||||
it('assigns choices instance to instance', () => {
|
||||
expect(instance.parentInstance).to.eql(choicesInstance);
|
||||
|
|
|
@ -18,6 +18,11 @@ describe('components/input', () => {
|
|||
instance = new Input(choicesInstance, choicesElement, DEFAULT_CLASSNAMES);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
document.body.innerHTML = '';
|
||||
instance = null;
|
||||
});
|
||||
|
||||
describe('constructor', () => {
|
||||
it('assigns choices instance to class', () => {
|
||||
expect(instance.parentInstance).to.eql(choicesInstance);
|
||||
|
|
|
@ -17,6 +17,11 @@ describe('components/list', () => {
|
|||
instance = new List(choicesInstance, choicesElement, DEFAULT_CLASSNAMES);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
document.body.innerHTML = '';
|
||||
instance = null;
|
||||
});
|
||||
|
||||
describe('constructor', () => {
|
||||
it('assigns choices instance to class', () => {
|
||||
expect(instance.parentInstance).to.eql(choicesInstance);
|
||||
|
|
|
@ -18,6 +18,11 @@ describe('components/wrappedElement', () => {
|
|||
instance = new WrappedElement(choicesInstance, choicesElement, DEFAULT_CLASSNAMES);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
document.body.innerHTML = '';
|
||||
instance = null;
|
||||
});
|
||||
|
||||
describe('getElement', () => {
|
||||
it('returns DOM reference of element', () => {
|
||||
expect(instance.getElement()).to.eql(choicesElement);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import WrappedElement from './wrapped-element';
|
||||
import { reduceToValues } from './../lib/utils';
|
||||
|
||||
export default class WrappedInput extends WrappedElement {
|
||||
constructor(instance, element, classNames) {
|
||||
|
@ -28,8 +29,11 @@ export default class WrappedInput extends WrappedElement {
|
|||
super.enable();
|
||||
}
|
||||
|
||||
setValue(value) {
|
||||
this.element.setAttribute('value', value);
|
||||
this.element.value = value;
|
||||
setValue(items) {
|
||||
const itemsFiltered = reduceToValues(items);
|
||||
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');
|
||||
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 templates from './../templates';
|
||||
|
||||
export default class WrappedSelect extends WrappedElement {
|
||||
constructor(instance, element, classNames) {
|
||||
|
@ -28,11 +29,6 @@ export default class WrappedSelect extends WrappedElement {
|
|||
super.enable();
|
||||
}
|
||||
|
||||
setOptions(options) {
|
||||
this.element.innerHTML = '';
|
||||
this.element.appendChild(options);
|
||||
}
|
||||
|
||||
getPlaceholderOption() {
|
||||
return this.element.querySelector('option[placeholder]');
|
||||
}
|
||||
|
@ -44,4 +40,24 @@ export default class WrappedSelect extends WrappedElement {
|
|||
getOptionGroups() {
|
||||
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');
|
||||
instance = new WrappedSelect(choicesInstance, choicesElement, DEFAULT_CLASSNAMES);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
document.body.innerHTML = '';
|
||||
instance = null;
|
||||
});
|
||||
});
|
||||
|
|
|
@ -593,4 +593,13 @@ export const getWindowHeight = () => {
|
|||
html.scrollHeight,
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @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', () => {
|
||||
it('returns choices', () => {
|
||||
const expectedResponse = state.choices;
|
||||
|
|
|
@ -226,9 +226,9 @@ export const TEMPLATES = {
|
|||
</div>
|
||||
`);
|
||||
},
|
||||
option(globalClasses, data) {
|
||||
option(data) {
|
||||
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