How to get ID of value in Autocomplete texbox in ASP - c#

I am getting list of Geolocations using autocomplete , after choosing one willing to get ID of chosen values in Textboxs and set it to hidden controls. No idea how to do it.
My codes are as follow :
index.cshtml:
`<script>
$(document).ready(function () {
$('#ToLocation').autocomplete({
source: '#Url.Page("index", "search")'
});
});
</script>
<script>
$(document).ready(function () {
$('#FromLocation').autocomplete({
source: '#Url.Page("index", "search")'
});
});
<div class="row">
<div class="col">
From
<input class="form-control" id="FromLocation">
<input type="hidden" id="hfFromLocationID" name="FromLocationId"/>
</div>
<div class="col">
To
<input class="form-control" id="ToLocation">
<input type="hidden" id="hfToLocationID" name="ToLocationId"/>
</div>
</div>`
index.cshtml.cs:
`public IActionResult OnGetSearch(string term)
{
var names = context.GeoLocations.Where(p => p.GeoLocationName.Contains(term)).Select(p => p.GeoLocationName ).ToList();
return new JsonResult(names);
}`
GeoLocation.cs
`public class GeoLocation
{
public int Id { get; set; }
public string GeoLocationName { get; set; }
}`

Related

Database value not populating on button submit

When I click the submit button on my form the value of Submit is not displaying and at the same time my input fields at the top are still not autofilling like I'd like them to. I'm also trying to use the eye icon to hide the value on post request and clicking the eye icon will reveal the value on textbox.
index.cshtml
#page "{id?}"
#model IndexModel
#{ViewData["Title"] = "Main";}
<div class=" container">
<div class="row">
<div class="text-center">
<h1 class="display-4">#Model.PageTitle</h1>
</div>
</div>
<div class="row">
<form class="mt-0" method="get">
<div class="row">
<div class="col-3 offset-2" id="DepartmentResult"></div>
<div class="col-4" id="EmployeeResult"></div>
</div>
</form>
<form class="mt=0" method="post">
<div class="row">
<label class="col-2 offset-3 col-form-label">Employee Name:</label>
<div class="col-2">
<input class="form-control" title="Employee name" asp-for="Name">
</div>
</div>
<br />
<div class="row">
<label class="col-2 offset-3 col-form-label">Department Name:</label>
<div class="col-2">
<input class="form-control" title="Department name" asp-for="DeptName">
</div>
</div>
<br />
<div class="row">
<button class="btn btn-outline-dark col-1 offset-5" type="submit" id="SubmitBtn" name="SubmitBtn" value="Submit" asp-page-handler="Submit">Submit</button>
</div>
<br />
<div class="row">
<div col-4>
<br />
<div class=" row">
<label class="col-6 col-form-label">Social Security #:</label>
<div class="col-5">
<input class="form-control" type="text" asp-for="OutputSSN" disabled />
<i class="fa fa-eye-slash"></i>
</div>
</div>
</div>
</div>
</form>
</div>
</div>
#section Scripts {
<script>
$(document).ready(function()
{
$.ajax(
{
url: "/Index?handler=DisplayDepartment",
type: "GET",
data: { value: #Model.Id },
headers: { RequestVerificationToken: $('input:hidden[name="__RequestVerificationToken"]').val() },
success: function(data) { $("#DepartmentResult").html(data); }
});
});
</script>
}
index.cs
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using PracticeApp.Models;
using System.Linq;
using System.Runtime.Serialization;
using System.Threading.Tasks;
// Namespaces
namespace PracticeApp.Pages
{
// Classes
public class IndexModel : PageModel
{
// Fields
public CompanyContext _context;
// Properties
[BindProperty(SupportsGet = true)] public int Id { get; set; }
[BindProperty] public string PageTitle { get; set; } = "Employee Check";
public Employee CheckEmployee { get; set; }
[BindProperty, DataMember] public string Name { get; set; }
[BindProperty, DataMember] public string DeptName { get; set; }
public string OutputSSN { get; set; }
// Constructors
public IndexModel(CompanyContext context) { _context = context; }
// Methods
public PartialViewResult OnGetDisplayDepartment(int value) => Partial("_DisplayDepartmentPartial", _context.Departments.Where(x => x.DepartmentId == value).ToList());
public PartialViewResult OnGetDisplayEmployee(string value) => Partial("_DisplayEmployeePartial", _context.Employees.Where(x => x.DepartmentName == value).GroupBy(x => x.EmployeeName).Select(x => x.First()).ToList());
public async Task<IActionResult> OnPostSubmit()
{
OutputSSN = $"{SubstringCheck(OutputSSN, 3)}-{SubstringCheck(OutputSSN, 3, 2)}-{SubstringCheck(OutputSSN, 5, 4)}";
return Page();
}
public string SubstringCheck(string s, int length)
{
int len = s.Length;
if (len > length)
{
len = length;
}
return s.Substring(0, len);
}
public string SubstringCheck(string s, int b, int length)
{
int len = s.Length;
if (len <= b)
{
return s;
}
len -= b;
if (len > length)
{
len = length;
}
return s.Substring(b, len);
}
}
}
You forgot to add a BindProperty attribute to your OutputSSN property, so the posted form value is not being bound to it. That's why you get a NullReferenceException when you try to access its Length property.
[BindProperty] public string OutputSSN { get; set; }
As #Mike Brind has said the posted form value is not being bound to it.
First you need to add [BindProperty] like this:
[BindProperty] public string OutputSSN { get; set; }
Besides,
<input class="form-control" type="text" asp-for="OutputSSN" disabled />
you set the input disabled , so it will cause form value is not being bound to it too. If you want it cannot be modified, you can use readonly:
<input class="form-control" type="text" asp-for="OutputSSN" readonly />
I'm also trying to use the eye icon to hide the value on post request
and clicking the eye icon will reveal the value on textbox.
Below is a demo about eye icon, you can refer to it, I set the value to OutputSSN to show data , you can use your way:
<input class="form-control" asp-for="OutputSSN" value="a" type="text" readonly/>
<i class="far fa-eye" id="toggleOutputSSN" ></i>
#section Scripts {
<script>
$(document).ready(function()
{
$.ajax(
{
url: "/Index?handler=DisplayDepartment",
type: "GET",
data: { value:#Model.Id },
headers: { RequestVerificationToken: $('input:hidden[name="__RequestVerificationToken"]').val() },
success: function(data) { $("#DepartmentResult").html(data); }
});
const toggleOutputSSN = document.querySelector('#toggleOutputSSN');
const OutputSSN = document.querySelector('#OutputSSN');
toggleOutputSSN.addEventListener('click', function (e) {
// toggle the type attribute
const type = OutputSSN.getAttribute('type') === 'text' ? 'password' : 'text';
OutputSSN.setAttribute('type', type);
// toggle the eye slash icon
this.classList.toggle('fa-eye-slash');
});
});
</script>
}
result:

