当前位置: 首页 > news >正文

第四章 表单(2)- 输入组件

在 Blazor 框架中,微软对 HTML 输入元素进行了封装,称为输入组件。使用输入组件相较于原生 HTML 输入元素,在编码和安全性方面具有显著优势。

输入组件简介

Blazor框架提供了用于接收和验证用户输入的内置输入组件,这些组件可以在EditForm表单组件中使用,也可以在表单之外使用,当更改输入和提交表单时,会验证输入(如果开启了验证)。

输入组件渲染为如下HTML元素描述
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>多行文本框

InputBase<TValue>是表单输入组件的抽象基类,在上述输入组件列表中,只有InputFileInputRadio<TValue>不是它的子类,其他内置输入组件都派生自InputBase<TValue>

一、通用属性

InputBase<TValue>中有几个较为常用的公共属性,所有子类输入组件皆可使用,分别为:AdditionalAttributesDisplayNameValueValueChangedValueExpression

1、AdditionalAttributes属性

AdditionalAttributesIReadOnlyDictionary<string, object>类型,用于指定在输入组件上附加的多个属性和值。

  • 所有输入组件(包括EditForm)都支持设置任意属性,如果属性与提供的组件参数不匹配,会将属性直接添加到渲染的Html元素上。

  • 示例

    @page "/form-params"
    
    <h3>FormParam</h3>
    
    <EditForm FormName="testForm" Model="Model" OnSubmit="Submit">
        <div>
            <label>
                输入:<InputText @bind-Value="Model!.Name" AdditionalAttributes="paramDic" />
            </label>
        </div>
        <div>
            <button type="submit">Submit</button>
        </div>
    </EditForm>
    
    @code {
        [SupplyParameterFromForm]
        public Student? Model { get; set; }
        protected override void OnInitialized()
        {
            Model = new();
        }
        //字典扩展的附加属性
        Dictionary<string, object> paramDic = new Dictionary<string, object>()
        {
            {"style","color:blue" },
            {"id","formId" }
        };
        
        private void Submit()
        {
            //提交、存储、导航啥的
        }
    
        public class Student
        {
            public string Name { get; set; } = null!;
        }
    }
    

在这里插入图片描述

2、DisplayName属性

DisplayName:当输入内容校验不通过时,使用DisplayName所设置的内容来代替所绑定的属性名来进行异常信息的展示。

  • DisplayName属性并不是所有的输入组件都生效,只是 HTML5 新增的部分输入元素有用,例如InputNumberInputDate等组件,而InputTextInputTextArea等组件是不支持的,感觉很鸡肋

  • 示例

    这里面的<DataAnnotationsValidator/><ValidationSummary/>组件的作用,可以查阅表单验证章节

    @page "/display-name"
    @using System.ComponentModel.DataAnnotations
    @rendermode InteractiveServer
    
    <label>
        <EditForm Model="Model" OnValidSubmit="Submit" FormName="Starship3">
            <DataAnnotationsValidator/>
            <ValidationSummary/>
            Product Date:
            <InputDate @bind-Value="Model!.Date" DisplayName="Product Date" />
            Product Name:
            <InputText @bind-Value="Model!.Name" DisplayName="Product Name" />
            <button type="submit">Submit</button>
        </EditForm>
    </label>
    
    @code {
        [SupplyParameterFromForm]
        private Starship? Model { get; set; }
    
        protected override void OnInitialized()
        {
            Model = new Starship();
        }
    
        public class Starship
        {
            [Required]
            public DateTime Date { get; set; }
            [Required]
            public string Name { get; set; }
        }
    
        public void Submit()
        {
            
        }
    }
    
    

在这里插入图片描述

错误信息

