MVC 5 HTML helper for client side validation for value not in model - validation

I'm following the MVC tutorial here to add a search/filter textbox:
http://www.asp.net/mvc/overview/getting-started/introduction/adding-search
I've added the filter textbox to my page:
#using (Html.BeginForm()) {
<p> Title: #Html.TextBox("SearchString") <br />
<input type="submit" value="Filter" /></p>
}
How do I perform client side validation on the textbox to ensure something was entered?
When you automatically created the controller and views based on a model, it creates this handy HTML helper:
#Html.ValidationMessageFor(model => model.Name, "", new { #class = "text-danger" })
Can something similar be used for a value not in your model or do you have to add custom jquery/html?
Edit:
Thanks for the direction everyone. Just adding some more information now. I've created a new class in my existing model:
public class SearchItem
{
[Required]
[StringLength(100, MinimumLength = 5, ErrorMessage = "This is my test error message")]
public string SearchString { get; set; }
}
Then inside the controller, I've created a partial view:
[ChildActionOnly]
[AllowAnonymous]
public PartialViewResult Search()
{
return PartialView();
}
Then I've created a new Search.cshtml with:
#model App.Models.SearchItem
#using (Html.BeginForm())
{
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
<h4>#Html.LabelFor(model => model.SearchString, "Search:", htmlAttributes: new { #class = "control-label col-md-2" })</h4>
<div class="col-md-10 input-max-width">
#Html.EditorFor(model => model.SearchString, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.SearchString, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<input type="submit" value="Search" class="btn btn-primary" />
</div>
}
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
Then on my existing page, I add it with this:
#Html.Action("Search", "Items")
When I enter no text into the textbox and click the Search button, the page just refreshes and I get no client side validation.
My HTML looks like this:
<form action="/Items/Index" method="post"> <div class="form-group">
<h4><label class="control-label col-md-2" for="SearchString">Search:</label></h4>
<div class="col-md-10 input-max-width">
<input class="form-control text-box single-line" data-val="true" data-val-length="This is my test error message" data-val-length-max="100" data-val-length-min="5" data-val-required="The SearchString field is required." id="SearchString" name="SearchString" type="text" value="" />
<span class="field-validation-valid text-danger" data-valmsg-for="SearchString" data-valmsg-replace="true"></span>
</div>
</div>
<div class="form-group">
<input type="submit" value="Search" class="btn btn-primary" />
</div>

Related

Validation error working wit ASP.NET MVC .NET FRAMEWORK

your text
I added validation to my ASP.NET MVC .NET FRAMEOWRK project and get this error:
your text
Unable to cast object of type 'System.Int32' to type 'System.String'.
My project connect to data base with one table.
my code:
Customer.cs:
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated from a template.
//
// Manual changes to this file may cause unexpected behavior in your application.
// Manual changes to this file will be overwritten if the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace ConnectToDB
{
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
public partial class Customers : IValidatableObject
{
[StringLength(1000, ErrorMessage = "Queue number must be no more than 1000 digits")]
[Required(ErrorMessage = "Queue number is required")]
[DataType(DataType.Text)]
[DisplayName("Queue number")]
public int queueNumber { get; set; }
[StringLength(30, ErrorMessage = "First name must be no more tha 1000 letters")]
[RegularExpression("^[a-zA-Z]+(([',. -][a-zA-Z ])?[a-zA-Z]*)*$")] // RegEx: Used to validate a person name
[Required(ErrorMessage = "First name is required")]
[DisplayName("First name")]
[DataType(DataType.Text)]
public string firstName { get; set; }
[StringLength(30, ErrorMessage = "Last name must be no more tha 1000 letters")]
[RegularExpression("^[a-zA-Z]+(([',. -][a-zA-Z ])?[a-zA-Z]*)*$")] // RegEx: Used to validate a person name
[Required(ErrorMessage = "Last name is required")]
[DisplayName("Last name")]
[DataType(DataType.Text)]
public string lastName { get; set; }
[Required(ErrorMessage = "Time customer enter is required")]
[DisplayName("Time customer enter")]
[DataType(DataType.Time)]
public Nullable<System.TimeSpan> timeCusEnter { get; set; }
// Validation for queue number using IValidatableObject interface:
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
List<ValidationResult> errors = new List<ValidationResult>();
if (queueNumber < 0)
{
errors.Add(new ValidationResult("Queue number can not be negative.", new List<string> { "queueNumber" }));
}
return errors;
}
}
}
addCustomer.cshtml:
#model ConnectToDB.Customers
#{
ViewBag.Title = "addCustomer";
}
<link rel="stylesheet" href="~/CSS/addCusDesign.css" />
<link rel="stylesheet" href="~/CSS/Local.css" />
<body>
#*Menu:*#
<div class="navBar">
<span class="navItem">
#Html.ActionLink("Dequeue to the queue", "addCustomer")
</span>
<span class="navItem">
#Html.ActionLink("Customers list", "customersList")
</span>
</div>
<h2>Enqueue</h2>
<span id="secondTitle">Fill in the following details, then press the button and enter the queue.<br>Have a good day :)</span>
<br />
<br />
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Customers</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.queueNumber, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.queueNumber, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.queueNumber)
</div>
</div>
<br />
<div class="form-group">
#Html.LabelFor(model => model.firstName, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.firstName, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.firstName)
</div>
</div>
<br />
<div class="form-group">
#Html.LabelFor(model => model.lastName, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.lastName, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.lastName)
</div>
</div>
<br />
<div class="form-group">
#Html.LabelFor(model => model.timeCusEnter, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.timeCusEnter, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.timeCusEnter)
</div>
</div>
<br />
<br />
#Html.ValidationSummary(true, "Add customer was unsuccessful. Please coorect the following errors: ")
#*Dequeue customer to the queue input: *#
<div class="form-group">
<div class="GetInTheQueue">
<input type="submit" value="GET IN THE QUEUE" class="btn btn-default" />
</div>
</div>
</div>
}
<br />
<br />
#*Carusel in boostrap: *#
<!-- #region Carusel -->
<div id="carouselExampleFade" class="carousel slide carousel-fade" data-bs-ride="carousel">
<div class="carousel-inner">
<div class="carousel-item active">
<img src="~/Images/image1.jpeg" class="d-block w-100" alt="...">
</div>
<div class="carousel-item">
<img src="~/Images/image2.png" class="d-block w-100" alt="...">
</div>
<div class="carousel-item">
<img src="~/Images/Image3.jpeg" class="d-block w-100" alt="...">
</div>
<div class="carousel-item">
<img src="~/Images/Image4.jpeg" class="d-block w-100" alt="...">
</div>
<div class="carousel-item">
<img src="~/Images/Image5.jpeg" class="d-block w-100" alt="...">
</div>
</div>
<button class="carousel-control-prev" type="button" data-bs-target="#carouselExampleFade" data-bs-slide="prev">
<span class="carousel-control-prev-icon" aria-hidden="true"></span>
<span class="visually-hidden">Previous</span>
</button>
<button class="carousel-control-next" type="button" data-bs-target="#carouselExampleFade" data-bs-slide="next">
<span class="carousel-control-next-icon" aria-hidden="true"></span>
<span class="visually-hidden">Next</span>
</button>
</div>
<!-- #endregion -->
<br />
<br />
#*Images: *#
<!-- #region Images -->
<div class="images">
<img width="200" height="200" src="~/Images/image1.jpeg" alt="Queue image1" />
<img width="200" height="200" src="~/Images/image2.png" alt="Queue image2" />
<img width="200" height="200" src="~/Images/Image3.jpeg" alt="Queue image3" />
<img width="200" height="200" src="~/Images/Image4.jpeg" alt="Queue image4" />
<img width="200" height="200" src="~/Images/Image5.jpeg" alt="Queue image5" />
</div>
<!-- #endregion -->
</body>
Would appreciate help
The validation work for me yesterday, but today not working.

ASP.NET MVC - data validation for modal window doesn't work

In my MVC application I have simple model for project:
public class Project
{
public int Id { get; set; }
[Required]
[MinLength(5, ErrorMessage = "Project name must have at leat 5 characters")]
public string ProjectName { get; set; }
[Required]
[MinLength(10, ErrorMessage = "Project description name must have at leat 10 characters")]
public string ProjectDescription { get; set; }
public ICollection<BugTrackerUser> Users { get; set; }
public Project()
{
Users = new List<BugTrackerUser>();
}
}
On the index page I have button that triggers bootstrap modal window. As a button, modal itself located in Index.chtml, but form that belongs to this model located in partial view _addProjectPartialView:
<form method="post" id="projectForm">
<div asp-validation-summary="All" class="text-danger"></div>
<div class="form-group">
<label asp-for="ProjectName">Project Name</label>
<input asp-for="ProjectName" class="form-control" />
<span asp-validation-for="ProjectName" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="ProjectDescription">Project Description</label>
<input asp-for="ProjectDescription" class="form-control" />
<span asp-validation-for="ProjectDescription" class="text-danger"></span>
</div>
In HomeController I have this post method for adding new project:
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult AddProject(Project project)
{
if (ModelState.IsValid)
{
_repository.AddProject(project);
return RedirectToAction("Index", "Home");
}
return PartialView("_addProjectPartialView", project);
}
Logic of adding new project works fine, and I have all references that i need, jquery, jquery-validation and jquery-validation-unobtrusive, but I have problems with validation. Validation errors doesn't displays in my modal window. What can I try to solve this problem? I already read a bunch of tutorials, related questions etc, but it seems to me that there is no problems with code. I only have doubts with my return statement in AddProject method, should I return something else?
I solved this problem by removing partial view. Form that I Have in partial view and modal window I placed in Index.cshtml, also instead of asp.net tag helpers I use Html.BeginForm, and it works fine. Here is my modal:
<div class="modal fade" id="addProjectModal" tabindex="-1" aria-labelledby="addProjectModallLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered modal-lg">
<div class="modal-content">
#using (Html.BeginForm("AddProject", "Home", FormMethod.Post))
{
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Project Information</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(p => p.Id)
<div class="form-group">
#Html.LabelFor(p => p.ProjectName, htmlAttributes: new { #class = "control-label col-3" })
<div class="col-9">
#Html.TextBoxFor(p => p.ProjectName, new { #class = "form-control" })
#Html.ValidationMessageFor(p => p.ProjectName, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(p => p.ProjectDescription, htmlAttributes: new { #class = "control-label col-3" })
<div class="col-9">
#Html.TextBoxFor(p => p.ProjectDescription, new { #class = "form-control" })
#Html.ValidationMessageFor(p => p.ProjectDescription, "", new { #class = "text-danger" })
</div>
</div>
#*<partial name="_addProjectPartialView" />*#
</div>
<div class="modal-footer">
<div>
<button type="button" class="btn btn-primary" data-bs-dismiss="modal">Cancel</button>
<button type="submit" class="btn btn-primary" id="btnSave">Save</button>
</div>
</div>
}
</div>
</div>
I also using ajax post method to add projects and render list of projects async on the client side:
<script type="text/javascript">$(document).ready(function () {
$('#btnSave').click(function () {
var projectData = $('#projectForm').serialize();
$.ajax({
type: "POST",
url: "/Home/AddProject",
data: projectData,
success: function () {
window.location.href = "/Home/Index";
}
})
})
})
$('#closeButton').click(function () {
$('#addProjectModal').modal('hide');
})</script>
But I still want to understand how to solve this problem, because using partial views have some benefits
I think the problem here is , when you triggers the modal that modal doesn't have the references to (validator unobtrusive).
So try manually register this where you triggers the modal like this
$.validator.unobtrusive.parse("#idForModal");

how to use role in mvc identity 2.1.0

