Ensure destroying instance reinstates options + tests

This commit is contained in:
Josh Johnson 2017-12-18 12:06:38 +00:00
parent beeeeb87ad
commit 9777287b92
16 changed files with 178 additions and 75 deletions

View file

@ -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) => {

View file

@ -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);
} }

View file

@ -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', () => {

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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;
} }
} }

View file

@ -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');
});
});
}); });

View file

@ -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);
}
} }

View file

@ -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;
});
}); });

View file

@ -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;
}

View 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);
});
});
});

View file

@ -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

View file

@ -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;

View file

@ -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>
`); `);
}, },
}; };