To send values of a checkbox list class to the server using AJAX in ASP.Net Core

I have the following model code for the checkbox list.
public class ReportViewModel
{
public List<Guid> Reports { get; set; }
public SelectList ReportList { get; set; }
public List<CheckBoxResponse> Status { get; set; }
}
public class CheckBoxResponse
{
public string ItemText { get; set; }
public bool Selected { get; set; }
}
This is my view :
<form id="frmReport">
<div class="row">
<div class="col-xs-12">
<div class="form-group">
<label asp-for="Reports"></label><br />
<select asp-for="Reports" asp-items="Model.ReportList" class="form-control" multiple></select>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<label>Status</label> <br />
#for (var i = 0; i < Model.Status.Count; i++)
{
<input type="checkbox" asp-for="#Model.Status [i].Selected" />
<label asp-for="#Model.Status[i].Selected"> #Model.Status[i].ItemText</label>
<input type="hidden" asp-for="#Model.Status[i].ItemText" />
}
</div>
</div>
<div class="row">
<div class="col-xs-12" style="padding-top: 10px; padding-bottom: 10px;">
<a id="submit" class="btn btn-primary" title="Submit">Submit</a>
</div>
</div>
</form>
There are 3 values in the check box list, and so there are 3 check boxes. I now need to pass the values to the server on click of button using jquery. This is my code :
$(document).on('click', '#submit', function (e) {
var reports = $("#Reports").find("option:selected").val();
//Need to add checkbox class to submit to the server
var model = {
Reports : reports,
Status : ??
}
}
I need to send the checkbox list to the server by adding it to the model. How do I do it?
You can put the checkboxes on a form (not nested, just use one form if it's okay) and then serialize the form and submit the data.
Do you want to send the value to the server? Then you should add value to input, and create an
array to store the selected value and then pass them, check this:
#for (var i = 0; i < Model.Status.Count; i++)
{
<input type="checkbox" asp-for="#Model.Status[i].Selected" value="#Model.Status[i].ItemText"/>
<label asp-for="#Model.Status[i].Selected">#Model.Status[i].ItemText</label>
<input type="hidden" asp-for="#Model.Status[i].ItemText" />
}
Jquery:
$(document).ready(function () {
$('#submit').click(function () {
var selected = []; //array to store
$('input:checked').each(function () {
selected.push($(this).attr("value")); //push value to array
});
$.ajax({
type: "POST",
url: '#Url.Action("Test", "Home")',
data: { Selecteditem: selected } //pass as string
});
});
});
The server:
public IActionResult Test(List<string> Selecteditem)
Result:

How can I set model input for an object attribute that exist in layers of list with asp tag-helper?

I have a model that consists of many layers. On the main frame, there will be an object for basic input and a list of object that contains a model to store view data but inside it, each item will have a data field to store its new value which I will also consider as input data. My problem is I don't know how to call, set that data field inside tag helper since it's cover by list of list. What I want to achieve is to pass all data back to controller.
public class TenDongThuocCongTy
{
public int Id { get; set; }
public int CauHinhBangId { get; set; }
public string CongThucDong { get; set; }
public string TenDong { get; set; }
public int CauHinhBang_Cha { get; set; }
[NotMapped]
public string inputValue { get; set; }
}
public class LayThongTinBangThuocCongTyThanhVien
{
public int Cttv_ThuocBangId { get; set; }
public int CauHinhBangID { get; set; }
public int CttvId { get; set; }
public string TenDong { get; set; }
public string CongThucDong { get; set; }
public string DichCongThuc { get; set; }
public List<TenDongThuocCongTy> TenDongThuocCongTies { get; set; }
}
public class MuaVuTruocUpsertModel
{
[DisplayName("Day")]
public DateTime? Ngay { get; set; }
[Required(ErrorMessage = "Number")]
[DisplayName("Number")]
public int? STT { get; set; }
}
public class TongHopItemMuaVuTruoc
{
public List<LayThongTinBangThuocCongTyThanhVien> MenuItemMuaVutruoc { get; set; }
public MuaVuTruocUpsertModel muaVuTruocModel {get; set;}
}
As in the model above, I want to access to the defined meaning of 'inputValue' then put it in:
#model MFF.Infrastructure.Models.TongHopItemMuaVuTruoc
<input asp-for="inputModel" type="text"/>
What I want to achieve is to pass all data back to controller.
To pass data from view to the controller, you could use the following methods:
Use asp.net core Model Binding and Submit button to submit the form.
Use JQuery Ajax submits the form data or a JavaScript object to the controller.
Please refer the following sample code:
Controller:
public IActionResult Index2()
{
TongHopItemMuaVuTruoc tongHopItemMuaVuTruoc = new TongHopItemMuaVuTruoc()
{
MenuItemMuaVutruoc = new List<LayThongTinBangThuocCongTyThanhVien>()
{
new LayThongTinBangThuocCongTyThanhVien()
{
TenDongThuocCongTies = new List<TenDongThuocCongTy>()
{
new TenDongThuocCongTy()
{
TenDong = "TD 1",
inputValue = "AA",
},
new TenDongThuocCongTy()
{
TenDong = "TD 2",
inputValue = "BB",
}
}
}
}
};
return View(tongHopItemMuaVuTruoc);
}
[HttpPost]
public IActionResult Index2(TongHopItemMuaVuTruoc tongHopItemMuaVuTruoc)
{
if (ModelState.IsValid)
{
//do something
}
return View(tongHopItemMuaVuTruoc);
}
Index2 View page (Index2.cshtml): Here I add two buttons, the "Submit" button will submit the form using the first method, the "Ajax Submit" button will submit the form using JQuery Ajax method. And you can add other properties using the similar tag.
#model WebApplication6.Models.TongHopItemMuaVuTruoc
<div class="row">
<div class="col-md-4">
<form id="mainform" asp-action="Index2">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="muaVuTruocModel.Ngay" class="control-label"></label>
<input asp-for="muaVuTruocModel.Ngay" class="form-control" />
<span asp-validation-for="muaVuTruocModel.Ngay" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="muaVuTruocModel.STT" class="control-label"></label>
<input asp-for="muaVuTruocModel.STT" class="form-control" />
<span asp-validation-for="muaVuTruocModel.STT" class="text-danger"></span>
</div>
#for (var i = 0; i < Model.MenuItemMuaVutruoc.Count(); i++)
{
for (var j = 0; j < Model.MenuItemMuaVutruoc[i].TenDongThuocCongTies.Count; j++)
{
<div class="form-group">
<input asp-for="MenuItemMuaVutruoc[i].TenDongThuocCongTies[j].TenDong" type="text" />
</div>
<div class="form-group">
<input asp-for="MenuItemMuaVutruoc[i].TenDongThuocCongTies[j].inputValue" type="text" />
</div>
}
}
<div class="form-group">
<input type="submit" value="Save" class="btn btn-primary" /> <input type="button" id="btnSubmit" value="Ajax Submit" class="btn btn-primary" />
</div>
</form>
</div>
</div>
At the end of the above view page, add the following scripts:
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
<script>
$(function () {
$("#btnSubmit").click(function () {
$.ajax({
url: "Test/Index2",
method: "Post",
data: $("#mainform").serialize(),
success: function () {
alert("sueess");
},
error: function (error) {
alert("error");
}
});
});
})
</script>
}
The output like this:
Reference:
Razor syntax reference for ASP.NET Core
I finally figure it out. What I have to do is treated my model as an array object. The code below returns all of my data, including default data and newly input ones, back to Controller successfully.
#for (int i = 0; i < Model.MenuItemMuaVutruoc.Count; i++)
{
//Value for Model
<input type="hidden" asp-for="MenuItemMuaVutruoc[i].CttvId" />
<input type="hidden" asp-for="MenuItemMuaVutruoc[i].Cttv_ThuocBangId" />
<input type="hidden" asp-for="MenuItemMuaVutruoc[i].CauHinhBangID" />
<input type="hidden" asp-for="MenuItemMuaVutruoc[i].TenDong" />
<input type="hidden" asp-for="MenuItemMuaVutruoc[i].CongThucDong" />
<input type="hidden" asp-for="MenuItemMuaVutruoc[i].DichCongThuc" />
#for (int j = 0; j < danhmuc.TenDongThuocCongTies.Count; j++)
{
//Value cho tung item
<input type="hidden" asp-for="MenuItemMuaVutruoc[i].TenDongThuocCongTies[j].Id" />
<input type="hidden" asp-for="MenuItemMuaVutruoc[i].TenDongThuocCongTies[j].CauHinhBangId" />
<input type="hidden" asp-for="MenuItemMuaVutruoc[i].TenDongThuocCongTies[j].CongThucDong" />
<input type="hidden" asp-for="MenuItemMuaVutruoc[i].TenDongThuocCongTies[j].CauHinhBang_Cha" />
<input type="hidden" asp-for="MenuItemMuaVutruoc[i].TenDongThuocCongTies[j].TenDong" />
var item = danhmuc.TenDongThuocCongTies.ElementAt(j);
<h6 class="col-md-4 col-lg-4 col-sm-4 mt-lg-2 mt-md-2 mt-2 mt-sm-2">
#item.TenDong
</h6>
<input asp-for="MenuItemMuaVutruoc[i].TenDongThuocCongTies[j].inputValue" type="text" class="form-control col-md-8 col-lg-8 col-sm-8 mt-lg-2 mt-md-2 mt-2 mt-sm-2" />
}
}

Input 'number' for Doubles in Asp.Net?

If in an Asp.Net Core application you have a variable type Int, this generates an input div for the model that only lets you write numbers, and lets you increase the number there with some buttons:
http://imgfz.com/i/HJuRvmS.png
<div class="form-group">
<label asp-for="CantidadperoDouble" class="control-label"></label>
<input asp-for="CantidadperoDouble" class="form-control" />
<span asp-validation-for="CantidadperoDouble" class="text-danger"></span>
</div>
However, if the original variable from your model is a Double, the input div that the code generates is the same which is used for the Strings, letting you write words there, although the model doesn't accept those values.
Is there a way to change that?
I would like my input div for Doubles to be the same as the used for Ints, but with the buttons that lets you increase the Integer part of the number, but still have the comma/dot at the end, letting you write the decimal part / fractional part, manually.
You could use JQuery to allow only numeric and one Decimal Point input in the Textbox.
Check the following code (from your description and the tag list, I assume you are create a Asp.net core Razor Application):
Product.cs
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public double Price { get; set; }
}
Create.cshtml.cs
public class CreateModel : PageModel
{
[BindProperty]
public Product Product { get; set; }
public void OnGet()
{
}
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
var data = Product;
return RedirectToPage("./Index");
}
}
Create.cshtml:
#page
#model RazorSample.Pages.CreateModel
<div class="row">
<div class="col-md-4">
<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Product.Name" class="control-label"></label>
<input asp-for="Product.Name" class="form-control" />
<span asp-validation-for="Product.Name" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Product.Price" class="control-label"></label>
<input asp-for="Product.Price" class="form-control" />
<span asp-validation-for="Product.Price" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
#section Scripts{
<script>
$(function () {
$("#Product_Price").on("keypress keyup blur", function (event) {
$(this).val($(this).val().replace(/[^0-9\.]/g, ''));
if ((event.which != 46 || $(this).val().indexOf('.') != -1) && (event.which < 48 || event.which > 57)) {
event.preventDefault();
}
});
})
</script>
}
The output as below (it allows only numeric and one Decimal Point):