I want to introduce the identity role to my login page .the user after entering username and password should select a dropdownlist of roles (superuser-admin-user).how could that happen?
Create a class to manage roles, that would be something like ApplicationRoleManager
public class ApplicationRoleManager : RoleManager<IdentityRole, string>
{
public ApplicationRoleManager(IRoleStore<IdentityRole, string> roleStore)
: base(roleStore)
{
}
public static ApplicationRoleManager Create(IdentityFactoryOptions<ApplicationRoleManager> options, IOwinContext context)
{
return new ApplicationRoleManager(new RoleStore<IdentityRole, string, IdentityUserRole>(context.Get<ApplicationDbContext>()));
}
}
Then you need to create instance of ApplicationRoleManager on owin startup. Add below code inside the ConfigureAuth method on Owin startup. App_Start >> Startup.Auth.cs
app.CreatePerOwinContext<ApplicationRoleManager>(ApplicationRoleManager.Create);
Now you have all setup for manage your roles. Make sure you have added roles to your 'AspNetRoles' table
Then you can retrieve roles as below inside the Login (Get) action
// GET: /Account/Login
[AllowAnonymous]
public ActionResult Login(string returnUrl)
{
var roleManager = HttpContext.GetOwinContext().Get<ApplicationRoleManager>();
var roles = roleManager.Roles.ToList();
var list = new SelectList(roles, "Id", "Name");
ViewBag.Roles = list;
ViewBag.ReturnUrl = returnUrl;
return View();
}
Then you can get roles in the Login view. After that populate dropdownList with roles. Your rasor script will look like below.
#using (Html.BeginForm("Login", "Account", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { #class = "form-horizontal", role = "form" }))
{
#Html.AntiForgeryToken()
<h4>Use a local account to log in.</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(m => m.Email, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.TextBoxFor(m => m.Email, new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.Email, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(m => m.Password, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.PasswordFor(m => m.Password, new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.Password, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<label id="RoleDdlLabel" class="col-md-2 control-label">Select Role</label>
<div class="col-md-10">
#Html.DropDownList("RoleList", ViewBag.Roles as SelectList)
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<div class="checkbox">
#Html.CheckBoxFor(m => m.RememberMe)
#Html.LabelFor(m => m.RememberMe)
</div>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Log in" class="btn btn-default" />
</div>
</div>
<p>
#Html.ActionLink("Register as a new user", "Register")
</p>
#* Enable this once you have account confirmation enabled for password reset functionality
<p>
#Html.ActionLink("Forgot your password?", "ForgotPassword")
</p>*#
}
I hope you can finish the saving part by posting the selected role with other model values. You can change the LoginViewModel to include roles.
Hope this helps.

Ajax GET request calling POST instead (ASP.NET MVC5)

I've created an ajax GET call to perform a search feature. But every time the search button is clicked, it is calling the POST instead (thereby returning null error for the model). I am not sure what I have done wrong. Care to give a hand please?
My controller:
//
// GET: /DataEntry/ChargeBack
public ActionResult ChargeBack(string dwName, string searchTerm = null)
{
var model = createModel();
if (Request.IsAjaxRequest())
{
return PartialView("_Suppliers", model);
}
return View(model);
}
//
// POST: /DataEntry/ChargeBack
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult ChargeBack(ChargeBackViewModel model)
{
if (ModelState.IsValid)
{
model.someAction();
}
return View(model);
}
My Main View:
#model CorporateM10.Models.ChargeBackViewModel
#using (Ajax.BeginForm(
new AjaxOptions
{
HttpMethod = "get",
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "SuppliersList"
}))
{
#Html.AntiForgeryToken()
<input type="search" name="searchTerm" class="form-control col-md-2" />
<input type="submit" value="Search by Name" class="btn btn-info" />
}
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
#Html.ValidationSummary(true)
#Html.Partial("_Suppliers", Model)
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
}
My Partial View:
#model CorporateM10.Models.ChargeBackViewModel
<div class="form-group" id="SuppliersList">
<div class="col-md-10">
#Html.EditorFor(model => model.Suppliers)
#Html.ValidationMessageFor(model => model.Suppliers)
</div>
</div>
I've found it. It is being caused by not including jquery.unobtrusive-ajax library. Once included, the Ajax action works as intended.

How to add elements without reloading the page

I create view by model Article.
class Article
{
public string Title {get;set;}
public List<string> Terms {get;set}
}
Terms - can be any count, and I want that they can be added gradually
#using (Html.BeginForm("Create"))
{
#Html.ValidationSummary(true)
<fieldset>
<legend>CreateArticle</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Title)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Title)
#Html.ValidationMessageFor(model => model.Title)
</div>
<div class="editor-label">
Terms:
</div>
<div id="divList">
</div>
#using (Ajax.BeginForm("Update", new AjaxOptions() { Confirm = "Add", HttpMethod = "Post", UpdateTargetId = "divList", InsertionMode = InsertionMode.InsertAfter }))
{
#Html.Partial("_TermPP", "")
<input id="count" name="count" type="hidden" value="-1" />
<input type="submit" value="add" onclick="javascript:plus()" />
}
</fieldset>
}
_TermPP:
#model String
<div>
<input type="text" name="terms[#(ViewBag.Count==null?0:ViewBag.Count)]" value="#(Model == null ? "" : Model)" /> </div>
when the click is sent to a form of ADD but I need to create on the Update. How do this?
You may take a look at the following blog post. Also please note that you cannot nest 2 <form> elements as you did in your code - this is invalid HTML and might result in undefined behavior.

Resources