InputDateInputNumber组件支持通过组件参数ParsingErrorMessage来设置验证失败时的显示信息

  • ParsingErrorMessage可以通过占位符{0}配合DisplayName使用

  • 示例

    @page "/display-name"
    @using System.ComponentModel.DataAnnotations
    @rendermode InteractiveServer
    
    <label>
        <EditForm Model="Model" OnValidSubmit="Submit" FormName="Starship3">
            <DataAnnotationsValidator/>
            <ValidationSummary/>
            Product Date:
            <InputDate @bind-Value="Model!.Date" DisplayName="Product Date" ParsingErrorMessage="{0} 必须正确填写"/>
        </EditForm>
    </label>
    
    @code {
        [SupplyParameterFromForm]
        private Starship? Model { get; set; }
    
        protected override void OnInitialized()
        {
            Model = new Starship();
        }
    
        public class Starship
        {
            [Required]
            public DateTime Date { get; set; }
        }
    
        public void Submit()
        {
            
        }
    }
    
    

在这里插入图片描述

注意,较为常规的用法是在表单所绑定的模型的属性上通过使用特性声明来设置展示名称了异常消息。

3、Value属性

默认情况下,在使用输入组件时,使用@bind-Value属性指令就可以实现输入组件的双向数据绑定。

实际上,@bind-Value属性指令是对 ValueValueChangedValueExpression 的一种语法糖,它会自动处理ValueValueChangedValueExpression的设置

  • Value:输入控件的输入值,可以通过Razor表达式绑定到指定的属性上,实现模型到视图的数据绑定
  • ValueChanged:当绑定的值发生变化时,会触发该事件。这通常用于通知组件或父组件,绑定的值已经改变,并且可以在这里执行必要的逻辑,从而实现视图到模型的数据绑定
  • ValueExpression:指定要进行校验或元数据管理的数据,直接返回要进行处理的数据即可

一般情况下直接使用@bind-Value属性指令进行数据绑定就可以了,如果需要对过程进行拆分处理,可以组合使用ValueValueChangedValueExpression,需要注意的是这 3 个属性不可单独使用,要3个组合使用。

  • 示例

    @page "/value-test"
    
    <PageTitle>Value属性测试</PageTitle>
    <EditForm Model="Model" OnSubmit="Submit" FormName="ValueTest">
        <div class="mb-3">
            <InputText Value="@Model.FullName" ValueChanged="ValueChanged" ValueExpression="()=>Model.FullName"/>
        </div>
        <div class="mb-3">
            <button class="btn btn-primary">提交</button>
        </div>
    </EditForm>
    @code {
        public Student Model = new();
    
        void ValueChanged(string value)
        {
            //当输入值发生改变时,修改Model.FullName的值,实现双向绑定
            Model.FullName = value;
        }
        void Submit()
        {
            Console.WriteLine(Model.FullName);
        }
    
        public class Student
        {
            public string? FullName { get; set; }
        }
    }
    

二、验证说明

输入组件会自动检查用户输入的字段是否已更改:

  • 对于带有 EditContext 的输入组件,默认会根据验证结果更新CSS,以通过基础的HTML元素来展示不同的验证结果
    • 即使在没有使用<ValidationSummary>组件的情况下,也会展示验证结果,不过默认是没有展示校验的错误信息的

在这里插入图片描述

  • 对于没有 EditContext 的输入组件,也是支持校验的,可以可通过代码调用验证逻辑(如 Validator.Validate),但不会为基础的HTML元素提供校验结果的样式

在这里插入图片描述
当使用<EditForm>组件时,会自动生成一个EditContext,这里所说的带有EditContext的输入组件指的是被EditForm所包括的输入组件,反之则是没有EditContext的输入组件。

基本示例

  • Starship.cs

    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; }
    }
    
  • Starship3.razor

    @page "/starship-3"
    @using BlazorServerStudy.Models
    @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);
        }
    }
    

异步+EditContext示例

注意,在赋值 EditContext 对象之后不能改变

  • Starship4.razor

    @page "/starship-4"
    @using BlazorServerStudy.Models
    @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 Starship(){
                          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 Task.Delay(1000);
            }
            else
            {
                Logger.LogInformation("Submit called: Form is INVALID");
            }
        }
    }
    

输入组件详解

Blazor中提供了一系列输入组件,方便进行表单处理,下面逐一进行学习。

一、输入框

1、单行文本框

InputText组件,是对 HTML 中的<input type="text">元素的封装,为单行文本框,用于处理string类型的文本值。

  • InputText 组件在纯 HTML 的<form>元素和<EditForm>组件中都可以使用。

  • 示例

    @page "/form-test"
    @inject ILogger<FormTest> Logger
    
    <h3>FormTest</h3>
    
    <EditForm FormName="testForm" Model="Model" OnSubmit="Submit">
        <div>
            <label>
                姓名:
                <InputText @bind-Value="Model!.Name"/>
            </label>
        </div>
        <div>
            <button type="submit">Submit</button>
        </div>
        <div>
            @Model!.Name
        </div>
    </EditForm>
    
    @code {
        public Student? Model { get; set; }
    
        protected override void OnInitialized() => Model ??= new();
    
        private void Submit()
        {
            Logger.LogInformation(Model?.Name);
        }
    
        public class Student
        {
            public string? Name { get; set; } = "Schuyler";
        }
    }
    

2、多行文本框

InputTextArea组件是对 HTML 标记中的<textarea>元素进行了封装,用于表示多行文本框。

常用属性

rows:设置文本框的展示行数,也是高度

cols:设置文本框的展示列数,也是宽度

  • 示例

    @page "/form-test"
    @inject ILogger<FormTest> Logger
    
    <h3>FormTest</h3>
    
    <EditForm FormName="testForm" Model="Model" OnSubmit="Submit">
        <div>
            <label>
                <InputTextArea @bind-Value="Model!.Name" rows="10" cols="50"/>
            </label>
        </div>
        <div>
            <button type="submit">Submit</button>
        </div>
    </EditForm>
    
    @code {
        public Student? Model { get; set; }
    
        protected override void OnInitialized() => Model ??= new();
    
        private void Submit()
        {
            Logger.LogInformation(Model?.Name);
        }
    
        public class Student
        {
            public string? Name { get; set; } = "Schuyler";
        }
    }
    

二、多选框

InputSelect组件是对 HTML 中<select>元素的封装,用于展示下拉菜单或选择列表框,其子选项使用<option>元素表示。

单选(下拉菜单)

InputSelect组件所绑定的数据源为非数组属性时,所展示的就是单选下拉菜单

  • 示例

    @page "/form-test"
    @inject ILogger<FormTest> Logger
    
    <h3>FormTest</h3>
    
    <EditForm FormName="testForm" Model="Model" OnSubmit="Submit">
        <div>
            <InputSelect @bind-Value="Model.City" class="form-select">
                <option value="@City.BJ">北京</option>
                <option value="@City.SH">上海</option>
                <option value="@City.GZ">广州</option>
                <option value="@City.SZ">深圳</option>
            </InputSelect>
        </div>
        <div>
            <button type="submit">Submit</button>
        </div>
    </EditForm>
    
    @code {
        public Student Model = new();
    
        private void Submit()
        {
            //进行提交处理
            Console.WriteLine(Model.City);
        }
    
        public class Student
        {
            public City? City { get; set; }
        }
    
        public enum City { SH, BJ, GZ, SZ }
    }
    

在这里插入图片描述

多选(选择列表框)

InputSelect组件支持多选,其绑定值必须绑定到数组类型的属性。

  • 此外,InputSelect支持 @onchange 事件,该事件通过参数ChangeEventArgs提供了一个选中值的数组

  • 示例

    @page "/form-test"
    @inject ILogger<FormTest> Logger
    
    <h3>FormTest</h3>
    
    <EditForm FormName="testForm" Model="Model" OnSubmit="Submit">
        <div>
            <InputSelect @bind-Value="Model.Citys" class="form-select">
                <option value="@City.BJ">北京</option>
                <option value="@City.SH">上海</option>
                <option value="@City.GZ">广州</option>
                <option value="@City.SZ">深圳</option>
            </InputSelect>
        </div>
        <div>
            <button type="submit">Submit</button>
        </div>
    </EditForm>
    
    @code {
        public Student Model = new();
    
        private void Submit()
        {
            //进行提交处理
            foreach (var city in Model.Citys!)
            {
                Console.WriteLine(city);
            }
        }
    
        public class Student
        {
            public City[]? Citys { get; set; } = new[] { City.NONE };
        }
    
        public enum City { NONE, SH, BJ, GZ, SZ }
    }
    

在这里插入图片描述

三、单选按钮

