ASP.NET Core MVC validate not required fields - asp.net-mvc

My page is validating a field that is not required when I submit, even though there is no validation configured for this field.
Create.cshtml
#model Lawtech.App.ViewModels.ProcessoViewModel
#{
ViewData["Title"] = "Novo processo";
}
<h3 style="padding-top: 10px">#ViewData["Title"] </h3>
<hr />
<div class="row">
<div class="col-md-12">
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="row">
<div class="form-group col-md-4">
<label asp-for="Numero" class="control-label"></label>
<input asp-for="Numero" class="form-control" />
<span asp-validation-for="Numero" class="text-danger"></span>
</div>
<div class="form-group col-sm-4">
<label asp-for="IdArea" class="control-label"></label>
<div class="input-group">
<select id="slcArea" asp-for="IdArea" class="form-control select2"></select>
<div class="input-group-btn">
<a asp-action="CreateArea" class="btn btn-info" style="border-radius:0 0.25rem 0.25rem 0" data-modal="">
<span class="fa fa-plus"></span>
</a>
</div>
</div>
</div>
</div>
<div class="row">
<div class="form-group col-md-6 mt-4">
<input type="submit" value="Cadastrar" class="btn btn-sm btn-primary" />
<a class="btn btn-sm btn-info" asp-action="Index">Voltar</a>
</div>
</div>
</form>
</div>
</div>
<div id="myModal" class="modal fade in">
<div class="modal-dialog">
<div class="modal-content">
<div id="myModalContent"></div>
</div>
</div>
</div>
ViewModel
public class ProcessoViewModel
{
[Key]
public int Id { get; set; }
[DisplayName("Número")]
[Required(ErrorMessage = "O campo número é obrigatório")]
public string Numero { get; set; }
[DisplayName("Área")]
public int IdArea { get; set; }
}
Controller
In Controller Create method, nothing happens, because all validation takes place on the client side.
[Route("novo-processo")]
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(ProcessoViewModel processoViewModel)
{
try
{
if (!ModelState.IsValid) return View(processoViewModel);
await _processoBLL.Insert(_mapper.Map<ProcessoDTO>(processoViewModel));
if (!ValidOperation()) return View(processoViewModel);
return RedirectToAction(nameof(Index));
}
catch
{
return View();
}
}
Inspecting in Chrome I see this generated html for the field that I didn't require validation, I don't know if it could be something related to Jquery.Unobtrusive but I can't remove it either because other fields will be validated.
<select id="slcArea" class="form-control select2 select2-hidden-accessible input-validation-error" data-val="true" data-val-required="The Área field is required." name="IdArea" data-select2-id="slcArea" tabindex="-1" aria-hidden="true" aria-describedby="slcArea-error" aria-invalid="true"></select>
Why is this validation taking place that I have not defined the field as required?

Not nullable properties (that is properties with value types) are always required. Use nullable types (reference types) for properties if they should not be required - eg. int?.

You can always use formnovalidate on any input you don't want validated.
<input asp-for="Numero" formnovalidate="formnovalidate" class="form-control" />
This way there is no need to change your model. This is demonstrated at W3Schools

Related

Is it possible to generate new instances of the same form by clicking a button?

