How do I validate a nested complex model in Blazor?
The built-in DataAnnotationsValidator allows you to validate form input using data annotations, but it only validates top-level properties bound to the form and not child or complex type properties. To validate the nested complex model, replace the DataAnnotationsValidator with the ObjectGraphDataAnnotationsValidator, which validates the entire object, including child and complex type properties in the form. Install the following package via Package Manager Console in order to use the ObjectGraphDataAnnotationsValidator. PM> Install-Package Microsoft.AspNetCore.Components.DataAnnotations.Validation -Version 3.2.0-rc1.20223.4 Create a new Folder named StudentDetails in the main application and add the class named Student.cs to the StudentDetails folder. In Student.cs file, create two model classes -Student and PersonalDetails. Here, add ValidateComplexType belonging to the ObjectGraphDataAnnotationsValidator above the complex type declaration. using System.ComponentModel.DataAnnotations;namespace Validating_Complex_Model_in_Blazor.StudentDetails{ public class Student { public Student () { Details = new PersonalDetails(); } [Required] public string Name { get; set; } [Required] public string Department { get; set; } [ValidateComplexType] public PersonalDetails Details { get; set; } } public class PersonalDetails { [Required] public int Age { get; set; } [Required] public string? Address { get; set; } }} Create an Index.razor page with the EditForm and Input components shown in the code sample below. Set the Model property of the EditForm component to the Student class instance. Additionally, the ObjectGraphDataAnnotationsValidator and ValidationSummary tags are used for validation and the display of validation summary, respectively. @page “/”@using Validating_Complex_Model_in_Blazor.StudentDetails<EditForm Model=”@_student” OnValidSubmit=”@HandleValidSubmit” OnInvalidSubmit=”@HandleInvalidSubmit”> <ObjectGraphDataAnnotationsValidator /> <ValidationSummary /> <div class=”form-group”> <label for=”name”>Name: </label> <InputText Id=”name” Class=”form-control” @bind-Value=”@_student.Name”></InputText> <ValidationMessage For=”@(() => _student.Name)” /> </div> <div class=”form-group”> <label for=”department”>Department: </label> <InputText Id=”department” Class=”form-control” @bind-Value=”@_student.Department”></InputText> <ValidationMessage For=”@(() => _student.Department)” /> </div> <div class=”form-group”> <label for=”address”>Address: </label> <InputTextArea Id=”address” Class=”form-control” @bind-Value=”@_student.Details.Address”></InputTextArea> <ValidationMessage For=”@(() => _student.Details.Address)” /> </div> <button type=”submit”>Submit</button> </EditForm> @code { public string StatusMessage; public Student _student = new Student(); public void HandleValidSubmit() { StatusMessage = “It’s a valid submission.”; } public void HandleInvalidSubmit() { StatusMessage = “It’s an invalid submission. Please see the error message(s) listed below.”; } } View Sample in GitHub
What is an EditContext and how do I define and use it in a form?
The EditContext of the form stores information about the editing process, such as which fields have been changed and which validation messages are currently displayed. To manually pass the EditContext to the EditForm, follow the steps below. Create a new Customer.cs file and model Customer class. public class Customer { [Required] public string Name { get; set; } [Required] [StringLength(4, ErrorMessage = “The organization code must be less than 5 characters in length.”)] public string OrganizationCode { get; set; } } Insert an EditForm component into the Index.razor page. Then, make instances of the Customer class and the EditContext, and assign the Customer class instance to the EditContext instance. Finally, bind the EditContext instance to the EditContext property in the EditForm component. @page “/” <EditForm EditContext=”@editContext”> <DataAnnotationsValidator /> <ValidationSummary /> </EditForm> @code { private Customer _customer = new Customer(); private EditContext editContext; protected override void OnInitialized() { editContext = new(_customer); } } As the EditContext stores all the form information, it can be used to validate the form components. Add the Razor code as given below with input texts and a button. When a form is submitted, the Validate() method is invoked to perform validation. @page “/” <EditForm EditContext=”@editContext”> <DataAnnotationsValidator /> <ValidationSummary /> <div class=”form-group”> <label for=”name”>Name:</> <InputText id=”name” @bind-Value=”_customer.Name” /> <ValidationMessage For=”=”@(() => _customer.Name)” /> </div> <div class=”form-group”> <label for=”organizationCode”>Organization Code:</> <InputText id=”organizationCode” class=”form-control” @bind-Value=”_customer.OrganizationCode”/> <ValidationMessage For=”=”@(() => _customer.OrganizationCode)” /> </div> <div style=”margin-top: 10px;”> <button type=”submit” class=”btn btn-primary” @onclick=”Submit”>Submit</button> </div> </EditForm> View Sample in GitHub
How can I add custom CSS class names to input components based on the validation state despite bootstrap and other CSS frameworks?
To add custom CSS class names to input components despite bootstrap and other CSS framework styling, follow the steps below. In the wwroot/css/site.css stylesheet, include the following styles. .validField { outline: 2px dotted green; } .invalidField { outline: 2px dotted red; } Create a new Customer.cs and model Customer class. using System.ComponentModel.DataAnnotations; namespace CustomCSS_Validation_InputComponent { public class Customer { [Required] public string Name { get; set; } [Required] [StringLength(4, ErrorMessage = “The organization code must be less than 5 characters in length.”)] public string OrganizationCode { get; set; } } } Create a new CustomFieldCssClassProvider.cs and then the CustomFieldCssClassProvider class.Inherit the CustomFieldCssClassProvider class from FieldCssClassProvider and override the GetFieldCssClass method, which helps to check for validation messages with the EditContext and returns the “validField” or “invalidField” class name to the appropriate field. using Microsoft.AspNetCore.Components.Forms; using System.Linq; namespace FormBootstrapCSS.Data { public class CustomFieldCssClassProvider : FieldCssClassProvider { public override string GetFieldCssClass(EditContext editContext, in FieldIdentifier fieldIdentifier) { var isValid = !editContext.GetValidationMessages(fieldIdentifier).Any(); return isValid ? “validField” : “invalidField”; } } } Add the form design code as well as the code for input components validation to the Index.razor page. Here, the SetFieldCssClassProvider method in the EditContext class is used to set the custom CSS name to the appropriate field based on the validation result returned by the CustomFieldCssClassProvider class, whose instance is passed into the method. @page “/” <EditForm EditContext=”@editContext” OnValidSubmit=”@Submit”> <DataAnnotationsValidator /> <ValidationSummary /> <div class=”mt-2 col-md-12″> Name: <InputText id=”name” @bind-Value=”_customer.Name” /> </div> <div class=”mt-2 col-md-12″> Organization Code: <InputText id=”organizationCode” @bind-Value=”_customer.OrganizationCode” /> </div> <div class=”mt-2 col-md-12″> <button type=”submit”>Submit</button> </div> </EditForm> @code { private Customer _customer = new Customer(); private EditContext editContext; protected override void OnInitialized() { editContext = new(_customer); editContext.SetFieldCssClassProvider(new CustomFieldCssClassProvider()); } private void Submit() { …….. . . } } View Sample in GitHub
How do I use NPM packages in Blazor WebAssembly?
To use .npm packages in a Blazor WebAssembly application, follow these steps: Create a Blazor WebAssembly application in Visual Studio 2019 using this link. Right-click on the application and create a new folder named npm_packages. Open the npm_packages folder directory via command prompt and run the following command to initialize NPM in the application. npm init -y Once the command is executed, it will create a new package.json file in the npm_packages directory. Continue in the command prompt by executing the following command to install a JavaScript bundler named webpack and its CLI as development dependencies. npm install webpack webpack-cli –save-dev Finally, install the required .npm package. In this demo, we installed Syncfusion Maps by running the following command. npm install @syncfusion/ej2-maps Within the npm_packages folder, create a new folder called src, and then a JavaScript file called index.js. Include the build script for the package.json file, as shown in the following, which uses webpack to bundle the JavaScript file. This script tells webpack to use the index.js file in the src folder as the source file. The output directory of the bundled file is then set to be created under the js folder in the wwwroot folder directory as index.bundle.js. { “name”: “npm_packages”, “version”: “1.0.0”, “description”: “”, “main”: “index.js”, “scripts”: { “build”: “webpack ./src/index.js –output-path ../wwwroot/js –output-filename index.bundle.js –mode=development” }, “keywords”: [], “author”: “”, “license”: “ISC”, “devDependencies”: { “webpack”: “^5.58.1”, “webpack-cli”: “^4.9.0” }, “dependencies”: { “@syncfusion/ej2-maps”: “^19.3.44” } } Navigate to the Index.razor page and insert a div tag with the id set as element to display the Syncfusion Maps component. [Index.razor] @page “/” <h1>NPM Packages Demo</h1> <div id=”element”></div> In the index.js file, import and declare the Syncfusion Maps component. Finally, the component is appended to the div tag with the id set as element in the Index.razor page.[index.js] import { Maps } from ‘@syncfusion/ej2-maps’; const map = new Maps({ layers: [ { layerType: “OSM” } ] }); map.appendTo(‘#element’); Modify the index.html file with the following code to help Blazor inject a script after it starts. Note: This step is primarily for including the Syncfusion Maps component; if you’re using something else, you can skip it. [index.html] <!DOCTYPE html> <html> <head> <title>NPM_Demo</title> <link href=”css/bootstrap/bootstrap.min.css” rel=”stylesheet” /> <link href=”css/app.css” rel=”stylesheet” /> </head> <body> ……………….. <script src=”_framework/blazor.webassembly.js” autostart=”false”></script> <script> Blazor.start().then(function () { var customScript = document.createElement(‘script’); customScript.setAttribute(‘src’, ‘js/index.bundle.js’); document.head.appendChild(customScript); }); </script> </body> </html> Add a prebuild step to the *.csproj file that will run the .npm commands whenever you compile or build the application. [.csproj] <Project Sdk=”Microsoft.NET.Sdk.BlazorWebAssembly”> ……………………….. <Target Name=”PreBuild” BeforeTargets=”PreBuildEvent”> <Exec Command=”npm install” WorkingDirectory=”npm_packages” /> <Exec Command=”npm run build” WorkingDirectory=” npm_packages ” /> </Target> </Project> Run the sample to see the demonstration.
How do you style Blazor components with SCSS?
SCSS, also known as Sassy CSS, is a CSS advancement that includes advanced features. It is more expressive, loads faster, uses fewer lines of code, and encourages proper rule nesting. It has all of the features of CSS and more, making it a good choice for developers to use. It is an SASS-specific file, similar to CSS, but with improved formatting. To style your Blazor components with SCSS, follow these steps: Create a Blazor WebAssembly application by referring to this link. Create a new folder named TowerRange, and inside it, create TowerRange.razor, a new Blazor component, and define it as shown. [TowerRange.razor] <div class=”tower”> <div class=”tower-range @BackgroundStyle” style=”height: @Height” aria-valuenow=”@CurrentValue” aria-valuemin=”0″ aria-valuemax=”80″> </div> </div> @code { [Parameter] public int CurrentValue { get; set; } [Parameter] public BackgroundColor Color { get; set; } = BackgroundColor.LightGrey; public enum BackgroundColor { LightGrey, MediumGrey, DarkGrey } private string BackgroundStyle => $”BackColor-{Color.ToString()}”; private string Height => $”{CurrentValue}%”; } Create a new SCSS file named TowerRange.scss inside the TowerRange folder and specify the style required for the TowerRange component as shown in the following. [TowerRange.scss] .tower { width: 15px; height: 200px; background-color: #fff; position: relative; } .tower-range { width: 100%; display: block; font-family: arial; font-size: 12px; background-color: white; color: #fff; position: absolute; bottom: 0; } $BackColor-LightGrey: #d4d3d2; $BackColor-MediumGrey: #8f9194; $BackColor-DarkGrey: #585959; .BackColor { &-LightGrey { background-color: $BackColor-LightGrey; } &-MediumGrey { background-color: $BackColor-MediumGrey; } &-DarkGrey { background-color: $BackColor-DarkGrey; } } Add the following code in the Helper.scss in the Shared folder to provide custom styles for the TowerRange component’s appearance in the Index.razor main page. [Helper.scss] .marginStyle { margin-left: 2px; display: inline-block; } To combine all SCSS files, create an App.scss file in the main application and add the following code. [App.scss] @import ‘TowerRange/TowerRange’; @import ‘Shared/Helper’; Now, follow this link to install the Web Compiler extension and restart Visual Studio. After restarting, right-click App.css and select Web Compiler > Compile File. The compilerconfig.json file will be generated under the main application. Add the following code to the compilerconfig.json file. [ { “outputFile”: “wwwroot/css/site.css”, “inputFile”: “App.scss”, “minify”: { “enabled”: true }, “options”: { “sourceMap”: true } } ] Insert the site.css file created by the Web Compiler into the index.html page. <head> ……………………. <link href=”css/site.css” rel=”stylesheet” /> </head> To run Web Compiler during the build action (F5), install a NuGet package, or right-click compilerconfig.json and select Web Compiler > Enable compile on build, which automatically installs this NuGet package. <Project Sdk=”Microsoft.NET.Sdk.BlazorWebAssembly”> ……………………. ……………………. <ItemGroup> <Content Remove=”compilerconfig.json” /> </ItemGroup> <ItemGroup> <None Include=”compilerconfig.json” /> </ItemGroup> <ItemGroup> <PackageReference Include=”BuildWebCompiler” Version=”1.12.394″ /> <PackageReference Include=”Microsoft.AspNetCore.Components.WebAssembly” Version=”5.0.10″ /> <PackageReference Include=”Microsoft.AspNetCore.Components.WebAssembly.DevServer” Version=”5.0.10″ PrivateAssets=”all” /> <PackageReference Include=”System.Net.Http.Json” Version=”5.0.0″ /> </ItemGroup> </Project> Add the TowerRange component to the Index.razor page, as shown in the following. @page “/” @using SCSS.TowerRange; <h1> Blazor component styling with SCSS </h1> <div class=”marginStyle”> <TowerRange CurrentValue=”20″ Color=”TowerRange.BackgroundColor.DarkGrey” /> </div> <div class=”marginStyle “> <TowerRange CurrentValue=”40″ Color=”TowerRange.BackgroundColor.MediumGrey” /> </div> <div class=”marginStyle “> <TowerRange CurrentValue=”60″ Color=”TowerRange.BackgroundColor.LightGrey” /> </div> When you run the application, you will see the following output.