在Blazor中,可以结合使用InputRadio<TValue>组件和InputRadioGroup<TValue>组件来使用单选按钮组。

单选按钮常常与枚举类型结合使用,有如下要点:

  • [EnumDataType(typeof(enumName))]:在表单模型中定义枚举属性时,使用[EnumDataType]特性进行声明,可以在表单进行验证时以确保属性值在指定的枚举范围内,如果属性值不在指定的枚举范围内,则模型验证将失败并返回相应的错误消息

  • 枚举属性也可以使用[Range]特性进行范围的限制以及错误信息的设置,如[Range(typeof(Manufacturer), nameof(Manufacturer.SpaceX),nameof(Manufacturer.VirginGalactic), ErrorMessage = "Pick a manufacturer.")],分别限制该属性为Manufacturer枚举类型、限制最小值为Manufacturer.SpaceX、最大值为Manufacturer.VirginGalactic

  • ComponentEnums.cs

    public class ComponentEnums
    {
        public enum Manufacturer { SpaceX, NASA, ULA, VirginGalactic, Unknown }
        public enum Color { ImperialRed, SpacecruiserGreen, StarshipBlue, VoyagerOrange }
        public enum Engine { Ion, Plasma, Fusion, Warp }
    }
    
  • RadioTestModel.cs

    public class RadioTestModel
    {
        [Required]
        [Range(typeof(Manufacturer), nameof(Manufacturer.SpaceX), nameof(Manufacturer.VirginGalactic), ErrorMessage = "Pick a manufacturer.")]
        public Manufacturer Manufacturer { get; set; } = Manufacturer.Unknown;
    
        [Required, EnumDataType(typeof(Color))]
        public Color? Color { get; set; } = null;
    
        [Required, EnumDataType(typeof(Engine))]
        public Engine? Engine { get; set; } = null;
    }
    
  • RadioTest.razor

    @page "/radio-test"
    @inject ILogger<RadioTest> Logger
    @using static ComponentEnums
    
    <EditForm Model="Model" OnSubmit="Submit" FormName="RadioTest">
        <fieldset>
            <legend>Manufacturer</legend>
            <InputRadioGroup @bind-Value="Model!.Manufacturer">
                @foreach (var manufacturer in Enum.GetValues<Manufacturer>())
                {
                    <div>
                        <label>
                            <InputRadio Value="manufacturer" />
                            @manufacturer
                        </label>
                    </div>
                }
            </InputRadioGroup>
        </fieldset>
    
        <fieldset>
            <legend>Engine and Color</legend>
            <p>
                Engine and color pairs are recommended, but any
                combination of engine and color is allowed.
            </p>
            <InputRadioGroup Name="engine" @bind-Value="Model!.Engine">
                <InputRadioGroup Name="color" @bind-Value="Model!.Color">
                    <div style="margin-bottom:5px">
                        <div>
                            <label>
                                <InputRadio Name="engine" Value="Engine.Ion" />
                                Ion
                            </label>
                        </div>
                        <div>
                            <label>
                                <InputRadio Name="color" Value="Color.ImperialRed" />
                                Imperial Red
                            </label>
                        </div>
                    </div>
                    <div style="margin-bottom:5px">
                        <div>
                            <label>
                                <InputRadio Name="engine" Value="Engine.Plasma" />
                                Plasma
                            </label>
                        </div>
                        <div>
                            <label>
                                <InputRadio Name="color" Value="Color.SpacecruiserGreen" />
                                Spacecruiser Green
                            </label>
                        </div>
                    </div>
                    <div style="margin-bottom:5px">
                        <div>
                            <label>
                                <InputRadio Name="engine" Value="Engine.Fusion" />
                                Fusion
                            </label>
                        </div>
                        <div>
                            <label>
                                <InputRadio Name="color" Value="Color.StarshipBlue" />
                                Starship Blue
                            </label>
                        </div>
                    </div>
                    <div style="margin-bottom:5px">
                        <div>
                            <label>
                                <InputRadio Name="engine" Value="Engine.Warp" />
                                Warp
                            </label>
                        </div>
                        <div>
                            <label>
                                <InputRadio Name="color" Value="Color.VoyagerOrange" />
                                Voyager Orange
                            </label>
                        </div>
                    </div>
                </InputRadioGroup>
            </InputRadioGroup>
        </fieldset>
    </EditForm>
    
    @code {
        [SupplyParameterFromForm]
        public RadioTestModel? Model { get; set; }
    
        protected override void OnInitialized()
        {
            Model ??= new RadioTestModel();
        }
    
        private void Submit()
        {
            
        }
    }
    

