ASP.NET Core Blazor 入力コンポーネント

Note

これは、この記事の最新バージョンではありません。 現在のリリースについては、この記事の .NET 8 バージョンを参照してください。

重要

この情報はリリース前の製品に関する事項であり、正式版がリリースされるまでに大幅に変更される可能性があります。 Microsoft はここに示されている情報について、明示か黙示かを問わず、一切保証しません。

現在のリリースについては、この記事の .NET 8 バージョンを参照してください。

この記事では、Blazor の組み込みの入力コンポーネントについて説明します。

入力コンポーネント

Blazor フレームワークには、ユーザー入力を受け取って検証するための組み込みの入力コンポーネントが用意されています。 次の表で示す組み込みの入力コンポーネントは、EditContext である EditForm でサポートされます。

表のコンポーネントは、Razor コンポーネント マークアップのフォームの外部でもサポートされます。 入力は、それらが変更されたときとフォームが送信されたときに検証されます。

入力コンポーネント ... とレンダリング
InputCheckbox <input type="checkbox">
InputDate<TValue> <input type="date">
InputFile <input type="file">
InputNumber<TValue> <input type="number">
InputRadio<TValue> <input type="radio">
InputRadioGroup<TValue> InputRadio<TValue> のグループ
InputSelect<TValue> <select>
InputText <input>
InputTextArea <textarea>

InputFile コンポーネントについて詳しくは、「ASP.NET Core Blazor ファイルのアップロード」をご覧ください。

入力コンポーネント ... とレンダリング
InputCheckbox <input type="checkbox">
InputDate<TValue> <input type="date">
InputNumber<TValue> <input type="number">
InputSelect<TValue> <select>
InputText <input>
InputTextArea <textarea>

Note

InputRadio<TValue>InputRadioGroup<TValue> コンポーネントは、ASP.NET Core 5.0 以降で使用できます。 詳細については、この記事のバージョン 5.0 以降を選択してください。

すべての入力コンポーネント (EditForm を含む) で、任意の属性がサポートされています。 コンポーネント パラメーターに一致しない属性は、レンダリングされる HTML 要素に追加されます。

入力コンポーネントによって、フィールドが変更されたときに検証するための既定の動作が提供されます。

  • EditContext を含むフォーム内の入力コンポーネントの場合、既定の検証動作には、基になる HTML 要素の検証スタイルを使用して、フィールドの状態を有効または無効として反映するように、フィールド CSS クラスを更新することが含まれます。
  • EditContext がないコントロールの場合、既定の検証には有効または無効な状態が反映されますが、基になる HTML 要素に対する検証スタイルは提供 "されません"。

一部のコンポーネントには、便利な解析ロジックが含まれます。 たとえば、InputDate<TValue>InputNumber<TValue> では、解析不能な値を検証エラーとして登録することによって、解析不能な値を適切に処理します。 null 値を受け入れることができる型では、ターゲット フィールドの null 値の許容もサポートされています (たとえば、null 許容整数の場合は int?)。

InputFile コンポーネントについて詳しくは、「ASP.NET Core Blazor ファイルのアップロード」をご覧ください。

フォームの例

この記事の例と他の "フォーム" ノードの記事の例のいくつかで使用されている次の Starship 型では、データ注釈を持つさまざまなプロパティのセットが定義されています。

  • Id は、RequiredAttribute で注釈が付けられているため必須です。 Id には、StringLengthAttribute を使用して、1 文字以上 16 文字以下の値が要求されています。
  • Description は、RequiredAttribute で注釈が付けられていないため、省略可能です。
  • Classification は必須です。
  • MaximumAccommodation プロパティは、既定値は 0 ですが、RangeAttribute により 1 から 100,000 の値が必要です。
  • IsValidatedDesign により、プロパティの値が true であることが要求されています。これは、プロパティが UI のチェック ボックス (<input type="checkbox">) にバインドされているときは、選択された状態と一致します。
  • ProductionDateDateTime であり、必須です。

