Livewire 3 和 Alpine.js 向导:Alpine 表达式中出现意外令牌“}”错误:“$wire。”

问题描述 投票:0回答:1

我正在使用 Livewire 3 和 Alpine.js 3.4.2 在 Laravel 项目中构建一个向导。主向导和每个步骤都是 Livewire 组件。一切正常,直到我单击第一步中的“保存”按钮进入下一步,此时我在浏览器控制台中遇到以下错误:

Alpine 表达式错误:意外的标记“}” 表达式:“$wire。” 未捕获的语法错误:意外的标记“}”

这是我的实现:

主要向导:

class TenantCreate extends Component { 

use AuthorizesActions;
public $tenant;
public $steps;
public $currentStep;

protected $listeners = ['stepCompleted'];

public function mount()
{
    $this->steps = [
        1 => ['status' => false, 'data' => []],
        2 => ['status' => false, 'data' => []],
        3 => ['status' => false, 'data' => []]
    ];

    $this->currentStep = 1;
}

public function stepCompleted($step, $stepStatus = false, $stepData = [])
{
    if ($step === $this->currentStep && $stepStatus) {
        if($step == 1) {
            $this->tenant = $stepData['tenant'];
        }
        $this->steps[$this->currentStep]['data'] = $stepData;
        $this->steps[$this->currentStep]['status'] = $stepStatus;
        $this->currentStep++;
    }
}

}

查看:

<div class="modal fade" id="createModal" tabindex="-1" aria-hidden="true" wire:ignore.self>
    <div class="modal-dialog modal-dialog-centered modal-lg" role="document">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title" id="modalCenterTitle">Create Tenant</h5>
                <button type="button" wire:click='closeModal()' class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
            </div>
            <form wire:submit.prevent>
                <div class="modal-body">
                    <div class="row">
                        <div>
                            <div x-data="app()" x-cloak>
                                <div class="container mx-auto">
                                    <div x-show.transition="step === 'complete'">
                                        <div class="w-100 d-flex flex-column align-items-center justify-content-center">
                                            <img src="{{ asset('admin-assets/img/general/check-icon.svg') }}" alt="Check Icon" class="mb-3">
                                            <h2 class="fs-4 mb-3 text-dark fw-bold">Tenant Created Successfully</h2>
                                        </div>                                          
                                    </div>
                    
                                    <div x-show.transition="step != 'complete'">    
                                        <!--- Top Navigation --->
                                        <div class="border-bottom py-3">

                                            <div class="progress w-75 mx-auto mb-4">
                                                <div class="progress-bar" role="progressbar" 
                                                     x-bind:style="'width: ' + (parseInt(step / 5 * 100)) + '%'" 
                                                     aria-valuenow="step" 
                                                     x-text="parseInt(step / 6 * 100) + '%'" 
                                                     aria-valuemin="0" 
                                                     aria-valuemax="100">
                                                </div>
                                            </div>
                    
                                            <div class="text-uppercase small text-muted mb-1 lh-tight" x-text="`Step : ${step} of 6`"></div>
                                            <div class="d-flex flex-column flex-md-row align-items-center justify-content-between">
                                                <div>
                                                    <div x-show="step === 1">
                                                        <div class="h5 fw-bold text-muted">Basic Information</div>
                                                    </div>
                                                    
                                                    <div x-show="step === 2">
                                                        <div class="h5 fw-bold text-muted">System Parameters</div>
                                                    </div>

                                                    <div x-show="step === 3">
                                                        <div class="h5 fw-bold text-muted">Employees import</div>
                                                    </div>

                                                    <div x-show="step === 4">
                                                        <div class="h5 fw-bold text-muted">Survey Installer(Engagement)</div>
                                                    </div>

                                                    <div x-show="step === 5">
                                                        <div class="h5 fw-bold text-muted">Survey Installer(Experience)</div>
                                                    </div>

                                                    <div x-show="step === 6">
                                                        <div class="h5 fw-bold text-muted">Survey Installer(On-Demand)</div>
                                                    </div>
                                                </div>                        
                                            </div>
                                        </div>
                                        <!--- /Top Navigation --->

                                        <!--- Step Content --->
                                        <div class="py-10">
                                            <div x-show="step === 1">
                                                @livewire('admin.tenants.partials.basic-information', 
                                                    ['stepData' => $steps[1]['data'] ?? [],
                                                     'scope' => 'wizard'])
                                            </div>
                                        
                                            <div x-show="step === 2">
                                                @livewire('admin.tenants.partials.system-parameters', 
                                                    [
                                                        'stepData' => $steps[2]['data'] ?? [], 
                                                        'scope' => 'wizard', 
                                                        'tenant' => $tenant
                                                    ], 
                                                    key('sys-param-' . ($tenant['id'] ?? 'default'))
                                                )
                                            </div>                                            
                                    
                                            <div x-show="step === 3">
                                                @livewire('admin.tenants.partials.employees-import', 
                                                    [
                                                        'stepData' => $steps[3]['data'] ?? [], 
                                                        'tenant' => $tenant,
                                                        'scope' => 'wizard'
                                                    ], 
                                                    key('emp-data-key-' . ($tenant['id'] ?? 'default'))
                                                )
                                            </div>
                                            
                                        </div>             
                                        <!--- / Step Content --->                           
                                    </div>
                                </div>
                    
                                <div class="bottom-0 start-0 end-0 py-4 bg-white" x-show="step != 'complete'">
                                    <div class="container mx-auto p-3">
                                        <div class="d-flex justify-content-between">
                                            <div class="col-6">
                                                <button
                                                    x-show="step > 1"
                                                    wire:click="updateStep(step - 1)"
                                                    class="mx-auto py-2 p-3 rounded-lg shadow text-center text-secondary bg-white border fw-medium" 
                                                    style="width: 8rem;">
                                                    Previous
                                                </button>
                                            </div>
                    
                                            <div>
                                                <button
                                                    x-show="step < 3 && isStepCompleted(step)"
                                                    wire:click="updateStep(step + 1)"
                                                    class="w-32 border-0 py-2 px-3 rounded shadow text-center text-white bg-primary fw-medium"
                                                    style="width: 8rem;">
                                                    Next
                                                </button>

                                                <button
                                                    x-show="step === 3"
                                                    wire:click="updateStep('complete')"
                                                    class="w-32 border-0 py-2 px-3 rounded shadow text-center text-white bg-primary fw-medium" 
                                                    style="width: 8rem;">
                                                    Complete
                                                </button>
                                            </div>
                                        </div>
                                    </div>
                                </div>
                            </div>
                            <script>
                                function app() {
                                    return {
                                        step: @entangle('currentStep'),
                                        stepsData: @entangle('steps'),
                                        isStepCompleted(step) {
                                            return this.stepsData[parseInt(step)]?.status === true;
                                        }
                                    }
                                }
                            </script>
                        </div>
                    </div>
                </div>
            </form>
        </div>
    </div>