例子中的<fieldset>元素主要用于在表单中对相关的控件(如输入框、选择框等)进行分组,以便于组织和渲染信息。<fieldset>通常与<legend>元素一起使用,<legend>用于为分组提供一个标题或描述。

四、复选框

在Blazor中,复选框为InputCheckbox组件,本质是对<input type="checkbox">元素的封装,用于通过勾选来确认bool类型的值。

  • InputCheckbox组件在纯 HTML 的<form>元素和<EditForm>组件中都可以使用

  • 示例

    @page "/form-test"
    @inject ILogger<FormTest> Logger
    
    <h3>FormTest</h3>
    
    <EditForm FormName="testForm" Model="Model" OnSubmit="Submit">
        <div>
            <label>
                <InputCheckbox @bind-Value="Model!.Sex" class="form-check-input" /></label>
        </div>
        <div>
            <button type="submit">Submit</button>
        </div>
    </EditForm>
    
    @code {
        public Student? Model { get; set; }
    
        protected override void OnInitialized() => Model ??= new() { Sex=true};
    
        private void Submit()
        {
           //随便干点啥
        }
    
        public class Student
        {
            public string? Name { get; set; } = "Schuyler";
            public bool Sex { get; set; }
        }
    }
    
    

五、数字框

InputNumber组件是对<input type=”number”/>元素的封装,这是在 HTML5 新增的元素,用于表示具有上下箭头的数字框,只能用于输入数字。

InputNumber组件中,支持DisplayName属性和ParsingErrorMessage属性:

  • DisplayName:当输入内容校验不通过时,使用DisplayName所设置的内容来代替所绑定的属性名来进行异常信息的展示

  • ParsingErrorMessage:用于指定错误消息的模板,模板中的占位符{0}指的就是DisplayName的值

  • 示例

    @page "/form-test"
    @inject ILogger<FormTest> Logger
    
    <h3>FormTest</h3>
    
    <EditForm FormName="testForm" Model="Model" OnSubmit="Submit">
        <DataAnnotationsValidator />
        <ValidationSummary />
        <div class="mb-3 w-50">
            <InputNumber @bind-Value="Model.Count"  DisplayName="测试数量" ParsingErrorMessage="{0}数量太多"/>
        </div>
        <div>
            <button type="submit">Submit</button>
        </div>
    </EditForm>
    
    @code {
        public Student Model = new();
    
        private void Submit()
        {
            //进行提交处理
            Console.WriteLine($"数量:{Model.Count}");
        }
    
        public class Student
        {
            public int Count { get; set; }
        }
    }
    

在这里插入图片描述

六、日期选择器

InputDate组件是对<input type="date"/>元素的封装,<input type="date"/>元素是在 HTML 5 中新增的,用于渲染一个可以让用户选择日期值的选择器。

  • 绑定到<InputDate>组件上的属性或字段的类型必须是 DateTimeDateOnly

  • InputDate组件也支持DisplayName属性和ParsingErrorMessage属性

  • 示例

    @page "/form-test"
    @inject ILogger<FormTest> Logger
    
    <h3>FormTest</h3>
    
    <EditForm FormName="testForm" Model="Model" OnSubmit="Submit">
        <DataAnnotationsValidator />
        <ValidationSummary />
        <div class="mb-3 w-50">
            <label>
                日期:
                <InputDate @bind-Value="Model.CreateDateTime" DisplayName="日期" ParsingErrorMessage="输入的{0}字段值不正确" />
            </label>
        </div>
        <div>
            <button type="submit">Submit</button>
        </div>
    </EditForm>
    
    @code {
        public Student Model = new();
    
        private void Submit()
        {
            //进行提交处理
            Console.WriteLine($"日期:{Model.CreateDateTime}");
        }
    
        public class Student
        {
            public DateTime CreateDateTime { get; set; } = DateTime.Now;
        }
    }
    

