8000 Precognition doesn't work when combinated with conditional fields helper · Issue #11833 · statamic/cms · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

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

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

Open
jeroen-balk opened this issue May 31, 2025 · 3 comments
Open
Labels

Comments

@jeroen-balk
Copy link
jeroen-balk commented May 31, 2025

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

@ryanmitchell
Copy link
Contributor

I think you need to override addToRenderableFieldData():

    public function addToRenderableFieldData($field, $data)
    {
        return [
            'show_field' => $this->renderAlpineShowFieldJs($field->conditions(), 'form.'.$this->scope),
        ];
    }

@jeroen-balk
Copy link
Author

I get the idea of changing the scope, but it seems that it doesn't work. That results in the following error:

Image

What I also tried:

  • NOT prefixing x-model with 'form.' in addToRenderableFieldAttributes
  • NOT prefixing show_field scope in addToRenderableFieldData with 'form.'
  • and passing js="precognition:form" (passing scope) to the jsDriver.

This renders $data.form in the conditions and prefixed the form handles with form. No errors, but precognition is broken and conditional showing of fields also doesn't work.

@ryanmitchell
Copy link
Contributor

Passing the scope will mean it's applied all the time, which isnt what you want. What about (this will use 'form' when no other scope is applied).

    public function addToRenderableFieldData($field, $data)
    {
        return [
            'show_field' => $this->renderAlpineShowFieldJs($field->conditions(), $this->scope ?? 'form'),
        ];
    }

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

No branches or pull requests

3 participants
0