Skip to content

Precognition doesn't work when combinated with conditional fields helper #11833

@jeroen-balk

Description

@jeroen-balk

Bug description

Hello,

To get precognition to work I did extend the alpine driver like this:

<?php

namespace App\Forms\JsDrivers;

use Statamic\Forms\JsDrivers\Alpine;

class Precognition extends Alpine
{
    public function addToFormAttributes()
    {
        $attributes = parent::addToFormAttributes();

        $attributes['x-ref'] = 'form';
        $attributes['novalidate'] = 'true';

        return $attributes;
    }

    public function addToRenderableFieldAttributes($field)
    {
        return [
            'x-model' => $this->getAlpineXDataKey('form.' . $field->handle(), $this->scope),
            '@change' => 'form.validate(\'' . $field->handle() . '\')'
        ];
    }
}

This way I don't have to add x-ref and novalidate manually to every form and I don't have to override the vendor input renderers. It works as expected.

Then I wanted to add conditional showing of fields to the form, so I included the helper in the as documented here: https://statamic.dev/tags/form-create#including-the-scripts

After that I added the x-if around the field+label inside the {{fields}} loop. The file looks like this:

{{ if form_handle }}
    {{ form:create in="{{form_handle}}" js="precognition" attr:class="form" }}
        <div class="grid grid-cols-12 gap-4"
             x-data='{
                    successMessage: null,
                    form: $form(
                        "post",
                        $refs.form.getAttribute("action"),
                        JSON.parse($refs.form.getAttribute("x-data"))
                    ).setErrors({{ error | json }})
             }'>

            <div class="col-span-12 bg-green-500 rounded-sm text-white block text-sm px-2 py-1 mt-2" x-cloak x-show="successMessage" x-text="successMessage">
            </div>

            {{ fields }}
                {{ col_span = switch(
                        (width == '100') => 'col-span-12',
                        (width == '75') => 'col-span-9',
                        (width == '66') => 'col-span-8',
                        (width == '50') => 'col-span-6',
                        (width == '33') => 'col-span-4',
                        (width == '25') => 'col-span-3',
                        () => 'col-span-12'
                    )
                }}

                <template x-if="{{ show_field }}">
                    <div class="mb-2 {{ col_span }}" :class="{'has-error': form.invalid('{{ handle }}')}">
                        <label class="field-label block mb-1" for="{{ id }}">
                            {{ display }}
                            {{ if validate | contains:required }}
                                <sup class="text-red-500">*</sup>
                            {{ /if }}
                        </label>

                        {{ field }}

                        <div>
                            <small class="bg-red-500 rounded-sm text-white block text-sm px-2 py-1 mt-2"
                                   x-show="form.invalid('{{ handle }}')"
                                   x-cloak
                                   x-text="form.errors.{{ handle }}">
                            </small>
                        </div>
                    </div>
                </template>
            {{ /fields }}

            <input type="text" class="hidden" name="{{ honeypot ?? 'honeypot' }}">

            <div class="col-span-12 flex">
                <button x-data="initSubmit()" type="submit" class="ml-auto btn btn-primary" :disabled="form.processing || form.hasErrors" @click.prevent="submitForm()">
                    {{ trans:form.send }}
                </button>
            </div>

        </div>
    {{ /form:create }}
{{ /if }}

<script>
    function initSubmit() {
        return {
            submitForm() {
                this.form.submit()
                    .then(() => {
                        this.form.reset();
                        this.successMessage = '{{ trans:form.success }}'
                    })
                    .catch(() => {
                        this.successMessage = null;
                    });
            }
        }
    }
</script>

I created a form blueprint with a select and one textarea, selecting option 2 should show the textarea but it does not. When I remove the 'form.' prefix in my addToRenderableFieldAttributes function the conditional rendering works as expected, but precognition doesn't work anymore. The form prefix is necessary as documented here: https://statamic.dev/forms#precognition

So I sort of hit a wall, since I feel like there should be an intended way both techniques can work nicely together but I can't find to figure it out. I also followed the docs so I decided to do a bug request.

Thanks in advance.

Jeroen Balk

How to reproduce

  1. Create a form with conditional logic
  2. Implement Precognition in the form (publish the field renderers or extend the js driver, doesn't really matter)
  3. Check if x-model has 'form.' prefix
  4. Try conditional logic.

Logs

Environment

Environment
Application Name: Buurtvereniging Eibergseweg
Laravel Version: 12.16.0
PHP Version: 8.4.7
Composer Version: 2.8.9
Environment: local
Debug Mode: ENABLED
URL: buurtverenigingeibergseweg.nl.ddev.site
Maintenance Mode: OFF
Timezone: UTC
Locale: en

Cache
Config: NOT CACHED
Events: NOT CACHED
Routes: NOT CACHED
Views: CACHED

Drivers
Broadcasting: log
Cache: file
Database: mariadb
Logs: stack / single
Mail: smtp
Queue: sync
Session: file

Storage
public/storage: NOT LINKED

Statamic
Addons: 0
Sites: 1
Stache Watcher: Enabled (auto)
Static Caching: Disabled
Version: 5.56.0 Solo

Installation

Fresh statamic/statamic site via CLI

Additional details

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions