Blazor client WASM form validation in component not working - .net-core

Im having trouble getting from validation to work properly in a Blazor WASM client application.
Encapsulating an InputText element to a component for compact layout does no longer perform validation that is executed correctly otherwise.
using model like
public class Customer {
[Required]
[StringLength(100)
public string customerName {get; set;} = "";
}
in a form of
<EditForm Model=#customer>
<DataAnnotationsValidator />
<ValidationSummary />
<div class="form-row">
<div class="form-group mb-0 col-sm-12">
<div class="input-group input-group-sm mb-1 mt-1">
<div class="input-group-prepend">
<span class="input-group-text" style="width:6em;">Firma</span>
</div>
<InputText type="text" class="form-control" #bind-Value=customer.customerName />
</div>
</div>
</EditForm>
the validation works fine!
But to modularize I outsource the inner stuff to an separate component
#page "/inputGroup"
<div class="input-group input-group-sm mb-1 mt-1">
<div class="input-group-prepend">
<span class="input-group-text" style="width:6em;">#label</span>
</div>
<InputText type=#type class="form-control" #bind-Value=#data #oninput=#onChange />
</div>
#code {
[Parameter]
public string label {get; set;} = "Label:";
[Parameter]
public string type {get; set;} = "text";
[Parameter]
public string data {get; set;} = "";
[Parameter]
public EventCallback<string> dataChanged {get; set;}
private Task onChange(ChangeEventArgs e) {
data = (string)e.Value;
return dataChanged.InvokeAsync(data);
}
}
Then I put this to my form, like
...
<div class="form-row">
<div class="form-group mb-0 col-sm-12">
<InputGroup label="Firma:" #bind-data=customer.customerName />
</div>
</div>
...
the validation is not working!?

You could do something like this where you subclass InputText
InputTextGroup.razor
#inherits Microsoft.AspNetCore.Components.Forms.InputText
<div class="mt-1">
<input type="text" id="#Id"
#attributes="#AdditionalAttributes" #bind="#CurrentValueAsString"
class="#CssClass myOtherCssClasses" />
</div>
#if (ValidationFor != null)
{
<div class="myValidationClass">
<ValidationMessage For="ValidationFor" />
</div>
}
And InputTextGroup.razor.cs
public partial class InputTextGroup
{
[Parameter] public string Id { get; set; } = HeadlessUI.HtmlElement.GenerateId();
[Parameter] public string? Label { get; set; }
[Parameter] public Expression<Func<string>>? ValidationFor { get; set; }
}
I took inspiration from this SO answer and this Microsoft docs

Related

How to make selection (choose one of the two strings with select input in html) with Entity Framework?

I want to make the user only choose between two strings, Internal or Consigned, to be inserted into the InternalConsigned column of a database. How do I do that?
This is my current code:
Equipment.cs model class:
public class Equipment
{
[Key]
public int Id { get; set; }
[Required]
[DisplayName("Equipment Name")]
public string Name { get; set; }
[Required]
public int Amount { get; set; }
[Required]
public string Status { get; set; }
[ForeignKey("DepartmentId")]
public int DepartmentId { get; set; }
public Department? Department { get; set; }
[Required]
public string InternalConsigned { get; set; }
public DateTime EOLDate { get; set; }
}
Create action method:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("Id,Name,Amount,Status,DepartmentId,InternalConsigned,EOLDate")] Equipment equipment)
{
if (ModelState.IsValid)
{
_context.Add(equipment);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
ViewData["DepartmentId"] = new SelectList(_context.Departments, "Id", "Name", equipment.DepartmentId);
return View(equipment);
}
Create.cshtml:
#model Equipment
#{
ViewData["Title"] = "Create";
}
<h4>Equipment</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Name" class="control-label"></label>
<input asp-for="Name" class="form-control" />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Amount" class="control-label"></label>
<input asp-for="Amount" class="form-control" />
<span asp-validation-for="Amount" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Status" class="control-label"></label>
<input asp-for="Status" class="form-control" />
<span asp-validation-for="Status" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="DepartmentId" class="control-label"></label>
<select asp-for="DepartmentId" class ="form-control" asp-items="ViewBag.DepartmentId"></select>
</div>
<div class="form-group">
<label asp-for="InternalConsigned" class="control-label"></label>
<input asp-for="InternalConsigned" class="form-control" />
<span asp-validation-for="InternalConsigned" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="EOLDate" class="control-label"></label>
<input asp-for="EOLDate" class="form-control" />
<span asp-validation-for="EOLDate" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
I know I have to use the select tag in the View, but I'm not sure what to write in the Controller.
If I don't misunderstand your question, You want to write a dropdown list with two options Internal or Consigned, So you can refer to this simple demo, Hope it can help you.
List<SelectListItem> test = new List<SelectListItem>();
test.Add(new SelectListItem { Text = "Internal ", Value = "Internal " });
test.Add(new SelectListItem { Text = "Consigned", Value = "Consigned" });
ViewData["demo"] = test;
Then in the view:
<select asp-for="InternalConsigned" asp-items="#ViewBag.demo"></select>
Demo:

