verbb / formie

The most user-friendly forms plugin for Craft CMS.
Other
93 stars 68 forks source link

Can I use a select box to create the number of repeater fields displayed using javascript? #1904

Open Jude867 opened 1 month ago

Jude867 commented 1 month ago

Question

Is it possible to have a select box consisting of numbers 0-10. When this select box is changed the corresponding number of repeater fields are displayed? I have set up the select box and a repeater field with a condition to appear if the select box is greater than 0.

I have also used some javascript to trigger the 'add row' button to generate the correct number of repeaters (from select box). However this doesn't work as each additional repeater field has the same index number e.g. new2 rather than new3 or new4 etc.

I presume I need to call a template using javascript but I'm struggling to find the right bit in the source code. Is this possible please?

Many thanks

Additional context

No response

engram-design commented 1 month ago

You can do something like this with JS. Based on the field handles being dropdown and repeater:

const $dropdown = document.querySelector('[data-field-handle="dropdown"]');
const $repeater = document.querySelector('[data-field-handle="repeater"]');
const $repeaterBtn = $repeater.querySelector('[data-add-repeater-row]');

$dropdown.addEventListener('change', function(e) {
    const value = e.target.value;

    for (let i = 0; i < value; i++) {
        $repeater.repeater.addRow({
            target: $repeaterBtn,
        });
    }
});

The only real tricky thing is that the repeater JS's addRow() function expects an event like clicking on the button. I may refactor that later to provide a friendlier API.

Jude867 commented 4 weeks ago

Thank you for this, it's very helpful. I'm still struggling a little though - one repeater is added by default - so if I select '3' from the dropdown I actually get 4. If I change the dropdown to 4 I get the first 3 and another 4 on top. Is it possible to clear all repeaters first before adding more?

Also the numbers don't seem right either - but this may be as a result of above. e.g. if I select '3' from the dropdown menu I get the first repeater as '1' then another 3 repeaters as '2'. If I then change the select to '4' from the dropdown menu I have four additional repeaters but all with '5' as their index.

Thank you for your help

engram-design commented 4 weeks ago

I didn't provide a full example just in case your use case was different to what I imagined. But if you want the number of repeater rows to exactly match what the user enters - you've got some other concerns to address.

What if the user adds or removes rows after using the Dropdown to set how many there are?

What happens if the user starts adding rows manually, and then uses the Dropdown field to either set or change the number of rows? Do the rows get reset or are their values gone?

You've got access to that entire JS class with $repeater.repeater, so you can remove and reset the rows before the change event is triggered again.

$dropdown.addEventListener('change', function(e) {
    $repeater.querySelectorAll('[data-remove-repeater-row]').forEach(($button) => {
        $repeater.repeater.removeRow({
            target: $button,
        });
    });

    const value = e.target.value;

    for (let i = 0; i < value; i++) {
        $repeater.repeater.addRow({
            target: $repeaterBtn,
        });
    }
});

But yes, this logic all needs to be altered based on any default rows you have setup. Again, the Repeater field doesn't allow you to "sync" how many rows it has based on the value you provide it, so it's largely up to you. Fortunately, it's pretty simple to offset the value by 1 (the number of default rows).

const value = e.target.value - 1;
Jude867 commented 3 weeks ago

Thank you much appreciated, it's all working now. I've removed the add row and delete row buttons from the repeater using css, which will hopefully solve the problem regarding user interaction.