提问者:小点点

为什么Laravel Livewire中的flash消息只显示一次?


我有一个问题,闪存消息不显示时使用Laravel Livewire。

如果我只使用wire:model,然后单击save按钮,一切正常,并显示成功消息。但是如果我使用wire:model。延迟flash消息只在页面刷新后工作一次,因此,例如,页面加载时,我更改了一个表单字段,然后单击SaveEverything。但是,假设我忘记更改字段,现在单击save,只有在重新加载页面时,才会显示flash消息。

这个人似乎有同样的问题,但没有提供解决方案。同样的问题?

<?php

namespace App\Http\Livewire;
use App\Models\User;
use Illuminate\Support\Facades\Auth;

use Livewire\Component;

class ProfileSettings extends Component
{
    public $display_name;
    public $bio;
    public $location;
    public $website_url;
    public $subscription;
    public $hide_status;
    public $hide_profile;


    public function UpdateProfile()
    {
        $validatedData = $this->validate(
            [
                'display_name' => ['required', 'string', 'min:3', 'max:40', 'regex:/^[a-zA-Z0-9.\s]+$/'],
                'bio' => ['nullable', 'string', 'max:1000'],
                'location' => ['nullable', 'string', 'max:100'],
                'website_url' => ['nullable', 'max:100', 'url'],
                'subscription' => ['nullable', 'numeric', 'min:4.99', 'max:29.99'],
                'hide_status' => 'boolean',
                'hide_profile' => 'boolean', 
            ]
        );

        // Store subscription price in cents.
        if($validatedData['subscription'])
            $validatedData['subscription'] = $this->subscription * 100;
        else
            $validatedData['subscription'] = NULL; 
  
        User::where('id', auth::user()->id)->update($validatedData);

        session()->flash('message', 'Profile settings successfully updated!');
    }
    

    // Populate the form fields with stored data.
    public function mount() {
        $this->display_name = Auth::user()->display_name;
        $this->bio = Auth::user()->bio;
        $this->location = Auth::user()->location;
        $this->website_url = Auth::user()->website_url;
        
        // If a subscription price is set, convert from cents to dollars
        // with two decimal places for displaying.
        if (Auth::user()->subscription)
        {
            $dollars = Auth::user()->subscription / 100;
            $this->subscription = number_format($dollars, 2, '.', ',');
        }

        $this->hide_status = Auth::user()->hide_status;
        $this->hide_profile = Auth::user()->hide_profile;
    }


    public function render()
    {   
        
        return view('livewire.profile-settings');
    }
}
    <div>
        <h3 class="text-xl mb-2">Profile</h3>
        <p>Here you can edit your profile information, privacy and subscription details.</p>
    </div>
    <div class="bg-white rounded-md lg:shadow-md shadow col-span-2">
        <form wire:submit.prevent="UpdateProfile">
            <div class="grid grid-cols-1 gap-3 lg:p-6 p-4">

                <div>
                    <label for="display_name">Display Name</label>
                    <input id="display_name" type="text" class="shadow-none with-border focus:ring-0" wire:model.defer="display_name">
                    @error('display_name')<x-validation-errors :message="$message"/>@enderror
                </div>
                <div>
                    <label for="bio">Bio</label>  
                    <textarea id="bio" rows="3" class="shadow-none bg-gray-100 with-border focus:ring-0" wire:model.defer="bio"></textarea>
                    @error('bio')<x-validation-errors :message="$message"/>@enderror
                </div>
                <div>
                    <label for="location">Location</label>
                    <input id="location" type="text" class="shadow-none with-border focus:ring-0" wire:model.defer="location">
                    @error('location')<x-validation-errors :message="$message"/>@enderror
                </div>
                <div>
                    <label for="website_url">Website URL</label>
                    <input id="website_url" type="text" class="shadow-none with-border focus:ring-0" wire:model.defer="website_url">
                    @error('website_url')<x-validation-errors :message="$message"/>@enderror
                </div>
                <div>
                    <label for="subscription">Subscription Price - minimum $4.99 USD per month or leave blank for free.</label>
                    <div class="flex items-center">
                        <div class="-mr-1 bg-gray-100 border px-3 py-3 rounded-l-md">$</div>
                        <input id="subscription" type="text" class="shadow-none with-border focus:ring-0" wire:model.defer="subscription">
                    </div>
                        @error('subscription')<x-validation-errors :message="$message"/>@enderror
                </div>
                <div class="mt-5 space-y-5 ">
                    <div class="flex justify-between items-center">
                        <div>
                            <h4>Activity Status</h4>
                            <div>Enable to hide your last seen status on your profile.</div>
                        </div>
                        <div class="switches-list -mt-8 is-large">
                            <div class="switch-container">
                                <input type="hidden" value="0" wire:mode.defer="hide_status">
                                <label class="switch"><input type="checkbox" value="1" wire:model.defer="hide_status"><span class="switch-button"></span></label>
                            </div>
                        </div>
                    </div>
                    <hr>
                    <div class="flex justify-between items-center">
                        <div>
                            <h4>Hide Profile</h4>
                            <div>Enable to hide your profile from search results.</div>
                        </div>
                        <div class="switches-list -mt-8 is-large">
                            <div class="switch-container">
                                <input type="hidden" value="0"wire:mode.defer="hide_profile" >
                                <label class="switch"><input type="checkbox" value="1" wire:model.defer="hide_profile"><span class="switch-button"></span></label>
                            </div>
                        </div>
                    </div>
                </div>
               
                <div>
                <x-auth-session-status class="mb-4" :status="session('message')"/>
                </div>

                <div class="flex items-center justify-center">
                    <x-button>
                        <span wire:loading.delay wire:target="UpdateProfile"><x-loading /></span>
                        <span wire:loading.remove wire:target="UpdateProfile">{{ __('Save') }}</span>
                    </x-button>
                </div>
    
            </div>
        </form>

    </div>
</div>

@if ($status)
<div x-data="{ show: true }" x-show="show"
    class="flex justify-between items-center bg-green-200 relative py-3 px-3 rounded-lg">
    <div>
        <div class="ml-2 text-sm text-green-600">
        {{ $status }}
        </div>
    </div>
    <div>
        <button type="button" @click="show = false" class=" text-green-700">
            <span class="text-2xl">&times;</span>
        </button>
    </div>
</div>
@endif

共1个答案

匿名用户

我认为这与Livewire关系不大,而与Alpine和它的生命周期关系更大。它第一次工作的原因是因为Alpin组件不在DOM中,所以当闪存消息被添加到DOM时,它是用x-data="{show: true初始化的}以便显示组件。当您单击关闭按钮将show的值更改为false,然后更新某些内容并按保存,该组件已经在DOM中,因此不会再次初始化意味着show的值没有设置为true

在Jetstream的Livewaire堆栈中,有使用带有LivewireAlpin的Flash消息的示例。它使用事件而不是会话()。

public function save()
{
    // ...
    $this->emit('saved');
}
<div x-data="{ shown: false, timeout: null }"
    x-init="@this.on('saved', () => { clearTimeout(timeout); shown = true; timeout = setTimeout(() => { shown = false }, 2000); })"
    x-show.transition.opacity.out.duration.1500ms="shown"
    style="display: none;">
    {{ __('Updated.') }}
</div>

这将初始化Alpine组件,并为saved事件附加一个侦听器,以便它在听到saved事件时触发一个函数执行,该函数显示消息,然后清除。

如果您想允许用户手动清除消息,您可以删除setTimeout内容并将其设置为show=true