Some model properties always null on post, modelbinding issue

I am making a part of a website where you can update your profile. The profile is tied to the user which is an extension of Microsofts Identity.
The problem is that LastName and FirstName is always null after making a post request.
I would like to think that if this was a ModelState error I would have caught it through !ModelState.IsValid.
https://i.gyazo.com/eea1e3465427eba5a731947473fca821.mp4
Model
using Microsoft.AspNetCore.Identity;
using System;
namespace Certificate_Wiki.Models {
public class CertificateUser : IdentityUser {
public string FirstName { get; set; }
public string LastName { get; set; }
public string Website { get; set; }
public string Occupation { get; set; }
public string Country { get; set; }
public string Description { get; set; }
public String ProfilePictureUrl { get; set; }
public Byte[] ProfilePicture { get; set; }
public bool isPrivate { get; set; }
}
}
cshtml
#{
ViewData["Title"] = "Edit Profile";
}
#model Certificate_Wiki.Models.CertificateUser
<link rel="stylesheet" href="~/css/pages/ProfileEdit.css" media="all" />
<div class="background"></div>
<div class="content">
<div class="content-image">
<img src="~/images/profile/Component 1 – 1.png" alt="" />
</div>
<div class="content-profile">
<div class="profile-image">
<img src="https://www.pngitem.com/pimgs/m/78-786293_1240-x-1240-0-avatar-profile-icon-png.png" alt="error loading image" />
</div>
<div class="profile-form">
<h2>#User.Identity.Name</h2>
<div asp-validation-summary="All">
</div>
<form asp-action="Edit" method="post">
<div class="form-row">
<label>First Name</label>
<input asp-for="FirstName" type="text" name="name" />
</div>
<div class="form-row">
<label>Last Name</label>
<input asp-for="LastName" type="text" name="name" />
</div>
<div class="form-row">
<label>Occupation</label>
<input asp-for="Occupation" type="text" name="occupation" />
</div>
<div class="form-row">
<label>Website</label>
<input asp-for="Website" type="url" name="website" />
</div>
<div class="form-row">
<label>Country</label>
<input asp-for="Country" type="text" name="Country" />
</div>
<div class="form-row">
<label>Profile Description</label>
<textarea asp-for="Description" type="text" name="description"></textarea>
</div>
<div class="form-row">
<label>Private Profile</label>
<input asp-for="isPrivate" type="checkbox" name="Private" />
</div>
<div class="form-row">
<button type="submit">Save</button>
</div>
</form>
</div>
</div>
</div>
Controller
[HttpGet]
[Authorize]
[Route("Profile/edit")]
public async Task<IActionResult> EditAsync()
{
var Profile = await userManager.FindByEmailAsync(User.Identity.Name);
if (Profile == null) { return View(); }
return View(Profile);
}
[ValidateAntiForgeryToken]
[HttpPost]
[Authorize]
[Route("Profile/edit")]
public async Task<IActionResult> EditAsync([FromForm]CertificateUser model)
{
//TODO
//Remove CW from single-line if
if (!ModelState.IsValid) { Console.WriteLine("Modelstate invalid"); return View(model); }
var Profile = await userManager.FindByEmailAsync(User.Identity.Name);
if (Profile == null) { return View(); }
//Update database
Profile.FirstName = model.FirstName;
Profile.LastName = model.LastName;
Profile.Description = model.Description;
Profile.Country = model.Country;
Profile.Occupation = model.Occupation;
Profile.Website = model.Website;
await userManager.UpdateAsync(Profile);
Console.WriteLine("Update success");
return RedirectToAction("Index");
}
Note, While I am at it I would also like to ask if there is a "better" or a rather clean way to update the user without profile... = model... for every property to be updated.
If you use the asp-for attribute for input box, then you shouldn't use the name attribute in the same time (or at least use the same value for it).
In your example you set FirstName for asp-for and then just name for the name attribute of the input for FirstName.

Need help making many-to-many relationships with CRUD in asp.net core

