diff --git a/CHANGELOG.md b/CHANGELOG.md index b21f64e..cc3e217 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ Semi-Breaking Changes: - `zoo-tag-options` are now stacked vertically - `zoo-tag-options` - changed left,right padding to `15px` and removed `5px` gap, `--input-tag-padding-top-bottom` and `--input-tag-padding-left-right` to control component padding + - selection will be updated when `data-initial-value` attribute changes - `--input-tag-options-max-height` CSS variable to control max height of options list overlay - `--input-tag-options-overflow` CSS variable to control options list scrolls - `zoo-tag` with `type="tag"` uses same border radius as other components diff --git a/src/zoo-modules/form/input-tag/input-tag.js b/src/zoo-modules/form/input-tag/input-tag.js index 75db35b..43674d4 100644 --- a/src/zoo-modules/form/input-tag/input-tag.js +++ b/src/zoo-modules/form/input-tag/input-tag.js @@ -49,6 +49,18 @@ export class InputTag extends FormElement { }); } + static get observedAttributes() { + return [...super.observedAttributes, 'data-initial-value']; + } + + attributeChangedCallback(name, oldValue, newValue) { + if (name === 'invalid') { + super.attributeChangedCallback(); + } else if (name === 'data-initial-value' && oldValue != null) { + this.handleInitialValues(); + } + } + toggleOptionSelect(e) { const target = this.getElAsParentBySlotName(e.target, 'tag-option'); if (target && target.hasAttribute('selected')) { @@ -114,7 +126,9 @@ export class InputTag extends FormElement { } handleInitialValues() { - const tagOptions = [...this.children].filter(el => el.tagName === 'ZOO-INPUT-TAG-OPTION'); + let tagOptions = []; + [].push.apply(tagOptions, this.children) + tagOptions = tagOptions.filter(el => el.tagName === 'ZOO-INPUT-TAG-OPTION'); const defaultValues = this.hasAttribute('data-initial-value') ? this.getAttribute('data-initial-value') .split(',') diff --git a/src/zoo-modules/form/input-tag/input-tag.spec.mjs b/src/zoo-modules/form/input-tag/input-tag.spec.mjs index 9ac165e..5b66941 100644 --- a/src/zoo-modules/form/input-tag/input-tag.spec.mjs +++ b/src/zoo-modules/form/input-tag/input-tag.spec.mjs @@ -68,6 +68,65 @@ describe('Zoo input tag', function () { expect(ret.selectedTags).not.toContain('Cat'); }); + it('should update initial selection when the attribute changes', async () => { + const ret = await page.evaluate(async () => { + document.body.innerHTML = ` + + + + At least one tag should be selected! + + + + Dog + + The domestic dog (Canis familiaris or Canis lupus familiaris)[4] is a domesticated descendant of the wolf. + + + + Cat + + The cat (Felis catus) is a domestic species of small carnivorous mammal. + + + `; + let options = [...document.querySelectorAll('option')]; + await new Promise(r => setTimeout(r, 10)); + + const input = document.querySelector('zoo-input-tag'); + let selectedTags = [] + input.shadowRoot.querySelectorAll('#input-wrapper zoo-tag').forEach(el=> selectedTags.push(el.textContent.trim())); + const optionsStatus = options.filter((option) => option.hasAttribute('selected')).map(option => option.value); + + input.setAttribute("data-initial-value", "Dog,Cat"); + await new Promise(r => setTimeout(r, 10)); + + let selectedTagsAfter = []; + options = [...document.querySelectorAll('option')]; + input.shadowRoot.querySelectorAll('#input-wrapper zoo-tag').forEach(el=> selectedTagsAfter.push(el.textContent.trim())); + const optionsStatusAfter = options.filter((option) => option.hasAttribute('selected')).map(option => option.value); + + return { + optionsStatus, + selectedTags, + selectedTagsAfter, + optionsStatusAfter + } + }); + expect(ret.optionsStatus).toEqual(['Dog']); + expect(ret.optionsStatus).not.toContain('Cat'); + expect(ret.selectedTags).toContain('Dog'); + expect(ret.selectedTags).not.toContain('Cat'); + + expect(ret.optionsStatusAfter).toContain('Dog'); + expect(ret.optionsStatusAfter).toContain('Cat'); + expect(ret.selectedTagsAfter).toContain('Dog'); + expect(ret.selectedTagsAfter).toContain('Cat'); + }); + it('should not render input error', async () => { const errorDisplay = await page.evaluate(async () => { document.body.innerHTML = `