2025-07-24 09:17:20 +02:00
|
|
|
import Sortable from 'sortablejs';
|
|
|
|
|
|
|
|
|
|
export class RepeatLine extends HTMLDivElement{
|
|
|
|
|
connectedCallback(){
|
|
|
|
|
this.$props = this.getProps(this, { maxRows: 5 });
|
|
|
|
|
this.$refs = this.getRefs(this);
|
|
|
|
|
|
|
|
|
|
this.rowHTML = this.$refs.rows.children[0].outerHTML;
|
|
|
|
|
|
|
|
|
|
this.init();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Hook up events for the row.
|
|
|
|
|
setUpRow(row) {
|
|
|
|
|
const rowRefs = this.getRefs(row);
|
|
|
|
|
|
|
|
|
|
rowRefs.removeButton.onclick = (e) => {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
this.removeRow(row);
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Enable or disable addButton as necessary.
|
|
|
|
|
updateAddButton() {
|
|
|
|
|
if (this.$refs.rows.children.length >= this.$props.maxRows) {
|
|
|
|
|
this.$refs.addButton.setAttribute('disabled', '');
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.$refs.addButton.removeAttribute('disabled');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Update array key values to the row number
|
|
|
|
|
updateFieldNames() {
|
|
|
|
|
[...this.$refs.rows.children]
|
|
|
|
|
.forEach((el, index) => {
|
|
|
|
|
el.querySelectorAll('[name]')
|
|
|
|
|
.forEach(el => {
|
|
|
|
|
const newName = el.getAttribute('name').replace(/\[\d\]/gm, `[${index}]`);
|
|
|
|
|
el.setAttribute('name', newName);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
addRow() {
|
|
|
|
|
if (
|
|
|
|
|
!this.rowHTML ||
|
|
|
|
|
this.$refs.rows.children.length >= this.$props.maxRows
|
|
|
|
|
) return;
|
|
|
|
|
|
|
|
|
|
let newRow = this.createFromHTML(this.rowHTML);
|
|
|
|
|
newRow.removeAttribute('id');
|
|
|
|
|
this.setUpRow(newRow);
|
|
|
|
|
|
|
|
|
|
this.$refs.rows.appendChild(newRow);
|
|
|
|
|
newRow.querySelector('input,textarea,select').focus();
|
2025-07-29 11:52:57 +02:00
|
|
|
newRow.querySelectorAll('input,textarea,select').forEach(el=>{
|
|
|
|
|
el.setAttribute('value','');
|
|
|
|
|
el.value = "";
|
|
|
|
|
})
|
2025-07-24 09:17:20 +02:00
|
|
|
this.updateFieldNames();
|
|
|
|
|
this.updateAddButton();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
removeRow(row) {
|
|
|
|
|
if (this.$refs.rows.children.length <= 1) return;
|
|
|
|
|
|
|
|
|
|
row.remove();
|
|
|
|
|
this.$refs.rows.focus();
|
|
|
|
|
|
|
|
|
|
this.updateFieldNames();
|
|
|
|
|
this.updateFieldNames();
|
|
|
|
|
}
|
|
|
|
|
init() {
|
|
|
|
|
this.setUpRow(this.$refs.rows.children[0]);
|
|
|
|
|
|
|
|
|
|
this.$refs.addButton.onclick = (e) => {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
this.addRow();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.updateFieldNames();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let repeater__rows = this.querySelector('.form-repeater__rows');
|
|
|
|
|
new Sortable(repeater__rows,{
|
|
|
|
|
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Return an object that contains references to DOM objects.
|
|
|
|
|
getRefs(el) {
|
|
|
|
|
let result = {};
|
|
|
|
|
|
|
|
|
|
[...el.querySelectorAll('[data-ref]')]
|
|
|
|
|
.forEach(ref => {
|
|
|
|
|
result[ref.dataset.ref] = ref;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
setDefaults(obj, defaults) {
|
|
|
|
|
let results = obj;
|
|
|
|
|
|
|
|
|
|
for (const prop in defaults) {
|
|
|
|
|
if (!obj.hasOwnProperty(prop)) {
|
|
|
|
|
results[prop] = defaults[prop];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return results;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
getProps(el, defaults={}) {
|
|
|
|
|
return this.setDefaults(
|
|
|
|
|
JSON.parse(el.dataset.props ?? '{}'),
|
|
|
|
|
defaults
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
createFromHTML(html='') {
|
|
|
|
|
let element = document.createElement(null);
|
|
|
|
|
element.innerHTML = html;
|
|
|
|
|
return element.firstElementChild;
|
|
|
|
|
}
|
|
|
|
|
}
|