Starship.cs:

using System.ComponentModel.DataAnnotations;

namespace BlazorSample;

public class Starship
{
    [Required]
    [StringLength(16, ErrorMessage = "Identifier too long (16 character limit).")]
    public string? Id { get; set; }

    public string? Description { get; set; }

    [Required]
    public string? Classification { get; set; }

    [Range(1, 100000, ErrorMessage = "Accommodation invalid (1-100000).")]
    public int MaximumAccommodation { get; set; }

    [Required]
    [Range(typeof(bool), "true", "true", ErrorMessage = "Approval required.")]
    public bool IsValidatedDesign { get; set; }

    [Required]
    public DateTime ProductionDate { get; set; }
}
using System.ComponentModel.DataAnnotations;

public class Starship
{
    [Required]
    [StringLength(16, ErrorMessage = "Identifier too long (16 character limit).")]
    public string? Id { get; set; }

    public string? Description { get; set; }

    [Required]
    public string? Classification { get; set; }

    [Range(1, 100000, ErrorMessage = "Accommodation invalid (1-100000).")]
    public int MaximumAccommodation { get; set; }

    [Required]
    [Range(typeof(bool), "true", "true", 
        ErrorMessage = "This form disallows unapproved ships.")]
    public bool IsValidatedDesign { get; set; }

    [Required]
    public DateTime ProductionDate { get; set; }
}
using System.ComponentModel.DataAnnotations;

public class Starship
{
    [Required]
    [StringLength(16, ErrorMessage = "Identifier too long (16 character limit).")]
    public string? Id { get; set; }

    public string? Description { get; set; }

    [Required]
    public string? Classification { get; set; }

    [Range(1, 100000, ErrorMessage = "Accommodation invalid (1-100000).")]
    public int MaximumAccommodation { get; set; }

    [Required]
    [Range(typeof(bool), "true", "true", 
        ErrorMessage = "This form disallows unapproved ships.")]
    public bool IsValidatedDesign { get; set; }

    [Required]
    public DateTime ProductionDate { get; set; }
}
using System;
using System.ComponentModel.DataAnnotations;

public class Starship
{
    [Required]
    [StringLength(16, ErrorMessage = "Identifier too long (16 character limit).")]
    public string Id { get; set; }

    public string Description { get; set; }

    [Required]
    public string Classification { get; set; }

    [Range(1, 100000, ErrorMessage = "Accommodation invalid (1-100000).")]
    public int MaximumAccommodation { get; set; }

    [Required]
    [Range(typeof(bool), "true", "true", 
        ErrorMessage = "This form disallows unapproved ships.")]
    public bool IsValidatedDesign { get; set; }

    [Required]
    public DateTime ProductionDate { get; set; }
}
using System;
using System.ComponentModel.DataAnnotations;

public class Starship
{
    [Required]
    [StringLength(16, ErrorMessage = "Identifier too long (16 character limit).")]
    public string Id { get; set; }

    public string Description { get; set; }

    [Required]
    public string Classification { get; set; }

    [Range(1, 100000, ErrorMessage = "Accommodation invalid (1-100000).")]
    public int MaximumAccommodation { get; set; }

    [Required]
    [Range(typeof(bool), "true", "true", 
        ErrorMessage = "This form disallows unapproved ships.")]
    public bool IsValidatedDesign { get; set; }

    [Required]
    public DateTime ProductionDate { get; set; }
}

以下のフォームでは、次のものを使用してユーザー入力が受け入れられて検証されます。

  • 前の Starship モデルで定義されているプロパティと検証。
  • Blazor の複数の組み込みの入力コンポーネント。

