記事内に広告が含まれています

【Blazor】フォームを入れ子にする方法

C#

フォーム(EditForm)の一部を別コンポーネントに切り出して入れ子状態にし、データをバインドさせる方法について解説します。

環境

  • Windows 11
  • Visual Studio 2022
  • .NET 8

サンプルコードと解説

まずは使用するクラスです。親となるTodoクラスと子となる2つのDetailsクラスがあります。

namespace ComponentSample.Components.Pages
{
    /// <summary>
    /// 親クラス
    /// </summary>
    public class Todo
    {
        public string Name { get; set; } = "";
        public TodoDetails1 Details1 { get; set; } = new();
        public TodoDetails2 Details2 { get; set; } = new();
    }

    /// <summary>
    /// 子クラス1
    /// </summary>
    public class TodoDetails1
    {
        public string? Memo { get; set; } = "";
    }

    /// <summary>
    /// 子クラス2
    /// </summary>
    public class TodoDetails2
    {
        public bool IsComplete { get; set; } = false;
        public DateTime? CompletionDate { get; set; } = DateTime.Today;
    }
}

次にDetails1に対応するRazorコンポーネントを用意します。

ポイントはEditor<T>を継承させる点で、Tに子クラスを渡すことで親クラスとデータをバインドさせることができます。

@inherits Editor<TodoDetails1>

<div>
    <label>
        メモ:
        <InputText @bind-Value="Value.Memo" />
    </label>
</div>

Details2に対応するRazorコンポーネントも同様に用意します。

@inherits Editor<TodoDetails2>

<div>
    <label>
        完了:
        <InputCheckbox @bind-Value="Value.IsComplete" />
    </label>
</div>
<div>
    <label>
        完了日:
        <InputDate @bind-Value="Value.CompletionDate" />
    </label>
</div>

最後にメインとなるフォームです。

2つのDetailsコンポーネントを呼び出し、@bind-Valueで親モデル内の子クラスプロパティを渡します。

@page "/form-nesting"

<EditForm Model="Model" OnValidSubmit="Submit" FormName="TodoForm">
    <DataAnnotationsValidator />
    <div>
        <label>
            Todo名:
            <InputText @bind-Value="Model!.Name" />
        </label>
    </div>
    <SubForm1 @bind-Value="Model.Details1" />
    <SubForm2 @bind-Value="Model.Details2" />
    <div>
        <button type="submit">登録</button>
    </div>
    @message
</EditForm>

@code {
    [SupplyParameterFromForm]
    public Todo? Model { get; set; } = new ();

    private string? message;

    private void Submit() 
    {
        message = $"登録しました!  Todo名:{Model?.Name}  メモ:{Model?.Details1.Memo}  完了:{Model?.Details2.IsComplete}  完了日:{Model?.Details2.CompletionDate}";
    }
}

実行すると、画面上では子も含めた全てのフォームが表示されます

登録ボタンを押すと、データのバインディングが行われていることが確認できます。

なお現段階での.NETの仕様では、今回のように入れ子になったクラスに対して属性バリデーションを行おうとしても、子クラスに対してはバリデーションが適用されません。

入れ子クラスに対するバリデーションの実装方法については下記記事を参照してください。

参考

ASP.NET Core Blazor フォームのバインド
Blazor フォームでバインドを使用する方法について説明します。
C#Blazor
hiranote

コメント

タイトルとURLをコピーしました