Razor Page - Form with multiple handlers/server-side validation not populating asp-validation-for tags on submit

I have a form that is used to submit one of two objects. Using Fluent Validation, each object has separate validation rules, which are handled by executing ModelState.Clear() and TryValidateModel(objectName) in the respective post handler. Validation is working correctly, but is only displaying on the asp-validation-summary tag, not on the asp-validation-for tags that accompany each field. Does anyone have any idea how to get around this? (Using 2 forms is not an option.) Here is code you can use to replicate the issue:
TestValidation.cshtml:
#page
#model MyApp.Namespace.TestValidationModel
#{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>TestValidation</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
</head>
<body>
<h1>Test Validation</h1>
<form method="post">
<div asp-validation-summary="All" class="text-danger"></div>
<div class="row">
<div class="col-md-6">
<div class="card">
<div class="card-header">ObjectToValidate1 - posts with empty handler, validates server side.</div>
<div class="card-body">
<div class="form-group">
<label class="control-label">Borrower Type</label>
<select asp-for="ObjectToValidate1.Item" asp-items="#Model.DDLItems" class="form-control" onchange="changeBorrowerType();"></select>
<span asp-validation-for="ObjectToValidate1.Item" class="text-danger"></span>
</div>
<div class="form-group">
<label class="control-label"></label>
<label asp-for="ObjectToValidate1.RequiredString" class="control-label businessName"></label>
<input asp-for="ObjectToValidate1.RequiredString" class="form-control autofocus" />
<span asp-validation-for="ObjectToValidate1.RequiredString" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="ObjectToValidate1.RequiredStringIfItem1Selected" class="control-label"></label>
<input asp-for="ObjectToValidate1.RequiredStringIfItem1Selected" class="form-control" />
<span asp-validation-for="ObjectToValidate1.RequiredStringIfItem1Selected" class="text-danger"></span>
</div>
<div class="form-group">
<button type="submit" class="btn btn-success" asp-page-handler="">Submit</button>
</div>
</div>
</div>
</div>
<div class="col-md-6">
<div class="card">
<div class="card-header">ObjectToValidate2 - posts with handler of TestValidation, validates serverside</div>
<div class="card-body">
#*<div class="form-group">
<label class="control-label">Borrower Type</label>
<select asp-for="ObjectToValidate2.Item" asp-items="#Model.DDLItems" class="form-control" onchange="changeBorrowerType();"></select>
<span asp-validation-for="ObjectToValidate2.Item" class="text-danger"></span>
</div>
<div class="form-group">
<label class="control-label"></label>
<label asp-for="ObjectToValidate2.RequiredString" class="control-label businessName"></label>
<input asp-for="ObjectToValidate2.RequiredString" class="form-control autofocus" />
<span asp-validation-for="ObjectToValidate2.RequiredString" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="ObjectToValidate2.RequiredStringIfItem1Selected" class="control-label"></label>
<input asp-for="ObjectToValidate2.RequiredStringIfItem1Selected" class="form-control" />
<span asp-validation-for="ObjectToValidate2.RequiredStringIfItem1Selected" class="text-danger"></span>
</div>
<div class="form-group">
<button type="submit" class="btn btn-success" asp-page-handler="TestValidation">Submit</button>
</div>*#
</div>
</div>
</div>
</div>
</form>
#*<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.17.0/jquery.validate.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validation-unobtrusive/3.2.11/jquery.validate.unobtrusive.min.js"></script>*#
</body>
</html>
TestValidation.cshtml.cs
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using FluentValidation;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.Rendering;
namespace MyApp.Namespace
{
public class TestValidationModel : PageModel
{
[BindProperty]
public InputValues ObjectToValidate1 { get; set; }
[BindProperty]
public InputValues ObjectToValidate2 { get; set; }
public List<SelectListItem> DDLItems { get; set; }
public void OnGet()
{
ObjectToValidate1 = new InputValues();
ObjectToValidate2 = new InputValues();
InitializeDDLItems();
}
public ActionResult OnPost()
{
ModelState.Clear();
TryValidateModel(ObjectToValidate1);
if (ModelState.IsValid)
{
// Refresh current page
return RedirectToPage("./TestValidation");
}
InitializeDDLItems();
return Page();
}
public ActionResult OnPostTestValidation()
{
ModelState.Clear();
TryValidateModel(ObjectToValidate2);
if (ModelState.IsValid)
{
// Refresh current page
return RedirectToPage("./TestValidation");
}
InitializeDDLItems();
return Page();
}
private void InitializeDDLItems()
{
DDLItems = new List<SelectListItem>
{
new SelectListItem("-- Select an Item -- ", ""),
new SelectListItem("Item 1", "1"),
new SelectListItem("Item 2", "2"),
};
}
}
public class InputValues
{
[Display(Name ="Item")]
public int Item { get; set; }
[Display(Name = "Required String")]
public string RequiredString { get; set; }
[Display(Name = "Conditional Required String")]
public string RequiredStringIfItem1Selected { get; set; }
}
public class Validator : AbstractValidator<InputValues>
{
public Validator()
{
RuleFor(i => i.Item).NotEmpty().WithMessage("Item is required");
RuleFor(i => i.RequiredString).NotEmpty().WithMessage("Required String is required");
When(i => i.Item.Equals(1), () =>
{
RuleFor(e => e.RequiredStringIfItem1Selected).NotEmpty().WithMessage("Conditional Required String is required if Item 1 selected");
});
}
}
}
You need to add the following javascript files which support client-side validation :
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryvalidate/1.17.0/jquery.validate.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validation-unobtrusive/3.2.11/jquery.validate.unobtrusive.min.js"></script>
The jQuery Unobtrusive Validation script is a custom Microsoft front-end library that builds on the popular jQuery Validate plugin. Without jQuery Unobtrusive Validation, you would have to code the same validation logic in two places: once in the server-side validation attributes on model properties, and then again in client-side scripts.
Reference :https://learn.microsoft.com/en-us/aspnet/core/mvc/models/validation?view=aspnetcore-3.0#client-side-validation
The answer: Don't use ModelState.Clear(). Doing so clears out the ModelState to the extent that, even after running TryValidateModel(modelname), the resulting ModelState doesn't have enough to enable the validation tags to render. So, here is a simplified version of my earlier sample, with ModelState.Clear() commented out and ModelState.ClearValidationState() run for each object that we want to validate server side. To run for my original code, above, I would ClearValidationState for the fields that are not relevant to the current OnPost method.
The Razor Page:
#page
#model MyApp.Namespace.TestValidation2Model
#{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>TestValidation</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
</head>
<body>
<h1>Test Validation</h1>
<form method="post">
#*<div asp-validation-summary="All" class="text-danger"></div>*#
<div class="row">
<div class="col-md-6">
<div class="card">
<div class="card-header">ObjectToValidate1 - posts with empty handler, validates server side.</div>
<div class="card-body">
<div class="form-group">
<label class="control-label">Borrower Type</label>
<select asp-for="ObjectToValidate1.Item" asp-items="#Model.DDLItems" class="form-control" onchange="changeBorrowerType();"></select>
<span asp-validation-for="ObjectToValidate1.Item" class="text-danger"></span>
</div>
<div class="form-group">
<label class="control-label"></label>
<label asp-for="ObjectToValidate1.RequiredString" class="control-label businessName"></label>
<input asp-for="ObjectToValidate1.RequiredString" class="form-control autofocus" />
<span asp-validation-for="ObjectToValidate1.RequiredString" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="ObjectToValidate1.RequiredStringIfItem1Selected" class="control-label"></label>
<input asp-for="ObjectToValidate1.RequiredStringIfItem1Selected" class="form-control" />
<span asp-validation-for="ObjectToValidate1.RequiredStringIfItem1Selected" class="text-danger"></span>
</div>
<div class="form-group">
<button type="submit" class="btn btn-success" asp-page-handler="">Submit</button>
</div>
</div>
</div>
</div>
</div>
</form>
#*<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.17.0/jquery.validate.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validation-unobtrusive/3.2.11/jquery.validate.unobtrusive.min.js"></script>*#
</body>
</html>
The PageModel:
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using FluentValidation;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.Rendering;
namespace MyApp.Namespace
{
public class TestValidation2Model : PageModel
{
[BindProperty]
public InputValues2 ObjectToValidate1 { get; set; }
public List<SelectListItem> DDLItems { get; set; }
public void OnGet()
{
ObjectToValidate1 = new InputValues2();
InitializeDDLItems();
}
public ActionResult OnPost()
{
ModelState.ClearValidationState(nameof(ObjectToValidate1.RequiredString));//.Clear();
ModelState.ClearValidationState(nameof(ObjectToValidate1.Item));//.Clear();
ModelState.ClearValidationState(nameof(ObjectToValidate1.RequiredStringIfItem1Selected));
//ModelState.Clear();
TryValidateModel(ObjectToValidate1);
var jsonString = Newtonsoft.Json.JsonConvert.SerializeObject(ModelState);
if (ModelState.IsValid)
{
// Refresh current page
return RedirectToPage("./TestValidation2");
}
InitializeDDLItems();
return Page();
}
private void InitializeDDLItems()
{
DDLItems = new List<SelectListItem>
{
new SelectListItem("-- Select an Item -- ", ""),
new SelectListItem("Item 1", "1"),
new SelectListItem("Item 2", "2"),
};
}
}
public class InputValues2
{
[Display(Name = "Item")]
public int Item { get; set; }
[Display(Name = "Required String")]
public string RequiredString { get; set; }
[Display(Name = "Conditional Required String")]
public string RequiredStringIfItem1Selected { get; set; }
}
public class Validator2 : AbstractValidator<InputValues2>
{
public Validator2()
{
RuleFor(i => i.Item).NotEmpty().WithMessage("Item is required");
RuleFor(i => i.RequiredString).NotEmpty().WithMessage("Required String is required");
When(i => i.Item.Equals(1), () =>
{
RuleFor(e => e.RequiredStringIfItem1Selected).NotEmpty().WithMessage("Conditional Required String is required if Item 1 selected");
});
}
}
}

Categories

Resources