I'm working on a use case in my animal shelter web application where customers are able to register one or more animals at the same time. Ideally I'd like a button on the bottom left that generates another instance of the same form when clicked, so that multiple animal registrations can be saved to the database at once.
NewAnimalRegistration.cshtml:
#model NewAnimalRegistrationViewModel
<html>
<head>
<title>Register an animal</title>
<link rel="stylesheet" href="~/css/style.css"/>
</head>
<body>
<div class="container py-5">
<div class=" row">
<div class="col-md-10" mx-auto>
<div asp-validation-summary="All"></div>
<h1>Animal registration</h1>
<p>
We are happy to hear that you are interested in placing your animal in our shelter. Please fill in the fields below and our system will
check if there is room for your animal.
</p>
<form asp-action="RegistrationForm" method="post">
<div class="form-group row mt-5">
<div class="col-sm-6">
<label asp-for="Name">Name</label>
<input asp-for="Name" class="form-control"/>
</div>
</div>
<div class="form-group row mt-5">
<div class="col-sm-4">
<label asp-for="Gender" class="mr-3">Gender</label>
<select class="form-group" asp-for="Gender" asp-items="#ViewBag.Genders"></select>
</div>
<div class="col-sm-4">
<label asp-for="Type" class="mr-3">Animal type</label>
<select class="form-group" asp-for="Type" asp-items="#ViewBag.AnimalTypes"></select>
</div>
<div class="col-sm-4">
<label>Neutered</label>
<div class="form-check">
<input asp-for="IsNeutered" class="form-check-input" type="radio" value="true">
<label class="form-check-label" asp-for="IsNeutered">
Yes
</label>
</div>
<div class="form-check">
<input asp-for="IsNeutered" class="form-check-input" type="radio" value="false">
<label class="form-check-label" asp-for="IsNeutered">
No
</label>
</div>
</div>
</div>
<div class="form-group mt-5">
<label asp-for="Reason">Why are you deciding to put this animal up for adoption?</label>
<textarea class="form-control" asp-for="Reason" rows="6"></textarea>
</div>
<div class="float-right">
<a asp-controller="Home" asp-action="Index" class="btn btn-primary px-4">Cancel</a>
<button class="btn btn-primary px-4">Save</button>
</div>
</form>
</div>
</div>
</div>
</body>
</html>
Is there a way to do this in .NET Core MVC? If yes, will I simply receive a list of all animal registrations through which I can simply loop and add them all to the database?
I made a demo based on your description, you can refer to it:
Model:
public class NewAnimalRegistrationViewModel
{
public int Id { get; set; }
public string Name { get; set; }
public string Gender { get; set; }
public string Type { get; set; }
public bool IsNeutered { get; set; }
public string Reason { get; set; }
}
Index.cshtml:
#model NewAnimalRegistrationViewModel
<html>
<head>
<title>Register an animal</title>
</head>
<body>
<div class="container py-5">
<div class=" row">
<div class="col-md-10" mx-auto>
<div asp-validation-summary="All"></div>
<h1>Animal registration</h1>
<p>
We are happy to hear that you are interested in placing your animal in our shelter. Please fill in the fields below and our system will
check if there is room for your animal.
</p>
<form asp-action="RegistrationForm" method="post">
<div class="float-right">
<a asp-controller="Home" asp-action="Index" class="btn btn-primary px-4">Cancel</a>
<button class="btn btn-primary px-4">Save</button>
</div>
</form>
<a id="add" href='#' class="text-danger">register another animal</a>
</div>
</div>
</div>
</body>
</html>
#section scripts{
<script>
var count = 0;
$(function () {
var actionUrl = "/Home/AddRegistrationForm?count=" + count;
$.get(actionUrl).done(function (data) {
$('body').find('.float-right').before(data);
});
})
$("#add").on("click", function (e) {
e.preventDefault();
count++;
var actionUrl = "/Home/AddRegistrationForm?count=" + count;
$.get(actionUrl).done(function (data) {
$('body').find('.float-right').before(data);
});
})
</script>
}
_RegisterPartial.cshtml:
#model NewAnimalRegistrationViewModel
#{
int i = ViewBag.Count;
}
<h3>Anaimal #i</h3>
<div class="form-group row mt-5">
<div class="col-sm-6">
<label asp-for="Name">Name</label>
<input asp-for="Name" name="[#i].Name" class="form-control" />
</div>
</div>
<div class="form-group row mt-5">
<div class="col-sm-4">
<label asp-for="Gender" class="mr-3">Gender</label>
<select class="form-group" asp-for="Gender" name="[#i].Gender" asp-items="#ViewBag.Genders"></select>
</div>
<div class="col-sm-4">
<label asp-for="Type" class="mr-3">Animal type</label>
<select class="form-group" asp-for="Type" name="[#i].Type" asp-items="#ViewBag.AnimalTypes"></select>
</div>
<div class="col-sm-4">
<label>Neutered</label>
<div class="form-check">
<input asp-for="IsNeutered" name="[#i].IsNeutered" class="form-check-input" type="radio" value="true">
<label class="form-check-label" asp-for="IsNeutered">
Yes
</label>
</div>
<div class="form-check">
<input asp-for="IsNeutered" name="[#i].IsNeutered" class="form-check-input" type="radio" value="false">
<label class="form-check-label" asp-for="IsNeutered">
No
</label>
</div>
</div>
</div>
<div class="form-group mt-5">
<label asp-for="Reason">Why are you deciding to put this animal up for adoption?</label>
<textarea class="form-control" asp-for="Reason" name="[#i].Reason" rows="6"></textarea>
</div>
Controller:
public IActionResult Index()
{
return View();
}
[HttpGet]
public IActionResult AddRegistrationForm(int count)
{
ViewBag.Count = count;
ViewBag.Genders = new List<SelectListItem>
{
new SelectListItem{ Text = "Female", Value="Female"},
new SelectListItem{ Text = "Male", Value="Male"}
};
ViewBag.AnimalTypes = new List<SelectListItem>
{
new SelectListItem{ Text = "Cat", Value="Cat"},
new SelectListItem{ Text = "Dog", Value="Dog"}
};
return PartialView("_RegisterPartial");
}
[HttpPost]
public IActionResult RegistrationForm(List<NewAnimalRegistrationViewModel> model)
{
return View();
}
Result:

Get request from RazorPage with ViewComponent

I tray use ViewComponent in Razor Page with condition,
and each Viewcomponents are separate,
My razorpage is "/Subfolder/Index.cshtml"
<div class="row">
<div class="col-md-4">
#await Component.InvokeAsync("RightMenu")
</div>
<div class="col-md-8">
#if (Model.SIndex != 0)
{
#await Component.InvokeAsync("SubContent", new { id = Model.SIndex })
}
#if (Model.SIndex == 15)
{
<div class="row">
<div class="col-md-12">
<form method="post">
#await Component.InvokeAsync("QuestionUs", new { askLibrarian = new Lib.Model.AskLibrarian() })
<div class="form-group">
<input type="submit" value="ask Question" class="btn btn-default" asp-page-handler="question" />
</div>
</form>
</div>
</div>
}
</div>
and code behind of this is "/subfolder/index.cshtml.cs"
public class IndexModel : PageModel
{
private readonly Lib.Model.LibContext _context;
[BindProperty]
public int SIndex { get; set; }
public async Task OnGet(int Id)
{
SIndex = Id;
}
[BindProperty]
public AskLibrarian AskLibrarian { get; set; }
public async Task<IActionResult> OnPostquestionAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
_context.AskLibrarians.Add(AskLibrarian);
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
}
Now "questionViewcomponent" is a simple form that show many input elements
in "/subfolder/component/questionus/default.cshtml"
#model Lib.Model.AskLibrarian
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-row">
<div class="form-group col-md-6">
<label asp-for="FullName" class="control-label"></label>
<div class="input-group mb-2 mr-sm-2">
<div class="input-group-prepend">
<div class="input-group-text"><i class="fas fa-user"></i></div>
</div>
<input asp-for="FullName" class="form-control" />
<span asp-validation-for="FullName" class="text-danger"></span>
</div>
</div>
<div class="form-group col-md-6">
<label asp-for="Email" class="control-label"></label>
<div class="input-group mb-2 mr-sm-2">
<div class="input-group-prepend">
<div class="input-group-text"><i class="fas fa-envelope"></i></div>
</div>
<input asp-for="Email" class="form-control" />
<span asp-validation-for="Email" class="text-danger"></span>
</div>
</div>
</div>
<div class="form-row">
<div class="form-group col-md-4">
<label asp-for="LibraryNameId" class="control-label"></label>
<div class="input-group mb-2 mr-sm-2">
<div class="input-group-prepend">
<div class="input-group-text"><i class="fas fa-book"></i></div>
</div>
<select asp-for="LibraryNameId" class="form-control" asp-items="ViewBag.LibraryNameId"></select>
</div>
</div>
<div class="form-group col-md-8">
<label asp-for="Subject" class="control-label"></label>
<div class="input-group mb-2 mr-sm-2">
<div class="input-group-prepend">
<div class="input-group-text"><i class="fas fa-book-reader"></i></div>
</div>
<input asp-for="Subject" class="form-control" />
<span asp-validation-for="Subject" class="text-danger"></span>
</div>
</div>
</div>
<div class="form-group">
<label asp-for="Text" class="control-label"></label>
<textarea asp-for="Text" class="form-control" style="min-height:250px;"></textarea>
<span asp-validation-for="Text" class="text-danger"></span>
</div>
set breakpoint on "OnpostQuestionAsync", When I click on submit button with "question" handler do nothing and show me a blank page instead question form.
how can I resolve That
After a long Time my problem resolved by remove
<input type="submit" value="ask Question" class="btn btn-default" asp-page-handler="question" />
and add in form tag
<form method="post" sp-page-handler="question">

Input validation generating data-* attributes ONLY on Primary key and checkbox type input tags