在这里插入图片描述

提交按钮的禁用

在表单中,表单的提交按钮可以使用<button type="submit">元素来实现。这个没啥特别的,比较需要注意的是提交按钮的禁用。一般情况下,当表单中的某个字段没有通过验证的时候,应该将提交按钮禁用的,以确保在前端就拦截提交。

想要禁用提交按钮,可以通过设置<button>元素的disabled属性来实现

  • 示例

    @page "/starship-14"
    @rendermode InteractiveServer
    @implements IDisposable
    @inject ILogger<Starship14> Logger
    
    <EditForm EditContext="editContext" OnValidSubmit="Submit" FormName="Starship14">
        <DataAnnotationsValidator />
        <ValidationSummary />
        <div>
            <label>
                Identifier:
                <InputText @bind-Value="Model!.Id" />
            </label>
        </div>
        <div>
            <button type="submit" disabled="@formInvalid">Submit</button>
        </div>
    </EditForm>
    
    @code {
        private bool formInvalid = false;
        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);
            editContext.OnFieldChanged += HandleFieldChanged;
        }
    
        private void HandleFieldChanged(object? sender, FieldChangedEventArgs e)
        {
            if (editContext is not null)
            {
                formInvalid = !editContext.Validate();
                StateHasChanged();
            }
        }
    
        private void Submit()
        {
            Logger.LogInformation("Submit called: Processing the form");
        }
    
        public void Dispose()
        {
            if (editContext is not null)
            {
                editContext.OnFieldChanged -= HandleFieldChanged;
            }
        }
    }
    

上面的例子中,存在一个问题,就是只要在任何一个输入组件中失焦后,<ValidationSummary>组件都会填充所有字段验证失败的信息,想要解决这个问题可以使用如下个方法:

  • 不使用<ValidationSummary>组件

  • 先将<ValidationSummary>组件隐藏,在点击提交按钮时,再将其展示

  • 示例

    <EditForm ... EditContext="editContext" OnValidSubmit="Submit" ......>
        <DataAnnotationsValidator />
        <ValidationSummary style="@displaySummary"/>
    
        ......
    
        <button type="submit" disabled="@formInvalid">Submit</button>
    </EditForm>
    
    @code {
        private string displaySummary = "display:none";
        ......
        private void Submit()
        {
            displaySummary = "display:block";
        }
    }
    

相关文章:

  • Python 变量作用域、global 关键字与闭包作用域深度解析 第三部分
  • vue中keep-alive组件的使用
  • Web前端考核 JavaScript知识点详解
  • 《可爱风格 2048 游戏项目:HTML 实现全解析》
  • 本地部署Stable Diffusion生成爆火的AI图片
  • [深度学习]图片分类任务
  • 新版本Springboot的lombok导入依赖出现问题的解决办法
  • C++友元:跨墙访问的三种姿势
  • MySQL小练习
  • 高速电路中的时序设计
  • 哪吒汽车:一边熬夜蹦迪,一边找药投医
  • easyExcel2.2.10中为0数据显示为空
  • 基于深度学习的行人人脸识别系统的设计与实现
  • 【 <二> 丹方改良:Spring 时代的 JavaWeb】之 Spring Boot 中的日志管理:Logback 的集成
  • LeetCode-215. 数组中的第K个最大元素
  • 解决MediaMetadataRetriever.finalize()超时问题
  • CUDA与GPU架构:解锁并行计算的终极奥义
  • 2025中国AI Agent 行业研究报告|附文件下载
  • 《TCP/IP网络编程》学习笔记 | Chapter 21:异步通知 I/O 模型
  • Charles抓HTTPS包
  • 四问当前旱情:还会持续多久
  • 发表“男性患子宫肌瘤”论文的杂志一年发文三千余篇,中介称可提供代写
  • 上海车展侧记|中国汽车产业的韧性从何而来
  • 人民日报和音:引领新时代中俄关系坚毅前行
  • 菲律宾首都机场航站楼外发生汽车冲撞事故致2死多伤
  • 经常犯困、迷糊……当心是身体发出的“黄牌”警告