Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Note on the interaction of conditional-formfields, multipage-form and ajax-form #89

Open
zonky2 opened this issue Mar 25, 2024 · 5 comments

Comments

@zonky2
Copy link
Contributor

zonky2 commented Mar 25, 2024

To ensure that the conditions for previous steps work with MP_Forms, a data attribute is filled with values in the form tag.

When used with ajax-form, the form tag is not updated and therefore no current values can be read from conditional-formfields.

As a workaround, the template ajaxform_inline.html5 can be customised:

<form action="<?php echo $this->action; ?>"<?php if ($this->formId): ?>id="<?php echo $this->formId; ?>"<?php endif; ?>
      method="<?php echo $this->method; ?>"
      enctype="<?php echo $this->enctype; ?>"<?php echo $this->attributes; ?><?php echo $this->novalidate; ?>>
    <div class="formbody">
        <?php if ($this->method != 'get'): ?>
            <input type="hidden" name="FORM_SUBMIT" value="<?php echo $this->formSubmit; ?>">
            <input type="hidden" name="REQUEST_TOKEN" value="{{request_token}}">
            <input type="hidden" name="MAX_FILE_SIZE" value="<?php echo $this->maxFileSize; ?>">
        <?php endif; ?>
        <?php echo $this->hidden; ?>
        <?php echo $this->fields; ?>
    </div>
</form>

The behaviour with Contao 5 still needs to be checked.

@zoglo
Copy link

zoglo commented Mar 26, 2024

Wouldn't work with the insert-tag {{request_token}} as it has been removed in C5

@zonky2
Copy link
Contributor Author

zonky2 commented Mar 26, 2024

@zoglo
Copy link

zoglo commented Mar 26, 2024

Remember that ajaxform won't be used in Contao 5 anymore since it's part of the Contao Core in 5.1, thus you'd be able to use the template from the contao core 😄.

Meaning you wouldn't need to bother about that.

@zonky2
Copy link
Contributor Author

zonky2 commented Mar 26, 2024

@zoglo

The behaviour with Contao 5 still needs to be checked.

@qzminski
Copy link
Member

Below are the snippets for Contao 4.13 and the ajaxform. Also, make sure that you have the version 3.1.3 of the conditionalformfields extension.

ajaxform.html5

<!-- indexer::stop -->
<div class="<?= $this->class ?> block"<?= $this->cssID ?><?php if ($this->style): ?> style="<?= $this->style ?>"<?php endif; ?>>
    <?php if ($this->headline): ?>
        <<?= $this->hl ?>><?= $this->headline ?></<?= $this->hl ?>>
    <?php endif; ?>

    <form<?php if ($this->action): ?> action="<?= $this->action ?>"<?php endif; ?> method="<?= $this->method ?>" enctype="<?= $this->enctype ?>"<?= $this->attributes ?><?= $this->novalidate ?>>
        <div class="formbody">
            <?php if ($this->method !== 'get'): ?>
                <input type="hidden" name="FORM_SUBMIT" value="<?= $this->formSubmit ?>">
                <input type="hidden" name="REQUEST_TOKEN" value="{{request_token}}">
            <?php endif; ?>
            <?= $this->hidden ?>
            <?= $this->fields ?>
        </div>
    </form>

    <script>
        window.addEventListener('DOMContentLoaded', () => {
            const el = document.querySelector('input[name="FORM_SUBMIT"][value="<?= $this->formSubmit; ?>"]').form;

            function request(method, form, url, body, callback) {
                const xhr = new XMLHttpRequest();
                xhr.open('POST', url, true);
                xhr.setRequestHeader('Accept', 'text/html');
                xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
                xhr.setRequestHeader('Contao-Ajax-Form', form.querySelector('[name="FORM_SUBMIT"]').value);

                form.ariaBusy = 'true';
                form.dataset.ajaxForm = 'loading';
                form.classList.add('ajax-loading');

                xhr.onload = () => {
                    form.dispatchEvent(new CustomEvent('ajax-form-onload', {
                        bubbles: true,
                        detail: { body, form, xhr },
                    }));

                    form.ariaBusy = 'false';
                    form.dataset.ajaxForm = '';

                    callback(xhr);
                };

                xhr.send(body || null)
            }

            function replaceForm(xhr, form) {
                const range = document.createRange();
                range.selectNode(form.parentNode);

                const newForm = range.createContextualFragment(xhr.responseText).firstElementChild;
                form.replaceWith(newForm);

                if (!newForm.getAttribute('action')) {
                    newForm.action = xhr.responseURL;
                }

                initForm(newForm);

                var event = new Event('ajax_change');
                newForm.dispatchEvent(event);
                window.dispatchEvent(event);

            }

            function initForm(form) {
                form.addEventListener('submit', e => {
                    e.preventDefault();

                    const formData = new FormData(form);

                    // Send the triggered button data as well
                    if (e.submitter) {
                        formData.append(e.submitter.name, e.submitter.value);

                        // Prevent double form submission
                        e.submitter.disabled = true;
                        setTimeout(() => e.submitter.disabled = false, 30000);
                    }

                    request('POST', form, form.action, formData, xhr => {
                        const location = xhr.getResponseHeader('X-Ajax-Location');

                        // Handle the redirect header
                        if (location) {
                            request('GET', form, location, null, xhr => replaceForm(xhr, form));
                            return;
                        }

                        replaceForm(xhr,form);
                    });
                });
            }

            initForm(el);
        });
    </script>
</div>
<!-- indexer::continue -->

ajaxform_inline.html5

<form<?php if ($this->action): ?> action="<?= $this->action ?>"<?php endif; ?> method="<?= $this->method ?>" enctype="<?= $this->enctype ?>"<?= $this->attributes ?><?= $this->novalidate ?>>
  <div class="formbody">
      <?php if ($this->method !== 'get'): ?>
        <input type="hidden" name="FORM_SUBMIT" value="<?= $this->formSubmit ?>">
        <input type="hidden" name="REQUEST_TOKEN" value="{{request_token}}">
      <?php endif; ?>
      <?= $this->hidden ?>
      <?= $this->fields ?>
  </div>
</form>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants