【问题标题】:Why do flash messages in Laravel Livewire only show once?为什么 Laravel Livewire 中的 flash 消息只显示一次?
【发布时间】:2021-08-29 04:06:39
【问题描述】:

我在使用 Laravel Livewire 时遇到了闪现消息不显示的问题。

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

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

<?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

【问题讨论】:

    标签: laravel laravel-livewire


    【解决方案1】:

    我认为这与Livewire 的关系不大,而与Alpine 的关系更大,它是生命周期。它第一次工作的原因是因为Alpine 组件不在DOM 中,因此当将flash 消息添加到DOM 时,它会使用x-data="{ show: true } 进行初始化,因此您的组件会显示出来。当您单击close 按钮将show 的值更改为false,然后更新某些内容并按save 时,组件已经在DOM 中,因此不会再次初始化,这意味着@987654332 的值@ 未设置为 true

    JetstreamLivewaire 堆栈中有使用带有LivewireAlpine 的flash 消息的示例。它使用事件而不是session()

    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 内容并将其设置为 shown = true

    【讨论】:

    • 太棒了!效果要好得多,我没想到要看看jetstream以及他们是如何做到的。感谢您的帮助,非常感谢。
    猜你喜欢
    • 2011-07-05
    • 1970-01-01
    • 1970-01-01
    • 2022-08-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-22
    • 1970-01-01
    相关资源
    最近更新 更多