</div>

第一步:

class BasicInformation extends Component
{
    public $tenant, $name, $clean_external_id, $region_id, $regions = [];

    public $scope, $stepStatus = false;

    public function submitBasicInfo()
    {
        $this->validate((new StoreTenant())->rules(1), $this->messages(), $this->attributes());

        DB::beginTransaction();
        try {
            $this->tenant = Tenant::create([
                'name' => $this->name,
                'region_id' => $this->region_id,
            ]);
            
            $this->tenant->update([
                'external_id' => strtolower($this->clean_external_id) . '-' . $this->tenant->id
            ]);

            $this->tenant->dataItem()->create([]);
            $this->tenant->tenant_id = $this->tenant->external_id;

            DB::commit();

            //Agent Request
            $response = (new AgentService($this->tenant->id))->createVhAndSslCeritificate($this->name, $this->tenant->tenant_id);
            if($response['status'] == 200){
                $this->stepStatus = true;
                //only if the component in wizard
                if($this->scope == 'wizard'){
                    $this->dispatch('stepCompleted', 1, $this->stepStatus, $this->getStepData());
                }
                return true;
            }else{
                $this->addError('stepErrors', 'Something went wrong While creating tenant on the server, please contact adminstartor');
                return $this;
            }

            return true;
        }catch (\Exception $e) {
            DB::rollBack();
            throw new \Exception('Error Creating Tenant : ' . $e->getMessage());
        }
    }
}

第一步查看:

<div>
    
    @error('stepErrors')
        <div class="container mt-0">
            <div class="alert alert-danger">
            <h5 class="alert-heading mb-3">Errors:</h5>
                <ul class="list-group list-group-flush">
                    @foreach ($errors->get('stepErrors') as $error)
                        <li class="list-group-item list-group-item-danger d-flex justify-content-between align-items-center">
                            <span>{{ $error }}</span>
                            <span class="badge bg-danger rounded-pill">!</span>
                        </li>
                    @endforeach
                </ul>
            </div>
        </div>
    @enderror
                                            
    {{-- Form Fields --}}
    <div class="row mt-3">
        <div class="col-6">
            <div class="d-flex align-items-center">
                <label class="form-label mb-0">Domain</label>
                <x-right-popover title="Tenant Domain" 
                content="<p>This field will be used for Tenant URLS<br><small>Must be valid URL, no spaces or symbols e.g. engagesoft</small></p>"/>
            </div>
            <x-text-input wire:model='name' placeholder="Tenant Domain" :disabled="$scope == 'wizard' && $stepStatus"/>
            <x-input-error :messages="$errors->get('name')" />
        </div>

        <div class="col-6">
            <div class="d-flex align-items-center">
                <label class="form-label mb-0">Region</label>
                <x-right-popover title="Tenant Region (server)" 
                content="<p>Choose the region that tenant will be on.</p>"/>
            </div>
            <x-select wire:model='region_id' placeholder="Select Region" :data="$regions" :disabled="$scope == 'wizard' && $stepStatus"
                wire:key="region-select-{{ now() }}" 
            />                
            <x-input-error :messages="$errors->get('region_id')" />
        </div>
    </div>

    <div class="row mt-3 mb-3">
        <div class="col-6 mb-0">
            <div class="d-flex align-items-center">
                <label class="form-label mb-0">Tenant ID</label>
                <x-right-popover title="Tenant ID" 
                content="<p>Unique id, no symbols or spaces.<small>e.g. engage</small></p>"/>
            </div>
            <x-text-input wire:model='clean_external_id' placeholder="Tenant ID" :disabled="$scope == 'wizard' && $stepStatus"/>
            <x-input-error :messages="$errors->get('clean_external_id')" />
        </div>
    </div>
    
    @if (!($scope == 'wizard' && $stepStatus))
        <x-button-loading 
            wire:click="submitBasicInfo"
            buttonName="Save"
            target="submit"
            class="w-32 border-0 py-2 px-3 rounded shadow text-center text-white bg-primary fw-medium" 
        />
    @endif

</div>

Livewire v3.5

Laravel v11.9

PHP v8.3

我尝试过的:

确保正确定义 Alpine.js 初始化(x-data)。

使用不同的方式调用stepCompleted方法直接调用livewire和内部apline:

$wire.call(), @this.call() 

观察结果:

该错误特别指向 Alpine.js 上下文中的 $wire 调用。 通过wire:click指令与Livewire组件交互时。

问题: 是什么导致了意外令牌“}”错误,如何修复它以允许向导中 Livewire 3 和 Alpine.js 之间的无缝集成?

laravel bootstrap-modal alpine.js laravel-11 livewire-3
1个回答
0
投票

我遇到了一个问题,单击表单向导步骤内的提交按钮(每个步骤都是一个 Livewire 组件)会触发传统的表单提交,这不是预期的行为。

问题: 我的表单向导的每个步骤都是一个 Livewire 组件,每个步骤都有一个提交按钮。最初,我像这样绑定提交操作:

<x-button-loading x-on:click="$wire.submitBasicInfo" buttonName="Save" target="submitBasicInfo"/>

如果没有 .prevent 修饰符,单击按钮会触发默认的表单提交行为。这导致表单以传统方式提交,干扰 Livewire 处理。

解决方案: 为了解决这个问题,我使用了 .prevent 修饰符,它可以阻止默认表单提交并允许 Alpine.js 和 Livewire 正确处理表单逻辑:

<x-button-loading @click.prevent="$wire.submitBasicInfo" buttonName="Save" target="submitBasicInfo" />

因此,通过使用 @click.prevent,可以停止默认行为,确保表单提交由 Livewire 控制,而不会发生传统的表单发布。

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.