船舶の分類のモデル プロパティ (Classification) を設定すると、モデルに一致するオプションがチェックされます。 たとえば、探査船の分類の checked="@(Model!.Classification == "Exploration")" などです。 チェック済みオプションを明示的に設定する理由は、<select> 要素の値がブラウザーにのみ存在することにあります。 フォームが送信後にサーバーにレンダリングされる場合、クライアントの状態はサーバーの状態でオーバーライドされます。通常、オプションはチェック済みとしてマークされません。 モデル プロパティからチェック済みオプションを設定することで、常に分類がモデルの状態を反映します。 これにより、フォームの送信全体で分類の選択が保持され、結果としてサーバー上でフォームが再レンダリングされます。 対話型サーバー レンダリング モードがコンポーネントに直接適用されている場合など、フォームがサーバー上で再レンダリングされない場合は、Blazor によってクライアントの <select> 要素の状態が保持されるため、モデルからのチェック済みオプションの明示的な割り当ては必要ありません。

Starship3.razor:

@page "/starship-3"
@inject ILogger<Starship3> Logger

<h1>Starfleet Starship Database</h1>

<h2>New Ship Entry Form</h2>

<EditForm Model="Model" OnValidSubmit="Submit" FormName="Starship3">
    <DataAnnotationsValidator />
    <ValidationSummary />
    <div>
        <label>
            Identifier: 
            <InputText @bind-Value="Model!.Id" />
        </label>
    </div>
    <div>
        <label>
            Description (optional): 
            <InputTextArea @bind-Value="Model!.Description" />
        </label>
    </div>
    <div>
        <label>
            Primary Classification: 
            <InputSelect @bind-Value="Model!.Classification">
                <option value="">
                    Select classification ...
                </option>
                <option checked="@(Model!.Classification == "Exploration")" 
                    value="Exploration">
                    Exploration
                </option>
                <option checked="@(Model!.Classification == "Diplomacy")" 
                    value="Diplomacy">
                    Diplomacy
                </option>
                <option checked="@(Model!.Classification == "Defense")" 
                    value="Defense">
                    Defense
                </option>
            </InputSelect>
        </label>
    </div>
    <div>
        <label>
            Maximum Accommodation: 
            <InputNumber @bind-Value="Model!.MaximumAccommodation" />
        </label>
    </div>
    <div>
        <label>
            Engineering Approval: 
            <InputCheckbox @bind-Value="Model!.IsValidatedDesign" />
        </label>
    </div>
    <div>
        <label>
            Production Date: 
            <InputDate @bind-Value="Model!.ProductionDate" />
        </label>
    </div>
    <div>
        <button type="submit">Submit</button>
    </div>
</EditForm>

@code {
    [SupplyParameterFromForm]
    private Starship? Model { get; set; }

    protected override void OnInitialized() =>
        Model ??= new() { ProductionDate = DateTime.UtcNow };

    private void Submit()
    {
        Logger.LogInformation("Id = {Id} Description = {Description} " +
            "Classification = {Classification} MaximumAccommodation = " +
            "{MaximumAccommodation} IsValidatedDesign = " +
            "{IsValidatedDesign} ProductionDate = {ProductionDate}",
            Model?.Id, Model?.Description, Model?.Classification,
            Model?.MaximumAccommodation, Model?.IsValidatedDesign,
            Model?.ProductionDate);
    }
}
@page "/starship-3"
@inject ILogger<Starship3> Logger

<h1>Starfleet Starship Database</h1>

<h2>New Ship Entry Form</h2>

<EditForm Model="Model" OnValidSubmit="Submit">
    <DataAnnotationsValidator />
    <ValidationSummary />
    <div>
        <label>
            Identifier:
            <InputText @bind-Value="Model!.Id" />
        </label>
    </div>
    <div>
        <label>
            Description (optional):
            <InputTextArea @bind-Value="Model!.Description" />
        </label>
    </div>
    <div>
        <label>
            Primary Classification:
            <InputSelect @bind-Value="Model!.Classification">
                <option value="">Select classification ...</option>
                <option value="Exploration">Exploration</option>
                <option value="Diplomacy">Diplomacy</option>
                <option value="Defense">Defense</option>
            </InputSelect>
        </label>
    </div>
    <div>
        <label>
            Maximum Accommodation:
            <InputNumber @bind-Value="Model!.MaximumAccommodation" />
        </label>
    </div>
    <div>
        <label>
            Engineering Approval:
            <InputCheckbox @bind-Value="Model!.IsValidatedDesign" />
        </label>
    </div>
    <div>
        <label>
            Production Date:
            <InputDate @bind-Value="Model!.ProductionDate" />
        </label>
    </div>
    <div>
        <button type="submit">Submit</button>
    </div>
</EditForm>

@code {
    private Starship? Model { get; set; }

    protected override void OnInitialized() =>
        Model ??= new() { ProductionDate = DateTime.UtcNow };

    private void Submit()
    {
        Logger.LogInformation("Id = {Id} Description = {Description} " +
            "Classification = {Classification} MaximumAccommodation = " +
            "{MaximumAccommodation} IsValidatedDesign = " +
            "{IsValidatedDesign} ProductionDate = {ProductionDate}", 
            Model?.Id, Model?.Description, Model?.Classification, 
            Model?.MaximumAccommodation, Model?.IsValidatedDesign, 
            Model?.ProductionDate);
    }
}

前の例の EditForm により、割り当てられた Starship インスタンス (EditContext) に基づいて Model="..." が作成され、有効なフォームが処理されます。 次の例では、EditContext をフォームに割り当て、フォームが送信されるときに検証する方法を示します。

次に例を示します。

  • 前の Starfleet Starship Database フォーム (Starship3 コンポーネント) の簡略版が使用され、宇宙船の ID の値のみが受け取られます。Starship の他のプロパティは、Starship 型のインスタンスが作成されるときに、有効な既定値を受け取ります。
  • Submit ボタンが選択されると、Submit メソッドが実行されます。
  • フォームは、Submit メソッドで EditContext.Validate を呼び出すことによって検証されます。
  • 検証結果に応じて、ログ記録が実行されます。

メモ

次の例の Submit は、フォーム値の格納で非同期呼び出し (await ...) が使用されることが多いので、非同期メソッドとして示されています。 示されているようにフォームがテスト アプリで使用される場合は、Submit は単に同期的に実行されます。 テスト目的の場合は、次のビルド警告を無視します。

This async method lacks 'await' operators and will run synchronously. ...

Starship4.razor:

@page "/starship-4"
@inject ILogger<Starship4> Logger

<EditForm EditContext="editContext" OnSubmit="Submit" FormName="Starship4">
    <DataAnnotationsValidator />
    <div>
        <label>
            Identifier: 
            <InputText @bind-Value="Model!.Id" />
        </label>
    </div>
    <div>
        <button type="submit">Submit</button>
    </div>
</EditForm>

@code {
    private EditContext? editContext;

    [SupplyParameterFromForm]
    private Starship? Model { get; set; }

    protected override void OnInitialized()
    {
        Model ??=
            new()
                {
                    Id = "NCC-1701",
                    Classification = "Exploration",
                    MaximumAccommodation = 150,
                    IsValidatedDesign = true,
                    ProductionDate = new DateTime(2245, 4, 11)
                };
        editContext = new(Model);
    }

    private async Task Submit()
    {
        if (editContext != null && editContext.Validate())
        {
            Logger.LogInformation("Submit called: Form is valid");

            // await ...
        }
        else
        {
            Logger.LogInformation("Submit called: Form is INVALID");
        }
    }
}
@page "/starship-4"
@inject ILogger<Starship4> Logger

<EditForm EditContext="editContext" OnSubmit="Submit">
    <DataAnnotationsValidator />
    <div>
        <label>
            Identifier:
            <InputText @bind-Value="Model!.Id" />
        </label>
    </div>
    <div>
        <button type="submit">Submit</button>
    </div>
</EditForm>