I currently have 2 models:
Movie.cs
public int MovieId { get; set; }
public Genre Genre { get; set; }
public int GenreId { get; set; }
public string MovieTitle { get; set; }
Genre.cs
public int GenreId { get; set; }
public string GenreName { get; set; }
public List<Movie> Movies;
My Create.cshtml View
<div class="row">
<div class="col-md-4">
<form asp-action="Create" enctype="multipart/form-data">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="GenreId" class="control-label"></label>
<select asp-for="GenreId" class="form-control" asp-items="ViewBag.GenreId"></select>
</div>
<div class="form-group">
<label asp-for="DirectorId" class="control-label"></label>
<select asp-for="DirectorId" class="form-control" asp-items="ViewBag.DirectorId"></select>
</div>
<div class="form-group form-check">
<label class="form-check-label">
<input class="form-check-input" asp-for="IsHot" /> #Html.DisplayNameFor(model => model.IsHot)
</label>
</div>
<div class="form-group form-check">
<label class="form-check-label">
<input class="form-check-input" asp-for="IsNew" /> #Html.DisplayNameFor(model => model.IsNew)
</label>
</div>
<div class="form-group">
<label asp-for="MovieTitle" class="control-label"></label>
<input asp-for="MovieTitle" class="form-control" />
<span asp-validation-for="MovieTitle" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="MovieLang" class="control-label"></label>
<input asp-for="MovieLang" class="form-control" />
<span asp-validation-for="MovieLang" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="MovieLink" class="control-label"></label>
<input asp-for="MovieLink" class="form-control" />
<span asp-validation-for="MovieLink" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="MoviePlot" class="control-label"></label>
<input asp-for="MoviePlot" class="form-control" />
<span asp-validation-for="MoviePlot" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="MovieImageFile" class="control-label"></label>
<input asp-for="MovieImageFile" accept="image/*" />
<span asp-validation-for="MovieImageFile" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="MovieReleaseYear" class="control-label"></label>
<input asp-for="MovieReleaseYear" class="form-control" />
<span asp-validation-for="MovieReleaseYear" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="CreateDate" class="control-label"></label>
<input asp-for="CreateDate" class="form-control" />
<span asp-validation-for="CreateDate" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="MovieTrailerLink" class="control-label"></label>
<input asp-for="MovieTrailerLink" class="form-control" />
<span asp-validation-for="MovieTrailerLink" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
so when I make a View to let Admins create a new Movie it allows them to choose from a dropdown list of Genres.
But now I want a many-to-many relationship which would allow me to add 3,4 Genres into one Movie, how do I make views and models for that?
I'm pretty sure I need to make a third model for many-to-many
relationship but I can't find an example on the internet that use it.
Yes, you need to create a third table to connect the two tables many-to-many relationship, first you need to modify your model, as follows:
public class Movie
{
[Key]
public int MovieId { get; set; }
public string MovieTitle { get; set; }
public List<MovieGenre> MovieGenres { get; set; }
}
public class Genre
{
public int GenreId { get; set; }
public string GenreName { get; set; }
public List<MovieGenre> MovieGenres { get; set; }
}
//Intermediate table
public class MovieGenre
{
public int MovieId { get; set; }
public Movie Movie { get; set; }
public int GenreId { get; set; }
public Genre Genre { get; set; }
}
You still need to determine the relationship between these three tables in OnModelCreating in the dbcontext file:
public partial class MyDbContext : DbContext
{
public MyDbContext(DbContextOptions<MyDbContext> options)
: base(options)
{
}
public DbSet<Movie> Movie { get; set; }
public DbSet<Genre> Genre { get; set; }
public DbSet<MovieGenre> MovieGenre { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<MovieGenre>()
.HasKey(bc => new { bc.MovieId, bc.GenreId });
modelBuilder.Entity<MovieGenre>()
.HasOne(bc => bc.Movie)
.WithMany(b => b.MovieGenres)
.HasForeignKey(bc => bc.MovieId);
modelBuilder.Entity<MovieGenre>()
.HasOne(bc => bc.Genre)
.WithMany(c => c.MovieGenres)
.HasForeignKey(bc => bc.GenreId);
}
}
Next, you can pass Movie object and select the list of GenreId to the controller:
View:
#model WebApplication_core_mvc.Models.Movie
#{
ViewData["Title"] = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h1>Index</h1>
<div class="row">
<div class="col-md-4">
<form asp-action="Create" enctype="multipart/form-data">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label class="control-label"></label>
<select class="form-control" asp-items="ViewBag.GenreId" name="GenreIdList" multiple></select>
</div>
<div class="form-group">
<label asp-for="MovieTitle" class="control-label"></label>
<input asp-for="MovieTitle" class="form-control" />
<span asp-validation-for="MovieTitle" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
Controller:
public class MMTestController : Controller
{
private readonly MyDbContext _context;
public MMTestController(MyDbContext context)
{
_context = context;
}
public IActionResult Index()
{
List<SelectListItem> selectListItems = _context.Genre.Select(a => new SelectListItem
{
Text = a.GenreName,
Value = a.GenreId.ToString()
}).ToList();
ViewBag.GenreId = selectListItems;
return View();
}
public IActionResult Create(Movie movie, List<int> GenreIdList)
{
_context.Movie.Add(movie);
_context.SaveChanges();
foreach (var item in GenreIdList)
{
MovieGenre movieGenre = new MovieGenre()
{
GenreId = item,
MovieId = movie.MovieId,
Genre = _context.Genre.Where(x => x.GenreId == item).FirstOrDefault(),
Movie = movie
};
_context.MovieGenre.Add(movieGenre);
}
_context.SaveChanges();
return View();
}
}
Here is the test result:

Foreach loop Null model in Razor view

I'm trying to Add values in table(Flight) which have one to many relation with table(Flight classes)
for view of flightClasses i'm using foreach loop but it comes with null model
i can't understand how to do it please help me
Flight Table will have one Row against which i want to add multiple rows in the FlightClasses Table
Flight Modle
public class FlightModel
{
public int Id { get; set; }
public string FlightName { get; set; }
public string FlightNo { get; set; }
public string OriginCity { get; set; }
public string DestinationCity { get; set; }
public DateTime Departure { get; set; }
public DateTime Arrival { get; set; }
public virtual ICollection<FlightClassesModel> FlightClasses { get; set; }
}
FlightClasses Model
public class FlightClassesModel
{
public int FlightClassesModelId { get; set; }
public type Class { get; set; }
public int AvailableSeats { get; set; }
public double Price { get; set; }
public virtual FlightModel Flight { get; set; }
public int? FlightId { get; set; }
}
public enum type
{
Business_Class,
First_Class,
Club_Class
}
View
#model Airline.Models.FlightModel
#{
ViewData["Title"] = "Create";
}
<h2>Create</h2>
<h4>FlightModel</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="FlightName" class="control-label"></label>
<input asp-for="FlightName" class="form-control" />
<span asp-validation-for="FlightName" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="FlightNo" class="control-label"></label>
<input asp-for="FlightNo" class="form-control" />
<span asp-validation-for="FlightNo" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="OriginCity" class="control-label"></label>
<input asp-for="OriginCity" class="form-control" />
<span asp-validation-for="OriginCity" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="DestinationCity" class="control-label"></label>
<input asp-for="DestinationCity" class="form-control" />
<span asp-validation-for="DestinationCity" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Departure" class="control-label"></label>
<input asp-for="Departure" class="form-control" />
<span asp-validation-for="Departure" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Arrival" class="control-label"></label>
<input asp-for="Arrival" class="form-control" />
<span asp-validation-for="Arrival" class="text-danger"></span>
</div>
#foreach (var flightClass in Model.FlightClasses)
{
<div class="form-group">
<label asp-for="#flightClass.Class" class="control-label"></label>
<select asp-for="#flightClass.Class" asp-items="Html.GetEnumSelectList<type>()"></select>
<span asp-validation-for="#flightClass.Class" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="#flightClass.AvailableSeats" class="control-label"></label>
<input asp-for="#flightClass.AvailableSeats" class="form-control" />
<span asp-validation-for="#flightClass.AvailableSeats" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="#flightClass.Price" class="control-label"></label>
<input asp-for="#flightClass.Price" class="form-control" />
<span asp-validation-for="#flightClass.Price" class="text-danger"></span>
</div>
}
<div class="form-group">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
Controller
public IActionResult Create()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(FlightModel flightModel)
{
if (ModelState.IsValid)
{
_context.Add(flightModel);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(flightModel);
}

Form Validation not working in Blazor 3.1

I am using EF to save data in DB and so far farm works fine and saves the data, but when i try to add validation to form it doesnt work & doesnt show any error message or save any data in database.
Example of working & non working code.
Below code without validation
Employee.cs
using System.ComponentModel.DataAnnotations;
namespace BlazorSPA1.Data
{
public class Employee
{
[MaxLength(50)]
public string Id { get; set; }
[MaxLength(50)]
public string Name { get; set; }
[MaxLength(50)]
public string Department { get; set; }
[MaxLength(100)]
public string Designation { get; set; }
[MaxLength(100)]
public string Company { get; set; }
[MaxLength(100)]
public string City { get; set; }
}
}
AddEmployee.razor
#page "/addemployee"
#inject NavigationManager NavigationManager
#inject IEmployeeService EmployeeService
<h2>Create Employee</h2>
<hr />
<form>
<div class="row">
<div class="col-md-8">
<div class="form-group">
<label for="Name" class="control-label">Name</label>
<input for="Name" class="form-control" #bind="#employee.Name" />
</div>
<div class="form-group">
<label for="Department" class="control-label">Department</label>
<input for="Department" class="form-control" #bind="#employee.Department" />
</div>
<div class="form-group">
<label for="Designation" class="control-label">Designation</label>
<input for="Designation" class="form-control" #bind="#employee.Designation" />
</div>
<div class="form-group">
<label for="Company" class="control-label">Company</label>
<input for="Company" class="form-control" #bind="#employee.Company" />
</div>
<div class="form-group">
<label for="City" class="control-label">City</label>
<input for="City" class="form-control" #bind="#employee.City" />
</div>
</div>
</div>
<div class="row">
<div class="col-md-4">
<div class="form-group">
<input type="button" class="btn btn-primary" #onclick="#CreateEmployee" value="Save" />
<input type="button" class="btn" #onclick="#Cancel" value="Cancel" />
</div>
</div>
</div>
</form>
#code {
Employee employee = new Employee();
protected async Task CreateEmployee()
{
await EmployeeService.CreateEmployee(employee);
NavigationManager.NavigateTo("listemployees");
}
void Cancel()
{
NavigationManager.NavigateTo("listemployees");
}
}
Code which is not working after i made validation changes
Employee.cs
using System.ComponentModel.DataAnnotations;
namespace BlazorSPA1.Data
{
public class Employee
{
[MaxLength(50)]
public string Id { get; set; }
[Required]
[StringLength(20)]
public string Name { get; set; }
[Required]
[StringLength(20)]
public string Department { get; set; }
[MaxLength(100)]
public string Designation { get; set; }
[MaxLength(100)]
public string Company { get; set; }
[MaxLength(100)]
public string City { get; set; }
}
}
AddEmployeeValidation.razor
#page "/addemployeeValidation"
#inject NavigationManager NavigationManager
#inject IEmployeeService EmployeeService
<h2>Create Employee</h2>
<hr />
<EditForm Model="#employee" OnValidSubmit="#CreateEmployee">
<DataAnnotationsValidator />
<div class="row">
<div class="col-md-8">
<div class="form-group">
<label for="Name" class="control-label">Name</label>
<input for="Name" class="form-control" #bind="#employee.Name" />
<ValidationMessage For="#(()=> employee.Name)" />
</div>
<div class="form-group">
<label for="Department" class="control-label">Department</label>
<input for="Department" class="form-control" #bind="#employee.Department" />
</div>
<div class="form-group">
<label for="Designation" class="control-label">Designation</label>
<input for="Designation" class="form-control" #bind="#employee.Designation" />
</div>
<div class="form-group">
<label for="Company" class="control-label">Company</label>
<input for="Company" class="form-control" #bind="#employee.Company" />
</div>
<div class="form-group">
<label for="City" class="control-label">City</label>
<input for="City" class="form-control" #bind="#employee.City" />
</div>
</div>
</div>
<div class="row">
<div class="col-md-4">
<div class="form-group">
<input type="button" class="btn btn-primary" value="Save" />
<input type="button" class="btn" #onclick="#Cancel" value="Cancel" />
</div>
</div>
</div>
</EditForm>
#code {
Employee employee = new Employee();
protected async Task CreateEmployee()
{
await EmployeeService.CreateEmployee(employee);
NavigationManager.NavigateTo("listemployees");
}
void Cancel()
{
NavigationManager.NavigateTo("listemployees");
}
}
I am using below code example show in this example https://www.c-sharpcorner.com/article/visual-studio-extension-for-blazor-spa-with-ef-core-3-1/
When i add validation code, it open Add Employee page but nothing happens no validation message no form submit even no data is save in database. not sure where issue is
I had made a tiny mistake which went un-noticed, Validation started working when i changed the input type to submit
<input type="button" class="btn btn-primary" value="Save" />
Correct
<input type="submit" class="btn btn-primary" value="Save" />

Resources