フォーム
ほとんどのウェブアプリケーションでフォームはバックボーンであるため、Livewireはフォームの構築に役立つ、多くのユーティリティを提供しています。シンプルな入力要素の処理から、リアルタイム検証やファイルアップロードのような複雑なものまで、Livewireには、あなたの人生を楽にし、ユーザーを喜ばせるためのシンプルで、十分に文書化されたツールがあります。Because forms are the backbone of most web applications, Livewire provides loads of helpful utilities for building them. From handling simple input elements to complex things like real-time validation or file uploading, Livewire has simple, well-documented tools to make your life easier and delight your users.
それでは、詳しく見ていきましょう。Let's dive in.
フォームの送信Submitting a form
まず、CreatePost
コンポーネントの非常にシンプルなフォームを見てみましょう。このフォームには、2つのシンプルなテキスト入力と送信ボタン、そしてフォームの状態と送信を管理するためのバックエンドのコードがあります。Let's start by looking at a very simple form in a CreatePost
component. This form will have two simple text inputs and a submit button, as well as some code on the backend to manage the form's state and submission:
<?php
namespace App\Livewire;
use Livewire\Component;
use App\Models\Post;
class CreatePost extends Component
{
public $title = '';
public $content = '';
public function save()
{
Post::create(
$this->only(['title', 'content'])
);
session()->flash('status', 'Post successfully updated.');
return $this->redirect('/posts');
}
public function render()
{
return view('livewire.create-post');
}
}
<form wire:submit="save">
<input type="text" wire:model="title">
<input type="text" wire:model="content">
<button type="submit">Save</button>
</form>
ご覧のとおり、上記のフォームで wire:model
を使用して、パブリックな$title
と$content
プロパティを「結合(bind)」しています。これは、最も一般的に使用される、Livewireの強力な機能の1つです。As you can see, we are "binding" the public $title
and $content
properties in the form above using wire:model
. This is one of the most commonly used and powerful features of Livewire.
$title
と$content
の結合に加え、"Save"ボタンがクリックされたときに、wire:submit
を使用してsubmit
イベントをキャプチャし、save()
アクションを呼び出しています。このアクションは、フォーム入力をデータベースへ永続化します。In addition to binding $title
and $content
, we are using wire:submit
to capture the submit
event when the "Save" button is clicked and invoking the save()
action. This action will persist the form input to the database.
データベースに新しいポストを作成した後、ユーザーを ShowPosts
コンポーネントページにリダイレクトし、新しいポストが作成されたことを示す「一時(flash)」メッセージを表示します。After the new post is created in the database, we redirect the user to the ShowPosts
component page and show them a "flash" message that the new post was created.
バリデーションの追加Adding validation
不完全、または危険なユーザー入力を保存しないように、ほとんどのフォームは何らかの入力バリデーションを必要とします。To avoid storing incomplete or dangerous user input, most forms need some sort of input validation.
Livewireでは、バリデーションしたいプロパティの上に、#[Validate]
属性を追加するだけで、フォームのバリデーションを簡単に行えます。Livewire makes validating your forms as simple as adding #[Validate]
attributes above the properties you want to be validated.
プロパティへ#[Validate]
属性を添付すると、プロパティの値がサーバ側で更新されるたびに、バリデーションルールを適用します。Once a property has a #[Validate]
attribute attached to it, the validation rule will be applied to the property's value any time it's updated server-side.
CreatePost
コンポーネントの$title
と$content
プロパティへ、いくつかの基本的なバリデーションルールを追加してみましょう。Let's add some basic validation rules to the $title
and $content
properties in our CreatePost
component:
<?php
namespace App\Livewire;
use Livewire\Attributes\Validate; // [tl! highlight]
use Livewire\Component;
use App\Models\Post;
class CreatePost extends Component
{
#[Validate('required')] // [tl! highlight]
public $title = '';
#[Validate('required')] // [tl! highlight]
public $content = '';
public function save()
{
$this->validate(); // [tl! highlight]
Post::create(
$this->only(['title', 'content'])
);
return $this->redirect('/posts');
}
public function render()
{
return view('livewire.create-post');
}
}
再度、Bladeテンプレートを修正して、ページへバリデーションエラーを表示しましょう。We'll also modify our Blade template to show any validation errors on the page.
<form wire:submit="save">
<input type="text" wire:model="title">
<div>
@error('title') <span class="error">{{ $message }}</span> @enderror <!-- [tl! highlight] -->
</div>
<input type="text" wire:model="content">
<div>
@error('content') <span class="error">{{ $message }}</span> @enderror <!-- [tl! highlight] -->
</div>
<button type="submit">Save</button>
</form>
これで、ユーザーがフィールドに入力せずにフォームを送信しようとすると、ポストを保存する前にどのフィールドが必要かを示すバリデーションメッセージが表示されます。Now, if the user tries to submit the form without filling in any of the fields, they will see validation messages telling them which fields are required before saving the post.
Livewireには、他にも多くのバリデーション機能があります。詳細については、バリデーションに関する専用ドキュメントページをご覧ください。Livewire has a lot more validation features to offer. For more information, visit our dedicated documentation page on Validation[/docs/validation].
フォームオブジェクトの抽出Extracting a form object
大規模なフォームを扱っていて、そのプロパティ、バリデーションロジックなどをすべて別のクラスに抽出したい場合、Livewireはフォームオブジェクトを提供します。If you are working with a large form and prefer to extract all of its properties, validation logic, etc., into a separate class, Livewire offers form objects.
フォームオブジェクトを使用すると、コンポーネント間でフォームロジックを再利用でき、フォーム関連のコードをすべて別のクラスにグループ化することで、コンポーネントクラスをよりクリーンに保てます。Form objects allow you to re-use form logic across components and provide a nice way to keep your component class cleaner by grouping all form-related code into a separate class.
フォームクラスを手動で作成することも、便利なartisanコマンドを使用することもできます。You can either create a form class by hand or use the convenient artisan command:
php artisan livewire:form PostForm
上記のコマンドは、app/Livewire/Forms/PostForm.php
ファイルを作成します。The above command will create a file called app/Livewire/Forms/PostForm.php
.
PostForm
クラスを使用するように、CreatePost
コンポーネントを書き換えてみましょう。Let's rewrite the CreatePost
component to use a PostForm
class:
<?php
namespace App\Livewire\Forms;
use Livewire\Attributes\Validate;
use Livewire\Form;
class PostForm extends Form
{
#[Validate('required|min:5')]
public $title = '';
#[Validate('required|min:5')]
public $content = '';
}
<?php
namespace App\Livewire;
use App\Livewire\Forms\PostForm;
use Livewire\Component;
use App\Models\Post;
class CreatePost extends Component
{
public PostForm $form; // [tl! highlight]
public function save()
{
$this->validate();
Post::create(
$this->form->only(['title', 'content']) // [tl! highlight]
);
return $this->redirect('/posts');
}
public function render()
{
return view('livewire.create-post');
}
}
<form wire:submit="save">
<input type="text" wire:model="form.title">
<div>
@error('form.title') <span class="error">{{ $message }}</span> @enderror
</div>
<input type="text" wire:model="form.content">
<div>
@error('form.content') <span class="error">{{ $message }}</span> @enderror
</div>
<button type="submit">Save</button>
</form>
必要に応じて、ポスト作成ロジックをフォームオブジェクトに抽出することもできます。If you'd like, you can also extract the post creation logic into the form object like so:
<?php
namespace App\Livewire\Forms;
use Livewire\Attributes\Validate;
use App\Models\Post;
use Livewire\Form;
class PostForm extends Form
{
#[Validate('required|min:5')]
public $title = '';
#[Validate('required|min:5')]
public $content = '';
public function store() // [tl! highlight:5]
{
$this->validate();
Post::create($this->only(['title', 'content']));
}
}
これで、コンポーネントから$this->form->store()
を呼び出せます。Now you can call $this->form->store()
from the component:
class CreatePost extends Component
{
public PostForm $form;
public function save()
{
$this->form->store(); // [tl! highlight]
return $this->redirect('/posts');
}
// ...
}
このフォームオブジェクトを、作成フォームと更新フォームの両方で使用したい場合は、両方のユースケースを処理するように簡単に適合させることができます。If you want to use this form object for both a create and update form, you can easily adapt it to handle both use cases.
UpdatePost
コンポーネントでこの同じフォームオブジェクトを使用し、初期データで入力する場合の例を次に示します。Here's what it would look like to use this same form object for an UpdatePost
component and fill it with initial data:
<?php
namespace App\Livewire;
use App\Livewire\Forms\PostForm;
use Livewire\Component;
use App\Models\Post;
class UpdatePost extends Component
{
public PostForm $form;
public function mount(Post $post)
{
$this->form->setPost($post);
}
public function save()
{
$this->form->update();
return $this->redirect('/posts');
}
public function render()
{
return view('livewire.create-post');
}
}
<?php
namespace App\Livewire\Forms;
use Livewire\Attributes\Validate;
use Livewire\Form;
use App\Models\Post;
class PostForm extends Form
{
public ?Post $post;
#[Validate('required|min:5')]
public $title = '';
#[Validate('required|min:5')]
public $content = '';
public function setPost(Post $post)
{
$this->post = $post;
$this->title = $post->title;
$this->content = $post->content;
}
public function store()
{
$this->validate();
Post::create($this->only(['title', 'content']));
}
public function update()
{
$this->validate();
$this->post->update(
$this->only(['title', 'content'])
);
}
}
ご覧のとおり、setPost()
メソッドをPostForm
オブジェクトに追加しました。これは、既存のデータでフォームを任意に埋めるだけでなく、後で使用するためにフォームオブジェクトにポストを保存できるようにするためです。また、既存のポストを更新するためのupdate()
メソッドも追加しました。As you can see, we've added a setPost()
method to the PostForm
object to optionally allow for filling the form with existing data as well as storing the post on the form object for later use. We've also added an update()
method for updating the existing post.
FormオブジェクトはLivewireを使用するときに、必須ではありませんが、コンポーネントから反復的な軽々コードを排除するための優れた抽象化を提供します。Form objects are not required when working with Livewire, but they do offer a nice abstraction for keeping your components free of repetitive boilerplate.
フォームフィールドのリセットResetting form fields
フォームオブジェクトを使用している場合、送信後にフォームをリセットしたい場合があります。これは、reset()
メソッドを呼び出すことで実行できます。If you are using a form object, you may want to reset the form after it has been submitted. This can be done by calling the reset()
method:
<?php
namespace App\Livewire\Forms;
use Livewire\Attributes\Validate;
use App\Models\Post;
use Livewire\Form;
class PostForm extends Form
{
#[Validate('required|min:5')]
public $title = '';
#[Validate('required|min:5')]
public $content = '';
// ...
public function store()
{
$this->validate();
Post::create($this->only(['title', 'content']));
$this->reset(); // [tl! highlight]
}
}
reset()
メソッドにプロパティ名を渡すことで、特定のプロパティをリセットすることもできます。You can also reset specific properties by passing the property names into the reset()
method:
$this->reset('title');
// または、複数を一度で...
$this->reset(['title', 'content']);
フォームフィールドの取得Pulling form fields
あるいは、pull()
メソッドを使用して、フォームのプロパティを取得し、同時にリセットすることができます。Alternatively, you can use the pull()
method to both retrieve a form's properties and reset them in one operation.
<?php
namespace App\Livewire\Forms;
use Livewire\Attributes\Validate;
use App\Models\Post;
use Livewire\Form;
class PostForm extends Form
{
#[Validate('required|min:5')]
public $title = '';
#[Validate('required|min:5')]
public $content = '';
// ...
public function store()
{
$this->validate();
Post::create(
$this->pull() // [tl! highlight]
);
}
}
pull()
メソッドにプロパティ名を渡し、特定のプロパティを取得することもできます。You can also pull specific properties by passing the property names into the pull()
method:
// リセットする前に値を返す
$this->pull('title');
// リセットする前にプロパティのキーと値の配列を返す
$this->pull(['title', 'content']);
Ruleオブジェクトの使用Using Rule objects
LaravelのRule
オブジェクトが必要な、より高度なバリデーションのシナリオがある場合は、代わりにrules()
メソッドを定義して、次のようにバリデーションルールを宣言できます。If you have more sophisticated validation scenarios where Laravel's Rule
objects are necessary, you can alternatively define a rules()
method to declare your validation rules like so:
<?php
namespace App\Livewire\Forms;
use Illuminate\Validation\Rule;
use App\Models\Post;
use Livewire\Form;
class PostForm extends Form
{
public ?Post $post;
public $title = '';
public $content = '';
protected function rules()
{
return [
'title' => [
'required',
Rule::unique('posts')->ignore($this->post), // [tl! highlight]
],
'content' => 'required|min:5',
];
}
// ...
public function update()
{
$this->validate();
$this->post->update($this->only(['title', 'content']));
$this->reset();
}
}
#[Validate]
の代わりにrules()
メソッドを使用する場合、Livewireは、プロパティが更新されるたびにではなく、$this->validate()
を呼び出すときにのみバリデーションルールを実行します。When using a rules()
method instead of #[Validate]
, Livewire will only run the validation rules when you call $this->validate()
, rather than every time a property is updated.
リアルタイムバリデーション、またはLivewireにリクエストごとに特定のフィールドを検証させたいその他のシナリオを使用している場合は、次のようにルールを指定せずに#[Validate]
を使用できます。If you are using real-time validation or any other scenario where you'd like Livewire to validate specific fields after every request, you can use #[Validate]
without any provided rules like so:
<?php
namespace App\Livewire\Forms;
use Livewire\Attributes\Validate;
use Illuminate\Validation\Rule;
use App\Models\Post;
use Livewire\Form;
class PostForm extends Form
{
public ?Post $post;
#[Validate] // [tl! highlight]
public $title = '';
public $content = '';
protected function rules()
{
return [
'title' => [
'required',
Rule::unique('posts')->ignore($this->post),
],
'content' => 'required|min:5',
];
}
// ...
public function update()
{
$this->validate();
$this->post->update($this->only(['title', 'content']));
$this->reset();
}
}
これで、フォームが送信される前に$title
プロパティが更新された場合(wire:model.blur
を使用している場合など)、$title
のバリデーションが実行されます。Now if the $title
property is updated before the form is submitted—like when using wire:model.blur
[/docs/wire-model#updating-on-blur-event]—the validation for $title
will be run.
ローディングインジケータの表示Showing a loading indicator
デフォルトでLivewireは、フォームの送信中にサブミットボタンを自動的に無効にし、入力をreadonly
としてマークし、最初の送信が処理されている間、ユーザーがフォームを再度送信するのを防ぎます。By default, Livewire will automatically disable submit buttons and mark inputs as readonly
while a form is being submitted, preventing the user from submitting the form again while the first submission is being handled.
ただし、アプリケーションのUIに追加の工夫がないと、ユーザーがこの「ローディング」状態を検出するのは難しくなります。However, it can be difficult for users to detect this "loading" state without extra affordances in your application's UI.
wire:loading
を介して「保存」ボタンに小さなローディングスピナーを追加して、フォームが送信されていることをユーザーが理解できるようにする例を次に示します。Here's an example of adding a small loading spinner to the "Save" button via wire:loading
so that a user understands that the form is being submitted:
<button type="submit">
Save
<div wire:loading>
<svg>...</svg> <!-- SVGローディングスピナー -->
</div>
</button>
これで、ユーザーが「保存」を押すと、小さなインラインスピナーが表示されます。Now, when a user presses "Save", a small, inline spinner will show up.
Livewireのwire:loading
機能には、さらに多くの機能があります。詳細は、ローディングのドキュメントを参照してください。Livewire's wire:loading
feature has a lot more to offer. Visit the Loading documentation to learn more.[/docs/wire-loading]
ライブ更新フィールドLive-updating fields
デフォルトでは、Livewireはフォームの送信時(または他のアクションが呼び出された場合)にのみネットワークリクエストを送信し、フォームの入力中は送信しません。By default, Livewire only sends a network request when the form is submitted (or any other action[/docs/actions] is called), not while the form is being filled out.
たとえば、CreatePost
コンポーネントを見てください。ユーザーが入力するときに、"title"入力フィールドがバックエンドの$title
プロパティと同期されていることを確認したい場合は、次のようにwire:model
に.live
モディファイアを追加できます。Take the CreatePost
component, for example. If you want to make sure the "title" input field is synchronized with the $title
property on the backend as the user types, you may add the .live
modifier to wire:model
like so:
<input type="text" wire:model.live="title">
これで、ユーザーがこのフィールドに入力すると、$title
を更新するためにネットワークリクエストがサーバに送信されます。これは、ユーザーが検索ボックスに入力するときにデータセットがフィルタリングされるリアルタイム検索などに役立ちます。Now, as a user types into this field, network requests will be sent to the server to update $title
. This is useful for things like a real-time search, where a dataset is filtered as a user types into a search box.
_blur_時にのみフィールドを更新するOnly updating fields on blur
ほとんどの場合、リアルタイムのフォームフィールドの更新にはwire:model.live
で問題ありません。ただし、テキスト入力ではネットワークリソースを過剰に消費する可能性があります。For most cases, wire:model.live
is fine for real-time form field updating; however, it can be overly network resource-intensive on text inputs.
ユーザーがタイプしたときにネットワークリクエストを送信する代わりに、ユーザーがテキスト入力から「タブ」で移動したとき(入力を「ぼかす(blur)とも呼ばれます)のみリクエストを送信する場合は、代わりに.blur
モディファイアを使用しますIf instead of sending network requests as a user types, you want to instead only send the request when a user "tabs" out of the text input (also referred to as "blurring" an input), you can use the .blur
modifier instead:
<input type="text" wire:model.blur="title" >
これで、サーバ上のコンポーネントクラスは、ユーザーがタブを押すか、テキスト入力からクリックで離れるまで更新されません。Now the component class on the server won't be updated until the user presses tab or clicks away from the text input.
リアルタイムバリデーションReal-time validation
ユーザーがフォームを埋めているときにバリデーションエラーを表示したい場合があるでしょう。この方法は、フォーム全体が入力されるまで待つ必要なく、何かが間違っていることを早期に警告できます。Sometimes, you may want to show validation errors as the user fills out the form. This way, they are alerted early that something is wrong instead of having to wait until the entire form is filled out.
Livewireは、これらを自動的に処理します。wire:model
で.live
または.blur
を使用することにより、Livewireはユーザーがフォームに入力するときにネットワークリクエストを送信します。これらの各ネットワークリクエストは、各プロパティを更新する前に、適切なバリデーションルールを実行します。バリデーションが失敗した場合、プロパティはサーバ上で更新されず、バリデーションメッセージがユーザーに表示されます。Livewire handles this sort of thing automatically. By using .live
or .blur
on wire:model
, Livewire will send network requests as the user fills out the form. Each of those network requests will run the appropriate validation rules before updating each property. If validation fails, the property won't be updated on the server and a validation message will be shown to the user:
<input type="text" wire:model.blur="title">
<div>
@error('title') <span class="error">{{ $message }}</span> @enderror
</div>
#[Validate('required|min:5')]
public $title = '';
これで、ユーザーが"title"入力欄に3文字だけを入力し、フォームの次の入力をクリックした場合、そのフィールドには最低5文字以上が必要であることを示すバリデーションメッセージを表示します。Now, if the user only types three characters into the "title" input, then clicks on the next input in the form, a validation message will be shown to them indicating there is a five character minimum for that field.
詳細は、バリデーションのドキュメントページを確認してください。For more information, check out the validation documentation page[/docs/validation].
リアルタイムフォームの保存Real-time form saving
ユーザーが「送信」をクリックするまで待たずに、フォームを埋めているときに自動保存する場合は、Livewireのupdated()
フックを使用してこれを行えます。If you want to automatically save a form as the user fills it out rather than wait until the user clicks "submit", you can do so using Livewire's updated()
hook:
<?php
namespace App\Livewire;
use Livewire\Attributes\Validate;
use Livewire\Component;
use App\Models\Post;
class UpdatePost extends Component
{
public Post $post;
#[Validate('required')]
public $title = '';
#[Validate('required')]
public $content = '';
public function mount(Post $post)
{
$this->post = $post;
$this->title = $post->title;
$this->content = $post->content;
}
public function updated($name, $value) // [tl! highlight:5]
{
$this->post->update([
$name => $value,
]);
}
public function render()
{
return view('livewire.create-post');
}
}
<form wire:submit>
<input type="text" wire:model.blur="title">
<div>
@error('title') <span class="error">{{ $message }}</span> @enderror
</div>
<input type="text" wire:model.blur="content">
<div>
@error('content') <span class="error">{{ $message }}</span> @enderror
</div>
</form>
上記の例で、ユーザーがフィールドを完了すると(クリックまたは次のフィールドへタブで移動)、ネットワークリクエストを送信し、コンポーネント上のそのプロパティを更新します。クラス上でプロパティを更新すると、すぐにその特定のプロパティ名とその新しい値に対して、updated()
フックを呼び出します。In the above example, when a user completes a field (by clicking or tabbing to the next field), a network request is sent to update that property on the component. Immediately after the property is updated on the class, the updated()
hook is called for that specific property name and its new value.
このフックを使用して、データベース内のその特定のフィールドのみ更新できます。We can use this hook to update only that specific field in the database.
さらに、そうしたプロパティに#[Validate]
属性がアタッチされているため、プロパティが更新されてupdated()
フックが呼び出される前に、バリデーションルールを実行します。Additionally, because we have the #[Validate]
attributes attached to those properties, the validation rules will be run before the property is updated and the updated()
hook is called.
"updated"ライフサイクルフックおよびその他のフックの詳細については、ライフサイクルフックのドキュメントをご覧ください。To learn more about the "updated" lifecycle hook and other hooks, visit the lifecycle hooks documentation[/docs/lifecycle-hooks].
ダーティインジケーターの表示Showing dirty indicators
上記で説明したリアルタイム保存のシナリオでは、フィールドがまだデータベースへ永続化されていないことをユーザーへ示すと役立つ場合があります。In the real-time saving scenario discussed above, it may be helpful to indicate to users when a field hasn't been persisted to the database yet.
たとえば、ユーザーがUpdatePost
ページにアクセスし、テキスト入力でポストのタイトルを変更し始めた場合、特にフォームの下部に「保存」ボタンがない場合は、タイトルが実際にデータベースで更新されているタイミングが不明確になる可能性があります。For example, if a user visits an UpdatePost
page and starts modifying the title of the post in a text input, it may be unclear to them when the title is actually being updated in the database, especially if there is no "Save" button at the bottom of the form.
Livewireは、入力値がサーバ側のコンポーネントと異なる場合に、要素を切り替えたり、クラスを変更したりできるwire:dirty
ディレクティブを提供しています。Livewire provides the wire:dirty
directive to allow you to toggle elements or modify classes when an input's value diverges from the server-side component:
<input type="text" wire:model.blur="title" wire:dirty.class="border-yellow">
上記の例では、ユーザーが入力フィールドに入力すると、フィールドの周りに黄色の境界線が表示されます。ユーザーがタブで移動すると、ネットワークリクエストが送信され、境界線が消えます。これは、入力が永続化され、「ダーティ(dirty)」ではなくなったことを示します。In the above example, when a user types into the input field, a yellow border will appear around the field. When the user tabs away, the network request is sent and the border will disappear; signaling to them that the input has been persisted and is no longer "dirty".
要素全体の表示を切り替えたいときは、wire:dirty
をwire:target
と組み合わせて使用することで実現できます。wire:target
は、「ダーティ」状態を監視するデータの部分を指定するために使用します。この場合、"title"フィールドです。If you want to toggle an entire element's visibility, you can do so by using wire:dirty
in conjunction with wire:target
. wire:target
is used to specify which piece of data you want to watch for "dirtiness". In this case, the "title" field:
<input type="text" wire:model="title">
<div wire:dirty wire:target="title">未保存…</div>
入力のデバウンスDebouncing input
テキスト入力で.live
を使用する場合に、ネットワークリクエストを送信する頻度をより細かく制御したい場合があります。デフォルトでは、入力に"250ms"のデバウンスを適用します。ただし、.debounce
修飾子を使用して、これをカスタマイズできます。When using .live
on a text input, you may want more fine-grained control over how often a network request is sent. By default, a debounce of "250ms" is applied to the input; however, you can customize this using the .debounce
modifier:
<input type="text" wire:model.live.debounce.150ms="title" >
.debounce.150ms
がフィールドに追加されたため、このフィールドの入力更新を処理する際に、より短い"150ms"のデバウンスを使用します。言い換えれば、ユーザーが入力すると、ユーザーが少なくとも150ミリ秒間入力を停止した場合にのみ、ネットワークリクエストを送信します。Now that .debounce.150ms
has been added to the field, a shorter debounce of "150ms" will be used when handling input updates for this field. In other words, as a user types, a network request will only be sent if the user stops typing for at least 150 milliseconds.
入力のスロットリングThrottling input
前述のように、フィールドに入力デバウンスを適用すると、ユーザーが一定時間入力を停止するまでネットワークリクエストを送信しません。これは、ユーザーが長いメッセージをタイプし続けると、ユーザーが完了するまでネットワークリクエストを送信しないことを意味します。As stated previously, when an input debounce is applied to a field, a network request will not be sent until the user has stopped typing for a certain amount of time. This means if the user continues typing a long message, a network request won't be sent until the user is finished.
場合により、これは望ましい動作ではなく、ユーザーが終了または休憩したときではなく、ユーザーがタイプ中にリクエストを送信したい場合があります。Sometimes this isn't the desired behavior, and you would rather send a request as the user types, not when they've finished or taken a break.
このような場合は、代わりに.throttle
を使用して、ネットワークリクエストを送信する時間間隔を指定できます。In these cases, you can instead use .throttle
to signify a time interval to send network requests:
<input type="text" wire:model.live.throttle.150ms="title" >
上記の例では、ユーザーが"title"フィールドへ継続的に入力していると、ユーザーが完了するまで150ミリ秒ごとにネットワークリクエストを送信します。In the above example, as a user is typing continuously in the "title" field, a network request will be sent every 150 milliseconds until the user is finished.
入力フィールドを Blade コンポーネントに抽出するExtracting input fields to Blade components
ここまで議論してきたCreatePost
の例のような小さなコンポーネントであっても、バリデーションメッセージやラベルのような、多くのフォームフィールドの定型コードを複製することになります。Even in a small component such as the CreatePost
example we've been discussing, we end up duplicating lots of form field boilerplate like validation messages and labels.
このような反復的なUI要素をアプリケーション全体で共有する専用のBladeコンポーネントへ抽出すると便利でしょう。It can be helpful to extract repetitive UI elements such as these into dedicated Blade components[https://laravel.com/docs/blade#components] to be shared across your application.
たとえば、以下はCreatePost
コンポーネントの、元のBladeテンプレートです。以下の2テキスト入力を専用のBladeコンポーネントへ抽出します。For example, below is the original Blade template from the CreatePost
component. We will be extracting the following two text inputs into dedicated Blade components:
<form wire:submit="save">
<input type="text" wire:model="title"> <!-- [tl! highlight:3] -->
<div>
@error('title') <span class="error">{{ $message }}</span> @enderror
</div>
<input type="text" wire:model="content"> <!-- [tl! highlight:3] -->
<div>
@error('content') <span class="error">{{ $message }}</span> @enderror
</div>
<button type="submit">Save</button>
</form>
<x-input-text>
という名前の、再利用可能なBladeコンポーネントを抽出した後、テンプレートは次のようになります。Here's what the template will look like after extracting a re-usable Blade component called <x-input-text>
:
<form wire:submit="save">
<x-input-text name="title" wire:model="title" /> <!-- [tl! highlight] -->
<x-input-text name="content" wire:model="content" /> <!-- [tl! highlight] -->
<button type="submit">Save</button>
</form>
次に、x-input-text
コンポーネントのソースを以下に示します。Next, here's the source for the x-input-text
component:
<!-- resources/views/components/input-text.blade.php -->
@props(['name'])
<input type="text" name="{{ $name }}" {{ $attributes }}>
<div>
@error($name) <span class="error">{{ $message }}</span> @enderror
</div>
ご覧のとおり、反復的なHTMLを取り出し、専用のBladeコンポーネント内に配置しました。As you can see, we took the repetitive HTML and placed it inside a dedicated Blade component.
ほとんどの場合、Bladeコンポーネントには、元のコンポーネントから抽出したHTMLのみを含めます。ただし、以下の2つを追加しました。For the most part, the Blade component contains only the extracted HTML from the original component. However, we have added two things:
@props
ディレクティブThe@props
directive- 入力に対する
{{ $attributes }}
ステートメントThe{{ $attributes }}
statement on the input
これらの追加について説明しましょう。Let's discuss each of these additions:
@props(['name'])
を使用してname
を「プロパティ」として指定することにより、Blade に次のように指示しています。このコンポーネントに"name"という属性が設定されている場合は、その値を取得して、このコンポーネント内で$name
として利用できるようにします。By specifying name
as a "prop" using @props(['name'])
we are telling Blade: if an attribute called "name" is set on this component, take its value and make it available inside this component as $name
.
明示的な目的を持たない他の属性には、{{ $attributes }}
ステートメントを使用しました。これは「属性転送」、つまり、Bladeコンポーネントで記述したすべてのHTML属性を取得し、コンポーネント内の要素に転送するために使用します。For other attributes that don't have an explicit purpose, we used the {{ $attributes }}
statement. This is used for "attribute forwarding", or in other words, taking any HTML attributes written on the Blade component and forwarding them onto an element within the component.
これにより、wire:model="title"
と、その他のdisabled
、class="..."
、required
など追加属性が、実際の<input>
要素へ確実に転送されるようになります。This ensures wire:model="title"
and any other extra attributes such as disabled
, class="..."
, or required
still get forwarded to the actual <input>
element.
カスタム フォーム コントロールCustom form controls
前の例では、ネイティブHTML入力要素であるかのように使用できる再利用可能なBladeコンポーネントへ入力要素を「ラップ」しました。In the previous example, we "wrapped" an input element into a re-usable Blade component we can use as if it was a native HTML input element.
このパターンは非常に便利です。ただし、(基になるネイティブ入力要素なしで)入力コンポーネント全体を最初から作成したい場合でも、wire:model
を使用してその値をLivewireプロパティに結合できるようにしたい場合もあるでしょう。This pattern is very useful; however, there might be some cases where you want to create an entire input component from scratch (without an underlying native input element), but still be able to bind its value to Livewire properties using wire:model
.
たとえば、Alpineで記述した単純な「カウンター」入力である<x-input-counter />
コンポーネントを作成すると想像してください。For example, let's imagine you wanted to create an <x-input-counter />
component that was a simple "counter" input written in Alpine.
Bladeコンポーネントを作成する前に、参照として、単純な純粋なAlpineの「カウンター」コンポーネントを見てみましょう。Before we create a Blade component, let's first look at a simple, pure-Alpine, "counter" component for reference:
<div x-data="{ count: 0 }">
<button x-on:click="count--">-</button>
<span x-text="count"></span>
<button x-on:click="count++">+</button>
</div>
ご覧のとおり、上記のコンポーネントは、その数値を増減させる2ボタンとともに数値を表示します。As you can see, the component above shows a number alongside two buttons to increment and decrement that number.
ここで、このコンポーネントを<x-input-counter />
という Blade コンポーネントに抽出し、次のようにコンポーネント内で使用したいと想像してください。Now, let's imagine we want to extract this component into a Blade component called <x-input-counter />
that we would use within a component like so:
<x-input-counter wire:model="quantity" />
このコンポーネントの作成はとても簡単です。カウンターのHTMLを取得し、resources/views/components/input-counter.blade.php
のようなBlad コンポーネントテンプレート内に配置します。Creating this component is mostly simple. We take the HTML of the counter and place it inside a Blade component template like resources/views/components/input-counter.blade.php
.
ただし、Livewire コンポーネントからAlpineコンポーネント内の "count"にデータを簡単に結合できるようにするために、wire:model="quantity"
で動作させるには、もう1つ手順が必要です。However, making it work with wire:model="quantity"
so that you can easily bind data from your Livewire component to the "count" inside this Alpine component needs one extra step.
以下のコンポーネントのソースをご覧ください。Here's the source for the component:
<!-- resources/view/components/input-counter.blade.php -->
<div x-data="{ count: 0 }" x-modelable="count" {{ $attributes}}>
<button x-on:click="count--">-</button>
<span x-text="count"></span>
<button x-on:click="count++">+</button>
</div>
ご覧のとおり、このHTMLに関する唯一の異なる点は、x-modelable="count"
と{{ $attributes }}
です。As you can see, the only different bit about this HTML is the x-modelable="count"
and {{ $attributes }}
.
x-modelable
は、特定のデータを外部からのバインドに利用できるようにするようにAlpineに指示するAlpineのユーティリティです。Alpine のドキュメントには、このディレクティブに関する詳細情報があります。x-modelable
is a utility in Alpine that tells Alpine to make a certain piece of data available for binding from outside. The Alpine documentation has more information on this directive.[https://alpinejs.dev/directives/modelable]
{{ $attributes }}
は前述したように、外部からBladeコンポーネントへ渡した属性を転送します。この場合、wire:model
ディレクティブが転送されます。{{ $attributes }}
, as we explored earlier, forwards any attributes passed into the Blade component from outside. In this case, the wire:model
directive will be forwarded.
{{ $attributes }}
のため、HTMLをブラウザーへレンダーすると、wire:model="quantity"
は、以下のようにAlpineコンポーネントのルート<div>
上のx-modelable="count"
とともにレンダーされます。Because of {{ $attributes }}
, when the HTML is rendered in the browser, wire:model="quantity"
will be rendered alongside x-modelable="count"
on the root <div>
of the Alpine component like so:
<div x-data="{ count: 0 }" x-modelable="count" wire:model="quantity">
x-modelable="count"
は、x-model
またはwire:model
ステートメントを探し、"count"を結合先のデータとして使用するようにAlpineへ指示します。x-modelable="count"
tells Alpine to look for any x-model
or wire:model
statements and use "count" as the data to bind them to.
x-modelable
はwire:model
とx-model
の両方で動作するため、このBladeコンポーネントをLivewireとAlpineで相互に交換して使用することもできます。このBladeコンポーネントを純粋な Alpine コンテキストで使用する例を次に示します。Because x-modelable
works for both wire:model
and x-model
, you can also use this Blade component interchangeably with Livewire and Alpine. Here’s an example of using this Blade component in a purely Alpine context:
<x-input-counter x-model="quantity" />
アプリケーションでカスタム入力要素を作成することは非常に強力ですが、LivewireとAlpineが提供するユーティリティと、それらが相互にどのように連携するかをより深く理解する必要があります。Creating custom input elements in your application is extremely powerful but requires a deeper understanding of the utilities Livewire and Alpine provide and how they interact with each other.