@code {
    private EditContext? editContext;

    private Starship Model { get; set; }

    protected override void OnInitialized()
    {
        Model ??= 
            new()
            {
                Id = "NCC-1701",
                Classification = "Exploration",
                MaximumAccommodation = 150,
                IsValidatedDesign = true,
                ProductionDate = new DateTime(2245, 4, 11)
            };
        editContext = new(Model);
    }

    private async Task Submit()
    {
        if (editContext != null && editContext.Validate())
        {
            Logger.LogInformation("Submit called: Form is valid");

            // await ...
        }
        else
        {
            Logger.LogInformation("Submit called: Form is INVALID");
        }
    }
}

注意

割り当てられた後で EditContext を変更することは、サポートされていません

InputSelect コンポーネントを使用した複数のオプションの選択

バインドでは、InputSelect<TValue> コンポーネントを使用した multiple オプションの選択がサポートされます。 @onchange イベントでは、イベント引数 (ChangeEventArgs) を介して選択したオプションの配列が提供されます。 その値は配列型にバインドされる必要があり、配列型にバインドすると InputSelect<TValue> タグで multiple 属性が省略可能になります。

次の例では、ユーザーは少なくとも 2 つの宇宙船の分類を選択する必要がありますが、3 つの分類以下でなければなりません。

Starship5.razor:

@page "/starship-5"
@using System.ComponentModel.DataAnnotations
@inject ILogger<Starship5> Logger

<h1>Bind Multiple <code>InputSelect</code> Example</h1>

<EditForm EditContext="editContext" OnValidSubmit="Submit" FormName="Starship5">
    <DataAnnotationsValidator />
    <ValidationSummary />
    <div>
        <label>
            Select classifications (Minimum: 2, Maximum: 3):
            <InputSelect @bind-Value="Model!.SelectedClassification">
                <option value="@Classification.Exploration">Exploration</option>
                <option value="@Classification.Diplomacy">Diplomacy</option>
                <option value="@Classification.Defense">Defense</option>
                <option value="@Classification.Research">Research</option>
            </InputSelect>
        </label>
    </div>
    <div>
        <button type="submit">Submit</button>
    </div>
</EditForm>

@if (Model?.SelectedClassification?.Length > 0)
{
    <div>@string.Join(", ", Model.SelectedClassification)</div>
}

@code {
    private EditContext? editContext;

    [SupplyParameterFromForm]
    private Starship? Model { get; set; }

    protected override void OnInitialized()
    {
        Model = new();
        editContext = new(Model);
    }

    private void Submit()
    {
        Logger.LogInformation("Submit called: Processing the form");
    }

    private class Starship
    {
        [Required]
        [MinLength(2, ErrorMessage = "Select at least two classifications.")]
        [MaxLength(3, ErrorMessage = "Select no more than three classifications.")]
        public Classification[]? SelectedClassification { get; set; } =
            new[] { Classification.None };
    }

    private enum Classification { None, Exploration, Diplomacy, Defense, Research }
}
@page "/starship-5"
@using System.ComponentModel.DataAnnotations
@inject ILogger<Starship5> Logger

<h1>Bind Multiple <code>InputSelect</code> Example</h1>

<EditForm EditContext="editContext" OnValidSubmit="Submit">
    <DataAnnotationsValidator />
    <ValidationSummary />
    <div>
        <label>
            Select classifications (Minimum: 2, Maximum: 3):
            <InputSelect @bind-Value="Model!.SelectedClassification">
                <option value="@Classification.Exploration">Exploration</option>
                <option value="@Classification.Diplomacy">Diplomacy</option>
                <option value="@Classification.Defense">Defense</option>
                <option value="@Classification.Research">Research</option>
            </InputSelect>
        </label>
    </div>
    <div>
        <button type="submit">Submit</button>
    </div>
</EditForm>

@if (Model?.SelectedClassification?.Length > 0)
{
    <div>@string.Join(", ", Model.SelectedClassification)</div>
}

