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's my current code:
<ul>
<company-repeat datas='[{"name": "NameValeur", "value": "valeurId"}, {"name": "NameObject", "value": "objectId"}]'>
<li>${name}</option>
</company-repeat>
</ul>
<select name="" id="">
<company-repeat datas='[{"name": "NameValeur", "value": "valeurId"}, {"name": "NameObject", "value": "objectId"}]'>
<option value="${value}">${name}</option>
</company-repeat>
</select>
The list
is rightly working since it seems to have no limitation on which tag allowed inside, but the select is not allowing the customElement
company-repeat
in it and by extension, break the feature and just display <option value="${value}">${name}</option>
Here's the source code of my WebComponent
class CompanyRepeater extends HTMLElement {
connectedCallback() {
this.render();
}
render() {
let datas = JSON.parse(this.getAttribute('datas'));
let elementType = this.getAttribute('element');
this.template = this.innerHTML;
console.log(elementType);
let htmlContent = elementType !== null ? `<${elementType.toLowerCase()}>` : '';
datas.forEach(elem => {
htmlContent += this.interpolate(this.template, elem)}
);
htmlContent += elementType !== null ? `</${elementType.toLowerCase()}>` : '';
this.innerHTML = htmlContent;
}
interpolate(template, obj) {
for(var key in obj) {
const pattern = "${" + key + "}";
if(template.indexOf(pattern) > -1) {
template = template.replace(pattern, obj[key]);
delete(obj[key]);
}
};
return template;
}
}
customElements.define('company-repeat', CompanyRepeater);
My question now is, how can I make it work, no matter what's the parent element? I've added a property element
to my repeater, but it's not allowing me to declare more attribute, and it'll stick not work inside a table.
This is the only thing to prevent me from moving everything to WebComponent.
Formidable Forms is the best WordPress Form Builder plugin. Get it for free! With the Repeater, you can choose the layout you would like for the fields within that section. To set the layout, go into the Field Options setting and select the Repeat Layout that you would like. The Inline format will display all the fields in the Repeater on one row.
To customize the order of the repeater buttons, go to Formidable → Styles → Custom CSS page and add the following CSS. Since section headings can't be used inside a repeater, you could create a two-column layout by following the steps below:
In Elementor Pro, in the Form Integration mechanism, we used a different method for adding repeater controls. Instead of using the add_control method for each nested control of the repeater, we added an array of controls directly into the 'fields' arguments.
The Repeater’s add_control () method is a slightly modified version of the “regular” add_control () method used in all Elementor widgets, but it accepts the exact same parameters. Please note that the instance you created of the repeater class does NOT create the repeater control itself.
Solution 1
Put the repeater around your elements. Ex. for a minimal <data-repeater>
custom element :
customElements.define('data-repeater', class extends HTMLElement
{
connectedCallback()
{
const parent = this.firstElementChild
const data = JSON.parse(this.dataset.values)
const interpolate = obj => parent.innerHTML.replace(
/\${(\w+)}/g,
(match, key) => obj[key]
)
parent.innerHTML = data.map(interpolate).join('')
}
})
<data-repeater data-values='[{"label": "Item 1", "id":1}, {"label": "Item 2", "id": 2}]'>
<ul>
<li id="${id}">${label}</li>
</ul>
</data-repeater>
<data-repeater data-values='[{"name": "option 1", "value":1}, {"name": "option 2", "value": 2}]'>
<select>
<option value="${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', class extends HTMLSelectElement {
connectedCallback() { render(this) }
}, { extends: 'select' })
customElements.define('ul-repeater', class extends HTMLUListElement {
connectedCallback() { render(this) }
}, { extends: 'ul' })
function render(view) {
const data = JSON.parse(view.dataset.values)
const interpolate = obj => view.innerHTML.replace(
/\${(\w+)}/g,
(match, key) => obj[key]
)
view.innerHTML = data.map(interpolate).join('')
}
<script src="https://rawgit.com/WebReflection/document-register-element/master/build/document-register-element.js"></script>
<ul is="ul-repeater" data-values='[{"label": "Item 1", "id":1}, {"label": "Item 2", "id": 2}]'>
<li id="${id}">${label}</li>
</ul>
<select is="select-repeater" data-values='[{"name": "option 1", "value":1}, {"name": "option 2", "value": 2}]'>
<option value="${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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With