Blazor で データバインディングと変更時イベントを同時に処理する悩みどころ
Blazor で データバインディングと変更時イベントを同時に処理する悩みどころ
実現したいこと
例えば、検索キーワードを入力中に選択候補を絞り込む仕様があるとします。
その仕様を実現しようとした場合、
- 検索キーワードをバインドして @bind-value="SearchValue"
- 入力時に値を反映したいのでバインドのタイミングは @bind-value:event="oninput"
- フィルタリングの処理は、入力イベントで処理したいため、 @oninput="OnFiltering"
<input @bind-value="SearchValue" @bind-value:event="oninput" @oninput="OnFiltering" />
但し、このコードはエラーが発生します。
The attribute 'oninput' is used two or more times for this element. Attributes must be unique (case-insensitive). The attribute 'oninput' is used by the '@bind-value' directive attribute
実はバインド構文は、Blazor フレームワーク側でイベントに置き換えて動作しているため"oninput" が二回定義されているよ。と怒られてしまっているのです。
詳細は下記ページ参照 ASP.NET Core Blazor データ バインディング | Microsoft Docs
回避策
回避策その1 - イベント内部で自前で バインドプロパティに値を設定する。
<input @bind-value="SearchValue" @oninput="OnFiltering" />
private void OnFiltering(ChangeEventArgs changeEventArgs) { // 入力した値を即時反映する this.SearchValue = changeEventArgs.Value as string; // フィルター処理を行う Filtering(); }
この方法の個人的によくないポイントは、ChangeEventArgs を @code で受け取らないといけないという点ですね。 コード側(c#) にイベント引数が渡ると、画面情報を生で渡してしまいスパゲッティコードになる危険性があります。
回避策その1 - バインドしたプロパティの set に処理を書く。
<input @bind-value="SearchValue" @bind-value:event="oninput" />
public string SearchValue { get { return _SearchValue; } set { _SearchValue = value; // フィルター処理を行う Filtering(); } }
この方法は、 setter が単純にデータを保持するプロパティの役割以外に、フィルター処理と連動しているため、保守性が悪くなる可能性があります。