@code {
    private EditContext? editContext;

    private Starship? Model { get; set; }

    protected override void OnInitialized()
    {
        Model ??= new();
        editContext = new(Model);
    }

    private void Submit()
    {
        Logger.LogInformation("Submit called: Processing the form");
    }

    private class Starship
    {
        [Required]
        [MinLength(2, ErrorMessage = "Select at least two classifications.")]
        [MaxLength(3, ErrorMessage = "Select no more than three classifications.")]
        public Classification[]? SelectedClassification { get; set; } =
            new[] { Classification.None };
    }

    private enum Classification { None, Exploration, Diplomacy, Defense, Research }
}

空の文字列と null 値がデータ バインディングでどのように処理されるかについては、「InputSelect オプションを C# オブジェクトの null 値にバインドする」セクションを参照してください。

InputSelect オプションを C# オブジェクトの null 値にバインドする

空の文字列と null 値がデータ バインディングでどのように処理されるかについては、「ASP.NET Core Blazor のデータ バインディング」をご覧ください。

表示名のサポート

いくつかの組み込みコンポーネントでは、InputBase<TValue>.DisplayName パラメーターを使用した表示名がサポートされています。

フォームの例」セクションの Starfleet Starship Database フォーム (Starship3 コンポーネント) で、新しい宇宙船の製造日には表示名が指定されていません。

<label>
    Production Date:
    <InputDate @bind-Value="Model!.ProductionDate" />
</label>

フォームの送信時にフィールドに無効な日付が含まれている場合、エラー メッセージにはわかりやすい名前が表示されません。 フィールド名 "ProductionDate" は、検証の概要に表示されるときに、"Production" と "Date" の間に空白がありません。

ProductionDate フィールドは日付である必要があります。

DisplayName プロパティには、"Production" と "Date" の間にスペースがあるフレンドリ名を設定します。

<label>
    Production Date:
    <InputDate @bind-Value="Model!.ProductionDate" 
        DisplayName="Production Date" />
</label>

フィールドの値が無効な場合、検証の概要にはフレンドリ名が表示されます。

Production Date フィールドは日付である必要があります。

エラー メッセージ テンプレートのサポート

InputDate<TValue>InputNumber<TValue> では、エラー メッセージ テンプレートがサポートされています。

わかりやすい表示名が割り当てられた「フォームの例」セクションの Starfleet Starship Database フォーム (Starship3 コンポーネント) の Production Date フィールドでは、次の既定のエラー メッセージ テンプレートを使用してエラー メッセージが生成されます。

The {0} field must be a date.

{0} プレースホルダーの位置は、エラーがユーザーに表示されるときに、DisplayName プロパティの値が表示される場所です。

<label>
    Production Date:
    <InputDate @bind-Value="Model!.ProductionDate" 
        DisplayName="Production Date" />
</label>

Production Date フィールドは日付である必要があります。

カスタム メッセージを提供するには、カスタム テンプレートを ParsingErrorMessage に割り当てます。

<label>
    Production Date:
    <InputDate @bind-Value="Model!.ProductionDate" 
        DisplayName="Production Date" 
        ParsingErrorMessage="The {0} field has an incorrect date value." />
</label>

Production Date フィールドに無効な日付値が指定されています。

フォームの例」セクションの Starfleet Starship Database フォーム (Starship3 コンポーネント) では、既定のエラー メッセージ テンプレートが使用されています。

The {0} field must be a date.

{0} プレースホルダーの位置は、エラーがユーザーに表示されるときに、DisplayName プロパティの値が表示される場所です。

<label>
    Production Date:
    <InputDate @bind-Value="Model!.ProductionDate" />
</label>

ProductionDate フィールドは日付である必要があります。

カスタム メッセージを提供するには、カスタム テンプレートを ParsingErrorMessage に割り当てます。

<label>
    Production Date:
    <InputDate @bind-Value="Model!.ProductionDate" 
        ParsingErrorMessage="The {0} field has an incorrect date value." />
</label>

ProductionDate フィールドに無効な日付値が指定されています。