I'm currently trying to implement a repeater WebComponent to allow the company to easily create front-end without depending on any framework (decision took by architecture). Here'
Solution 1:
Solution 1
Put the repeater around your elements. Ex. for a minimal <data-repeater>
custom element :
customElements.define('data-repeater', classextendsHTMLElement
{
connectedCallback()
{
const parent = this.firstElementChildconst data = JSON.parse(this.dataset.values)
constinterpolate = obj => parent.innerHTML.replace(
/\${(\w+)}/g,
(match, key) => obj[key]
)
parent.innerHTML = data.map(interpolate).join('')
}
})
<data-repeaterdata-values='[{"label": "Item 1", "id":1}, {"label": "Item 2", "id": 2}]'><ul><liid="${id}">${label}</li></ul></data-repeater><data-repeaterdata-values='[{"name": "option 1", "value":1}, {"name": "option 2", "value": 2}]'><select><optionvalue="${value}">${name}</option></select></data-repeater>
Solution 2
Use customized built-in elements. You need to choose a new name for each standard element you want to extend, but you can reuse internally a unique base class to render the elements:
<select is="repeat-option" data-values="[...]">
<option value="${value}">${name}</option>
</select>
customElements.define('select-repeater', classextendsHTMLSelectElement {
connectedCallback() { render(this) }
}, { extends: 'select' })
customElements.define('ul-repeater', classextendsHTMLUListElement {
connectedCallback() { render(this) }
}, { extends: 'ul' })
functionrender(view) {
const data = JSON.parse(view.dataset.values)
constinterpolate = obj => view.innerHTML.replace(
/\${(\w+)}/g,
(match, key) => obj[key]
)
view.innerHTML = data.map(interpolate).join('')
}
<scriptsrc="https://rawgit.com/WebReflection/document-register-element/master/build/document-register-element.js"></script><ulis="ul-repeater"data-values='[{"label": "Item 1", "id":1}, {"label": "Item 2", "id": 2}]'><liid="${id}">${label}</li></ul><selectis="select-repeater"data-values='[{"name": "option 1", "value":1}, {"name": "option 2", "value": 2}]'><optionvalue="${value}">${name}</option></select>
If the rendering is very different depending on the element you could decide to create a class for rendering and to use derived classes for each type fo rendering ( select, ul, tr, td ), like in this example for tables.