I've created a sample ASP.NET MVC Core 1.1 web app created using VS2015-Update3. It generates input tags with data -* attributes only on a model property that is a Primary Key, and on a property that is of type bool. For instance, in the following example the generated html (shown below) is showing the data-attributes only on the input tag generated for properties MyEntityId and Prop2 of the model. NOTE: I'm using the default ASP.NET Core Web Application template that automatically installs Jquery, Bootstrap, etc.
Model:
public class MyEntity
{
public int MyEntityId { get; set; }
public string Prop1 { get; set; }
[Column(TypeName = "char(2)")]
[RegularExpression(#"^[0-9]{2,2}$", ErrorMessage = "Must enter two digit numbers"), StringLength(2)]
public string TestCode { get; set; }
public DateTime? StartDate { get; set; }
public bool Prop2 { get; set; }
}
View
<form asp-controller="TestController" asp-action="TestAction" method="post" class="form-horizontal">
<div asp-validation-summary="All" class="text-danger"></div>
<div><input type="hidden" asp-for="MyEntityId" /></div>
<div class="form-group">
<label asp-for="Prop1" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="Prop1" class="form-control" style="margin-top:15px;" />
<span asp-validation-for="Prop1" class="text-danger"></span>
</div>
</div>
<div class="form-group">
<label asp-for="TestCode" class="col-md-2 control-label"></label>
<div class="col-md-2">
<input asp-for="TestCode" class="form-control" />
<span asp-validation-for="TestCode" class="text-danger"></span>
</div>
</div>
<div class="form-group">
<label asp-for="StartDate" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="StartDate" type="date" class="form-control" />
<span asp-validation-for="StartDate" class="text-danger"></span>
</div>
</div>
<div class="form-group">
<label asp-for="Prop2" class="col-md-2 control-label"></label>
<div class="col-md-1">
<input asp-for="Prop2" class="form-control" style="zoom:0.5;margin-top:25px;" />
<span asp-validation-for="Prop2" class="text-danger"></span>
</div>
</div>
<button type="submit" name="submit" value="testVal">Save</button>
</form>
Generated Html:
<div><input type="hidden" data-val="true" data-val-required="The MyEntityId field is required." id="MyEntityId" name="MyEntityId" value="54321"></div>
<div class="form-group">
<label class="col-md-2 control-label" for="StateName">Prop1</label>
<div class="col-md-2">
<input class="form-control" readonly="" type="text" id="Prop1" name="Prop1" value="TestVal">
<span class="text-danger field-validation-valid" data-valmsg-for="Prop1" data-valmsg-replace="true"></span>
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label" for="TestCode">TestCode</label>
<div class="col-md-2">
<input class="form-control" type="text" id="TestCode" name="TestCode" value="">
<span class="text-danger field-validation-valid" data-valmsg-for="TestCode" data-valmsg-replace="true"></span>
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label" for="StartDate">Start Date</label>
<div class="col-md-10">
<input type="date" class="form-control" id="StartDate" name="StartDate" value="2015-10-01">
<span class="text-danger field-validation-valid" data-valmsg-for="StartDate" data-valmsg-replace="true"></span>
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label" for="Prop2">Test Prop2</label>
<div class="col-md-1">
<input class="form-control" data-val="true" data-val-required="Test Prop2 is required." id="Prop2" name="Prop2" style="zoom:0.5;margin-top:25px;" type="checkbox" value="true">
<span class="text-danger field-validation-valid" data-valmsg-for="Prop2" data-valmsg-replace="true"></span>
</div>
</div>
I'm assuming your issue is that TestCode does not have validation on it, despite having both RegularExpression and StringLength attributes applied. MyEntityId and Prop2 are non-nullable, so there's an implicit required validation for those, while Prop1 and StartDate are nullable and do not have any explicit validation applied. As a result, those are rightly not validated.
TestCode is weird, though. I'm not sure you'd actually get data-* attributes, as both the regular expression and string length can be satisfied using the HTML attributes pattern and maxlength, respectively. But, you should then have pattern and maxlength applied to the input for TestCode which is not the case.
According to the docs, the code you have should work, and at the least, it seems that StringLength is applied via data-val-maxlength rather than (or perhaps in addition to) using the maxlength attribute. There's either some bug at play, or there's something else in your codebase that is preventing the correct behavior from occurring. However, without more code, it's impossible to say.

Creating register method for mvc

Made a small front end for the register page, not sure how to actually register users in the mongodb. CRUD methods are written, the question is how to take parameters from the view's text boxes and parse it all the way to the data layer? This is my button for the submit register form:
<div class="form-group">
<input ="Submit" id="Padding" value="Sign up" class="btn btn-primary" />
or cancel
</div>
User controller is empty for now. Not sure if in MVC I can use onClick="" method for the button, probably not, because there is no code behind file. At first I thought that somehow I should be able to call the Padding.Click() or whatever method, but it doesn't seem to be a right way.
Use strongly typed data binding for posting data from view to controller like:
POCO
public class RegisterUser
{
[Required]
[EmailAddress]
[Display(Name = "Email")]
public string Email { get; set; }
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
[DataType(DataType.Password)]
[Display(Name = "Confirm password")]
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
public string ConfirmPassword { get; set; }
}
Register.cstml
<form asp-controller="Account" asp-action="Register" method="post" class="form-horizontal" role="form">
<h4>Create a new account.</h4>
<hr />
<div asp-validation-summary="ValidationSummary.All" class="text-danger"></div>
<div class="form-group">
<label asp-for="Email" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="Email" class="form-control" />
<span asp-validation-for="Email" class="text-danger"></span>
</div>
</div>
<div class="form-group">
<label asp-for="Password" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="Password" class="form-control" />
<span asp-validation-for="Password" class="text-danger"></span>
</div>
</div>
<div class="form-group">
<label asp-for="ConfirmPassword" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="ConfirmPassword" class="form-control" />
<span asp-validation-for="ConfirmPassword" class="text-danger"></span>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<button type="submit" class="btn btn-default">Register</button>
</div>
</div>
Controller's Action method
public IActionResult Register(RegisterUser model)
{
//send data to data layer and then can be inserted into mongodb or may be in some other databases
}
I don't know what are you trying to achieve. But first let's correct your html/
<input ="Submit" id="Padding" value="Sign up" class="btn btn-primary" />
should be
<input type="Submit" id="Padding" value="Sign up" class="btn btn-primary" />
You are missing the type attribute in your button. Now you html is correct.
Next: You can use onclick() on your button as below:
<input type="Submit" id="Padding" value="Sign up" onclick="Your_Javascript_Function()" class="btn btn-primary" />

Unobtrusive JQuery Validation not working in popup PartialViews [duplicate]

This question already has an answer here:
Required field validations not working in JQuery Popup MVC 4
(1 answer)
Closed 7 years ago.
I have the following a partial view in asp.net 5 mvc 6 project. The partial view is shown as a jquery ui dialog and is loaded dynamically when the user clicks a button in the parent view page.The issue is that the Unobtrusive JQuery Validation does not work after I enter invalid entires and clicked submit.
I have done all the procedures needed to make Unobtrusive JQuery Validation work and it works in Non partial views.
Here is my code
my partial view name EquipmentEditTemplate.cshtml
#model MyProject.Models.EquipmentViewModel
#*<form role="form" name="FormPost" asp-controller="Asset" method="post" asp-action="SaveEq" data-ajax="true" id="FrmGrid_grdLocation1" class="FormGrid form-horizontal" style="width:477px;height:703px;">*#
#*<form asp-controller="Asset" asp-action="SaveEq" method="post" style="width:600px;height:703px;" class="form-horizontal" >*#
<div class="FormError bg-danger" style="display:none;"></div><div class="tinfo topinfo"></div><div class="modal-body">
<div style="margin-left:15px;">
<div class="form-group">
<label asp-for="EquipmentID" class="col-sm-2 control-label">Equipment ID:</label>
<div class="col-sm-10">
<input asp-for="EquipmentID" class="FormElement form-control" />
<span asp-validation-for="EquipmentID" class="text-danger"></span>
</div>
</div>
<div class="form-group">
<label asp-for="Email" class="col-sm-2 control-label">Email:</label>
<div class="col-sm-10">
<input asp-for="Email" class="FormElement form-control" />
</div>
</div>
<div class="form-group">
<label asp-for="Department" class="col-sm-2 control-label">Department:</label>
<div class="col-sm-10">
<input type="text" id="Department" name="Department" value="#Model.Department" role="textbox" class="FormElement form-control">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-default">Sign in</button>
</div>
</div>
</div>
</form>
I have the code below in the main view as shown I have included the validation scripts in there equipment.cshtml
#{
ViewData["Title"] = "Equipment";
}
<h2>#ViewData["Title"].</h2>
<h3>#ViewData["Message"]</h3>
#section scripts{
#{await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
<script src="~/js/equipment.js" type="text/javascript"></script>
}
I have my model class defined as follows
public class EquipmentViewModel
{
[Required]
public int EquipmentID { get; set; }
[EmailAddress]
public string Email{ get; set; }
public int Description{ get; set; }
}
}
When you've loaded a form in to your DOM dynamically then add the below line at the end of your partial view.
$(document).ready(function() {
$.validator.unobtrusive.parse($('#yourform'));
});

Resources