Начало работы с Laravel Livewire
В этом уроке мы рассмотрим еще один инструмент, который может облегчить вашу жизнь как разработчика Laravel. В частности, мы рассмотрим Livewire, полнофункциональную платформу для Laravel, которая позволяет нам создавать динамические интерфейсы без написания большого количества JavaScript. По сути, все делается с помощью инструментов, с которыми вы уже знакомы как разработчик Laravel.
Что такое Livewire?
Livewire — это библиотека, которая позволяет нам создавать реактивные и динамические интерфейсы с использованием Blade и небольшого количества JavaScript. Я говорю «немного», потому что мы собираемся написать JavaScript только для передачи данных через события браузера и реагирования на них.
Вы можете использовать Livewire для реализации следующих функций без перезагрузки страницы:
- нумерация страниц
- проверка формы
- уведомления
- предварительный просмотр загрузки файлов
Обратите внимание, что Livewire не ограничивается вышеуказанными функциями. Вы можете использовать его для гораздо большего. Вышеуказанные функции — это лишь самые распространенные из них, которые вы, возможно, захотите реализовать в своих приложениях.
Обзор приложения
Мы собираемся создать живое приложение CRUD. По сути, это CRUD-приложение без перезагрузки страницы. Livewire будет обрабатывать все запросы AJAX, необходимые для обновления пользовательского интерфейса. Сюда входит фильтрация результатов через поле поиска, сортировка по заголовку столбца и простая нумерация страниц (предыдущая и следующая). Для создания и редактирования пользователей будут использоваться модальные окна Bootstrap.
Настройка проекта
Теперь вы можете создать новый проект Laravel:
composer create-project laravel/laravel livecrud
Перейдите в livecrud
папку, которую он создаст. Это будет корневая папка проекта, в которой вы будете выполнять все команды в этом руководстве.
Следующим шагом будет создание базы данных MySQL с использованием выбранного вами инструмента управления базой данных. Назовите базу данных как livecrud
.
Установите внутренние зависимости
У нас есть только одна зависимость для серверной части — Livewire. Установите его с помощью следующей команды:
composer require livewire/livewire:2.3
Примечание. Мы устанавливаем конкретную версию, которую мы использовали при создании демо-версии. Если вы будете читать это в будущем, рекомендуется установить самую последнюю версию.
Настройка базы данных
Обновите миграцию по умолчанию для создания users
таблицы и добавьте настраиваемые поля, которые мы собираемся использовать:
// database/migrations/<timestamp>_create_users_table.php public function up() { Schema::create('users', function (Blueprint $table) { $table->id(); $table->string('name'); $table->string('email')->unique(); $table->enum('user_type', ['admin', 'user'])->default('user'); // add this $table->tinyInteger('age'); // add this $table->string('address')->nullable(); // add this $table->timestamp('email_verified_at')->nullable(); $table->string('password'); $table->rememberToken(); $table->timestamps(); }); }
Затем обновите database/factories/UserFactory.php
файл и укажите значения в добавленных нами настраиваемых полях:
// database/factories/UserFactory.php public function definition() { return [ 'name' => $this->faker->name, 'email' => $this->faker->unique()->safeEmail, 'email_verified_at' => now(), 'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password 'remember_token' => Str::random(10), // add these 'user_type' => 'user', 'age' => $this->faker->numberBetween(18, 60), 'address' => $this->faker->address, ]; }
Наконец, откройте database/seeders/DatabaseSeeder.php
файл и раскомментируйте вызов для создания фиктивных пользователей:
// database/seeders/DatabaseSeeder.php public function run() { \App\Models\User::factory(100)->create(); }
Не забудьте обновить .env
файл, указав тестовую базу данных, которую вы собираетесь использовать. В данном случае я назвал базу данных livecrud
. Как только это будет сделано, запустите миграцию и сеялку для заполнения базы данных:
php artisan migrate php artisan db:seed
Настройка внешних зависимостей
Чтобы упростить задачу, мы собираемся использовать каркас Laravel для Bootstrap. Чтобы использовать это, вам сначала необходимо установить пакет laravel/ui
:
composer require laravel/ui
Затем установите Bootstrap 4. Это добавит конфигурацию в ваш webpack.mix.js
файл и создаст файлы resources/js/app.js
и resources/sass/app.scss
:
php artisan ui bootstrap
Затем добавьте в resources/sass/app.scss
файл Font Awsome. По умолчанию там уже должны быть шрифты, переменные и загрузочный импорт:
// Fonts @import url("https://fonts.googleapis.com/css?family=Nunito"); // Variables @import "variables"; // Bootstrap @import "~bootstrap/scss/bootstrap"; // add these: @import "~@fortawesome/fontawesome-free/scss/fontawesome"; @import "~@fortawesome/fontawesome-free/scss/brands"; @import "~@fortawesome/fontawesome-free/scss/regular"; @import "~@fortawesome/fontawesome-free/scss/solid";
Как только это будет сделано, установите все зависимости:
npm install @fortawesome/fontawesome-free npm install
Создание компонента Livewire
Вы можете использовать make:livewire
команду для создания нового компонента Livewire:
php artisan make:livewire LiveTable
Это создаст следующие файлы:
app/Http/Livewire/LiveTable.php
— контроллер компонентаresources/views/livewire/live-table.blade.php
— файл представления для компонента
Откройте resources/views/livewire/live-table.blade.php
файл и добавьте следующее:
<div> <div class="row mb-4"> <div class="col-md-12"> <div class="float-right mt-5"> <input wire:model="search" class="form-control" type="text" placeholder="Search Users..."> </div> </div> </div> <div class="row"> @if ($users->count()) <table class="table"> <thead> <tr> <th> <a wire:click.prevent="sortBy('name')" role="button" href="#"> Name @include('includes.sort-icon', ['field' => 'name']) </a> </th> <th> <a wire:click.prevent="sortBy('email')" role="button" href="#"> Email @include('includes.sort-icon', ['field' => 'email']) </a> </th> <th> <a wire:click.prevent="sortBy('address')" role="button" href="#"> Address @include('includes.sort-icon', ['field' => 'address']) </a> </th> <th> <a wire:click.prevent="sortBy('age')" role="button" href="#"> Age @include('includes.sort-icon', ['field' => 'age']) </a> </th> <th> <a wire:click.prevent="sortBy('created_at')" role="button" href="#"> Created at @include('includes.sort-icon', ['field' => 'created_at']) </a> </th> <th> Delete </th> <th> Edit </th> </tr> </thead> <tbody> @foreach ($users as $user) <tr> <td>{{ $user->name }}</td> <td>{{ $user->email }}</td> <td>{{ $user->address }}</td> <td>{{ $user->age }}</td> <td>{{ $user->created_at->format('m-d-Y') }}</td> <td> <button class="btn btn-sm btn-danger"> Delete </button> </td> <td> <button class="btn btn-sm btn-dark"> Edit </button> </td> </tr> @endforeach </tbody> </table> @else <div class="alert alert-warning"> Your query returned zero results. </div> @endif </div> <div class="row"> <div class="col"> {{ $users->links() }} </div> </div> </div>
Кода очень много, поэтому давайте разберем его сверху вниз. Во-первых, у нас есть поле поиска для поиска пользователей. Мы хотим, чтобы пользователи могли видеть результаты своего запроса по мере ввода. Мы реализуем это с помощью wire:model
. Это позволяет нам передавать имя переменной из класса компонента ( LiveTable
). Независимо от того, что пользователь вводит в это поле, оно будет синхронизировано со значением этой переменной. В данном случае мы привязываем search
переменную:
<input wire:model="search" class="form-control" type="text" placeholder="Search Users...">
Позже в коде класса компонента LiveTable вы увидите связанную переменную, как показано в приведенном ниже коде. В Livewire они называются свойствами . Если вы используете Vue, то это эквивалент состояния. public
Доступ непосредственно из внешнего интерфейса возможен только к свойствам:
// app/Http/Livewire/LiveTable.php <?php class LiveTable extends Component { public $search = ''; // don't add this yet }
Далее у нас есть заголовки таблиц. Здесь мы используем wire:click.prevent
для прослушивания событий кликов в элементе ссылки. В Livewire это называется действиями . По сути, они позволяют вам прослушивать события браузера, но реагировать на них, используя методы серверной части. Использование .prevent
предотвращает действие браузера по умолчанию. Значение, которое вы указываете для этого, — это имя метода, который вы хотите выполнить в классе компонента. В данном случае это sortBy
. Затем мы передаем имя столбца, который хотим отсортировать:
<th> <a wire:click.prevent="sortBy('name')" role="button" href="#"> Name @include('includes.sort-icon', ['field' => 'name']) </a> </th>
Вот как выглядит соответствующий метод в классе компонента. Мы добавим код для этого позже:
// app/Http/Livewire/LiveTable.php public function sortBy($field) { // }
В приведенный выше код мы включили еще один файл представления с именем sort-icon
. Создайте resources/views/includes/sort-icon.blade.php
файл и добавьте следующее. Это отобразит текущий значок сортировки на основе текущей сортировки, выбранной пользователем:
@if ($sortField !== $field) <i class="text-muted fas fa-sort"></i> @elseif ($sortAsc) <i class="fas fa-sort-up"></i> @else <i class="fas fa-sort-down"></i> @endif
Вот и все, что касается разметки. Остальная часть кода в основном такая же, как и в стандартном шаблоне Blade. Поэтому мы по-прежнему используем links()
метод для отображения нумерации страниц и @if
директиву для условного отображения чего-либо.
Теперь мы переходим к классу компонентов. Откройте app/Http/Livewire/LiveTable.php
файл и обновите его, чтобы он содержал следующий код:
<?php namespace App\Http\Livewire; use Livewire\Component; use Livewire\WithPagination; use App\Models\User; class LiveTable extends Component { use WithPagination; public $sortField = 'name'; // default sorting field public $sortAsc = true; // default sort direction public $search = ''; public function sortBy($field) { if ($this->sortField === $field) { $this->sortAsc = !$this->sortAsc; } else { $this->sortAsc = true; } $this->sortField = $field; } public function render() { return view('livewire.live-table', [ 'users' => User::search($this->search) ->orderBy($this->sortField, $this->sortAsc ? 'asc' : 'desc') ->simplePaginate(10), ]); } }
Как упоминалось ранее, мы привязали значение переменной search
к определенному текстовому полю на стороне клиента через метод wire:model
. Таким образом, каждый раз, когда пользователь что-то вводит, search
переменная также обновляется. И когда он обновляется, компонент также перерисовывается. Это связано с тем, что в render()
функции мы зависим от значения переменной search
для получения пользовательских данных. Таким образом, для каждого нажатия клавиши мы фактически извлекаем данные из базы данных, предоставляя пользовательский запрос и выбранную сортировку (мы рассмотрим, как это улучшить, позже в разделе «Оптимизация» ):
User::search($this->search) ->orderBy($this->sortField, $this->sortAsc ? 'asc' : 'desc') ->simplePaginate(10)
sortBy()
метод мы используем для обновления поля для сортировки таблицы пользователей. Каждое поле можно отсортировать по возрастанию или убыванию. По умолчанию нажатие на поле сортировки сортирует его по возрастанию. Повторное нажатие приведет к обратному результату:
public function sortBy($field) { if ($this->sortField === $field) { $this->sortAsc = !$this->sortAsc; // if field is already sorted, use the opposite instead } else { $this->sortAsc = true; // sort selected field by ascending by default } $this->sortField = $field; }
При фильтрации users
таблицы мы используем search()
метод. Но мы еще этого не добавили. Обновите app/Models/User.php
файл, включив в него search()
метод. Это фильтрует таблицу пользователей, чтобы возвращать только пользователей типа user
. Тогда остальные условия будут полями, которые мы хотим использовать для фильтрации поля поиска:
protected $casts = [ // ]; public static function search($query) { return empty($query) ? static::query()->where('user_type', 'user') : static::where('user_type', 'user') ->where(function($q) use ($query) { $q ->where('name', 'LIKE', '%'. $query . '%') ->orWhere('email', 'LIKE', '%' . $query . '%') ->orWhere('address', 'LIKE ', '%' . $query . '%'); }); }
Использование компонента Livewire
Как только это будет сделано, функции поиска и сортировки должны быть готовы к работе. Откройте routes/web.php
файл и замените существующий маршрут следующим:
Route::get('/', function () { return view('index'); });
Затем создайте resources/views/index.blade.php
файл и добавьте следующее. Здесь мы используем созданный нами компонент Live Table. Мы можем отобразить его на странице так же, как и со стандартным компонентом. Единственное отличие состоит в том, что нам нужно добавить префикс к имени компонента, livewire:
а также использовать его @livewireScripts
для рендеринга файла JavaScript Livewire:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>{{ config('app.name') }}</title> <link rel="stylesheet" type="text/css" href="{{ asset('css/app.css') }}"> </head> <body> <div class="container"> <div class="row justify-content-center"> <div class="col-md-9"> <livewire:live-table /> </div> </div> </div> @livewireScripts <script src="{{ asset('js/app.js') }}"></script> </body> </html>
На этом этапе вы можете запустить приложение. Самый простой способ — обслуживать проект с помощью Artisan:
php artisan serve
Затем откройте приложение в браузере по адресу http://127.0.0.1:8000/ .
Если вы настроили локальный домен через Laravel Valet или какой-либо другой инструмент, вы также можете использовать его.
Удаление пользователей
Далее реализуем удаление пользователей. Как и раньше, мы используем wire:click
для прослушивания событий нажатия кнопки удаления. Только на этот раз мы не будем вызывать метод в классе компонента напрямую. Это потому, что это операция удаления. Мы не хотим, чтобы пользователи по ошибке удалили кого-либо, поэтому нам нужно предоставить какое-то подтверждение, прежде чем продолжить удаление. Это идеальный вариант использования Livewire Events . Это позволяет нам отправлять и получать определенные события на сервер и с него. Вы можете использовать его, вызвав $emit()
метод. Его первым аргументом будет имя события, а последующие — это аргументы, которые вы хотите передать прослушивателю этого события. В данном случае у нас есть deleteTriggered
событие, и мы передаем идентификатор и имя пользователя в качестве аргументов прослушивателю.
Откройте resources/views/livewire/live-table.blade.php
файл и обновите код кнопки удаления:
<button class="btn btn-sm btn-danger" wire:click="$emit('deleteTriggered', {{ $user->id }}, '{{ $user->name }}')"> Delete </button>
Затем мы можем прослушивать это событие либо на сервере, либо на стороне клиента. Поскольку все, что мы хотим, — это показать подтверждение при срабатывании этого события, мы прослушиваем его на стороне клиента. Создайте resources/js/users.js
файл и добавьте следующее. Как видите, мы получаем доступ к id
и name
пользователя через аргументы, передаваемые слушателю:
Livewire.on("deleteTriggered", (id, name) => { const proceed = confirm(`Are you sure you want to delete ${name}`); if (proceed) { Livewire.emit("delete", id); } });
Как только пользователь соглашается, мы создаем событие, которое фактически удаляет пользователя. Чтобы прослушивать события на серверной стороне, создайте $listeners
массив, содержащий имена прослушивателей и методы класса, с которыми они сопоставляются. В этом случае имя события и метода совпадают, поэтому мы просто добавляем. Затем delete.
метод delete()
удалит пользователя с соответствующим id
:
// app/Http/Livewire/LiveTable.php protected $listeners = ['delete']; public function sortBy($field) { // } public function delete($id) { User::find($id) ->delete(); }
Если вам нужно какое-то уведомление при удалении пользователя, вы можете отправить событие браузера:
User::find($id) ->delete(); $this->dispatchBrowserEvent('user-deleted', ['user_name' => $user->name]); // add this
Затем на стороне клиента прослушивайте это событие через стандартный API прослушивателя событий браузера . Здесь мы просто показываем оповещение, содержащее имя удаленного пользователя:
// resources/js/users.js window.addEventListener("user-deleted", (event) => { alert(`${event.detail.user_name} was deleted!`); });
Наконец, не забудьте добавить users.js
файл в webpack.mix.js
:
// webpack.mix.js mix.js("resources/js/app.js", "public/js") .sass("resources/sass/app.scss", "public/css") .js("resources/js/users.js", "public/js") // add this .sourceMaps();
На этом этапе удаление пользователей теперь должно работать, если вы попробуете это сделать в своем браузере.
Создание новых пользователей
Перейдем к созданию новых пользователей. Откройте resources/views/livewire/live-table.blade.php
файл и добавьте кнопку создания нового пользователя. Опять же, мы используем wire:click
для запуска события под названием triggerCreate
:
<div> <div class="row mb-4"> <div class="col-md-12"> <div class="float-left mt-5"> <button class="btn btn-success" wire:click="$emit('triggerCreate')">Create New User</button> </div> <div class="float-right mt-5"> <input wire:model="search" class="form-control" type="text" placeholder="Search Users..."> </div> </div> </div> <!-- code for the users table from earlier --> <div class="row"> @if ($users->count()) @endif </div> </div>
Затем в вашем resources/js/users.js
файле прослушайте это событие и откройте модальное окно:
Livewire.on("triggerCreate", () => { $("#user-modal").modal("show"); });
Примечание: Обычно, если вы используете Livewire, вы хотите, чтобы вся интерактивность обрабатывалась Livewire, включая модальные окна. В данном случае мы используем jQuery для открытия модального окна. Это простительно, поскольку это всего лишь одна строка кода. Но если вы хотите использовать Livewire, правильный способ сделать это — использовать Livewire для всего. Вы не можете смешивать и сопоставлять его с jQuery. Это поможет упростить задачу, когда вам позже понадобится добавить интерфейсные тесты.
На самом деле мы еще не создали компонент Livewire, поэтому давайте продолжим и сделаем это:
php artisan make:livewire UserForm
Как и в случае с Live Table, при этом создается класс компонента, а также файл представления:
app/Http/Livewire/UserForm.php
resources/views/livewire/user-form.blade.php
Сначала откройте файл представления и добавьте следующее. Этот код покажется вам знакомым, поскольку по большей части он представляет собой стандартный шаблон Blade для отрисовки формы. Единственное отличие состоит в том, что мы добавили в него некоторые атрибуты Livewire, со всеми из которых вы уже знакомы:
<!-- resources/views/livewire/user-form.blade.php --> <div> <form wire:submit.prevent="save"> <div class="form-group"> <label for="name">Name</label> <input type="text" class="form-control" id="name" name="name" wire:model="name"> @error('name') <span class="text-danger">{{ $message }}</span> @enderror </div> <div class="form-group"> <label for="exampleInputPassword1">Email</label> <input type="email" class="form-control" id="email" name="email" wire:model="email"> @error('email') <span class="text-danger">{{ $message }}</span> @enderror </div> <div class="form-group"> <label for="age">Age</label> <input type="number" class="form-control" id="age" name="age" wire:model="age"> @error('age') <span class="text-danger">{{ $message }}</span> @enderror </div> <div class="form-group"> <label for="address">Address</label> <input type="text" class="form-control" id="address" name="address" wire:model="address"> @error('address') <span class="text-danger">{{ $message }}</span> @enderror </div> <button class="btn btn-primary" type="submit">Save</button> </form> </div>
На данный момент вы уже знаете, что оно wire:submit.prevent="save"
будет запущено при нажатии кнопки сохранения. .prevent
предотвращает действие по умолчанию, то есть фактическую отправку формы. Затем мы используем wire:model
для привязки каждого поля к определенному свойству в классе компонента.
Еще одна особенность этого кода: это стандартный код шаблона Blade для отображения ошибок формы. Вам может быть интересно, что он здесь делает, когда мы находимся в компоненте Livewire. Ответ в том, что Livewire также может использовать этот код, чтобы показывать нам ошибки формы. Таким образом, если пользователь не указал значение в определенном поле при отправке формы, сервер выдаст сигнал и вызовет появление следующих ошибок:
@error('name') <span class="text-danger">{{ $message }}</span> @enderror
Затем откройте resources/views/index.blade.php
файл и добавьте разметку для модального окна:
<div class="container"> <div class="row justify-content-center"> <div class="col-md-9"> <livewire:live-table /> </div> </div> </div> <!-- add this --> <div class="modal" tabindex="-1" role="dialog" id="user-modal"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title">User</h5> <button type="button" class="close" data-dismiss="modal" aria-label="Close"> <span aria-hidden="true">×</span> </button> </div> <div class="modal-body"> <livewire:user-form> </div> </div> </div> </div>
Теперь, когда у нас есть код для клиентской части, давайте взглянем на внутреннюю часть. Откройте app/Http/Livewire/UserForm.php
и добавьте следующее:
<?php namespace App\Http\Livewire; use Livewire\Component; use App\Models\User; // add this class UserForm extends Component { // add these public $name; public $email; public $age; public $address; public function render() { return view('livewire.user-form'); } // add this public function save() { $validated = $this->validate([ 'name' => 'required|min:10', 'email' => 'required|email|min:10', 'age' => 'required|integer', 'address' => 'required|min:10', ]); User::create(array_merge($validated, [ 'user_type' => 'user', 'password' => bcrypt($this->email) ])); $this->resetForm(); $this->dispatchBrowserEvent('user-saved', ['action' => 'created', 'user_name' => $this->name]); $this->emitTo('live-table', 'triggerRefresh'); } public function resetForm() { $this->user_id = null; $this->name = null; $this->email = null; $this->age = null; $this->address = null; } }
Это много, но большая часть из них уже должна быть вам понятна, поскольку мы уже использовали их ранее. Поэтому я не буду рассматривать их подробно. Вместо этого давайте просто рассмотрим причины, по которым я закодировал это определенным образом.
Во-первых, это то, как я проверил форму. Здесь нет ничего нового. Это всего лишь стандартный код проверки формы Laravel. Но почему я использовал это вместо класса Request? Это потому, что способ работы Livewire несовместим с классом Request. По сути, класс Laravel Request работает только для стандартных HTTP-запросов. Это означает, что он перенаправляет пользователя на предыдущую страницу, если возникает ошибка проверки. В Livewire этого не может быть, так как все делается через AJAX:
$validated = $this->validate([ 'name' => 'required|min:10', 'email' => 'required|email|min:10', 'age' => 'required|integer', 'address' => 'required|min:10', ]);
Далее идет этот фрагмент кода. Здесь мы используем emitTo()
вместо emit()
. Это дает возможность различным компонентам взаимодействовать друг с другом посредством событий. Он принимает имя компонента в качестве первого аргумента и имя события в качестве второго:
$this->dispatchBrowserEvent('user-saved', ['action' => 'created', 'user_name' => $this->name]); $this->emitTo('live-table', 'triggerRefresh');
Почему мы используем два отдельных события (одно событие браузера и одно событие Livewire), хотя мы можем использовать только одно? Что ж, это правда, что мы можем использовать только одно событие. Проблема в том, что нам также необходимо обновить таблицу данных после создания пользователя. В настоящее время я не знаю, как инициировать перезагрузку определенного компонента со стороны клиента, поэтому я использовал два отдельных события — одно для скрытия модального окна и отображения предупреждения, а другое — для обновления таблицы данных.
Теперь, когда вы знаете причину кода, давайте приступим к обработчикам этих событий. Добавьте в файл следующее resources/js/users.js
:
window.addEventListener("user-saved", (event) => { $("#user-modal").modal("hide"); alert(`User ${event.detail.user_name} was ${event.detail.action}!`); });
Затем в класс компонента LiveTable добавьте прослушиватель для triggerRefresh
. Это немного отличается от delete
прослушивателя, поскольку мы указываем на $refresh
функцию, которую нам на самом деле не нужно объявлять как метод класса. Это потому, что это встроенный метод для всех классов компонентов Livewire, который позволяет нам перезагрузить весь компонент:
// app/Http/Livewire/LiveTable.php protected $listeners = ['delete', 'triggerRefresh' => '$refresh'];
На этом этапе пользователей теперь можно создавать, когда вы пробуете это в своем браузере.
Обновление существующих пользователей
Последняя часть функциональности, которую мы реализуем, — это обновление пользователей. Обновите кнопку редактирования в resources/views/livewire/live-table.blade.php
файле следующим образом. Поскольку мы находимся в компоненте LiveTable, а функции редактирования должны быть в компоненте UserForm, нам нужно использовать команду $emitTo()
для отправки triggerEdit
события в компонент UserForm. В отличие от предыдущего случая, когда мы предоставляли только отдельные значения, здесь мы предоставляем весь user
объект:
<td> <button class="btn btn-sm btn-dark" wire:click="$emitTo('user-form', 'triggerEdit', {{ $user }})">Edit</button> </td>
Чтобы прослушать triggerEdit
событие, откройте app/Http/Livewire/UserForm.php
файл и добавьте следующее. Отдельный user
объект передается этой функции, и мы используем его для заполнения полей формы значениями. Обратите внимание, что вместо объекта вы получаете доступ к отдельным полям так же, как и к массиву. Как только это будет сделано, создайте событие dataFetched
:
protected $listeners = ['triggerEdit']; public function resetForm() { // } public function triggerEdit($user) { $this->user_id = $user['id']; $this->name = $user['name']; $this->email = $user['email']; $this->age = $user['age']; $this->address = $user['address']; $this->emit('dataFetched', $user); }
Прослушивайте dataFetched
событие на стороне клиента. Поскольку на этом этапе мы уже заполнили отдельные поля значениями, мы можем просто открыть модальное окно:
// resources/js/users.js Livewire.on("dataFetched", (user) => { $("#user-modal").modal("show"); });
Наконец, обновите save()
метод в классе компонента UserForm, чтобы он также обрабатывал обновления. Для этого проверьте значение поля user_id
. Если у него есть значение, это означает, что пользователь в настоящее время обновляется. В противном случае мы создаем его:
// app/Http/Livewire/UserForm.php public function save() { $validated = $this->validate([ 'name' => 'required|min:10', 'email' => 'required|email|min:10', 'age' => 'required|integer', 'address' => 'required|min:10', ]); if ($this->user_id) { User::find($this->user_id) ->update([ 'name' => $this->name, 'email' => $this->email, 'age' => $this->age, 'address' => $this->address, ]); $this->dispatchBrowserEvent('user-saved', ['action' => 'updated', 'user_name' => $this->name]); } else { User::create(array_merge($validated, [ 'user_type' => 'user', 'password' => bcrypt($this->email) ])); $this->dispatchBrowserEvent('user-saved', ['action' => 'created', 'user_name' => $this->name]); } $this->resetForm(); $this->emitTo('live-table', 'triggerRefresh'); }
На этом этапе данные пользователя теперь можно редактировать, когда вы попробуете это сделать в своем браузере.
Оптимизации
В этом разделе мы рассмотрим некоторые варианты оптимизации, которые вы можете выполнить, чтобы ваше приложение не использовало больше ресурсов сервера, чем ему необходимо.
Поле поиска
Как вы, возможно, уже заметили, ввод текста в поле поиска почти сразу же запускает запрос AJAX, который извлекает обновленные данные с сервера. При этом каждый раз отправляется запрос в базу данных, поэтому это не совсем идеально. По умолчанию Livewire применяет к входам дребезг в 150 мс. Мы хотим увеличить эту задержку, чтобы Livewire не отправлял запрос на сервер, пока пользователь все еще печатает. Приведенный ниже код добавляет дребезг на 800 мс, поэтому возникает заметная задержка. Поиграйте с этим значением, чтобы убедиться в идеальном балансе:
<!-- resources/views/livewire/live-table.blade.php --> <input wire:model.debounce.800ms="search">
Поля формы
Еще одна быстрая оптимизация, которую мы могли бы сделать, — это обновление полей формы пользователя. Как и в случае с полем поиска, запрос отправляется на сервер почти мгновенно, когда вы что-то вводите. На этот раз вместо добавления устранения дребезга мы используем ленивое обновление. Это отправит запрос на сервер только тогда, когда пользователь выведет фокус из текстового поля:
<!-- resources/views/livewire/user-form.blade.php --> <input wire:model.lazy="name">
Заключение
В этом уроке мы изучили основы использования Livewire, чтобы сделать ваши приложения Laravel более динамичными без написания целой кучи JavaScript для получения и отправки данных на сервер.
В частности, мы создали простое CRUD-приложение, которое использует Livewire, чтобы устранить необходимость во внешних пакетах, таких как Datatables, для реализации поиска и сортировки по таблицам. Мы также устранили необходимость полного обновления страницы для отправки форм. Наконец, мы использовали как события Livewire, так и события браузера, чтобы интерфейсная и серверная части могли взаимодействовать друг с другом без необходимости писать код AJAX.