ASP .Net MVC: Razor view ignores or skips validation ViewBag - asp.net-mvc

I am trying to have validation for my Search option field, which is inside Index.cshtml :
When I enter name it works fine and displays all matching results inside DetailsBySurname.cshtml :
This is DetailsBySurname.cshtml
This Razor view supposed to show Validation Success or Error messages depending on whats inside the ViewBag, but when it redirects from Controller IActionResult to my Razor View with Error Messages inside ViewBag it skips(i think) the block of code with if statement and goes directly to foreach loop which is supposed to be activated only when there are NO Error messages. Then i get this error:
Here is Code for the Razor view DetailsBySurname.cshtml:
#model IEnumerable<codeRed_Capstone.Models.Employee>
#{
ViewData["Title"] = "DetailsBySurname";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#if (ViewBag.Message != null)
{
<p class="alert-#(ViewBag.Error != null ? "danger" : "success")">#(ViewBag.Message)</p>
if (ViewBag.Error != null)
{
<ul>
#foreach (Exception e in ViewBag.Exception.ValidationExceptions)
{
<li class="alert-danger">#(e.Message)</li>
}
</ul>
}
}
<h1>Details</h1>
<div>
<h4>Employee</h4>
<hr />
#foreach (var item in Model)
{
<dl class="row">
<dt class="col-sm-2">
#Html.DisplayNameFor(item => item.FirstName)
</dt>
<dd class="col-sm-10">
#Html.DisplayFor(modelItem => item.FirstName)
</dd>
<dt class="col-sm-2">
#Html.DisplayNameFor(model => item.LastName)
</dt>
<dd class="col-sm-10">
#Html.DisplayFor(modelItem => item.LastName)
</dd>
</dl>
}
</div>
This is block of code from Controller for the IAction result DetailsBySurname:
public async Task<IActionResult> DetailsBySurname(string lastName)
{
if (Request.Query.Count > 0)
{
try
{
ValidationException exception = new ValidationException();
lastName = !string.IsNullOrWhiteSpace(lastName) ? lastName.Trim() : null;
using (CompanyContext context = new CompanyContext())
{
if (string.IsNullOrWhiteSpace(lastName))
{
exception.ValidationExceptions.Add(new Exception("Last Name Not Provided"));
}
// Category ID fails parse.
// Common validation points (5) and (5a).
int n;
bool isNumeric = int.TryParse(lastName, out n);
if (isNumeric)
{
exception.ValidationExceptions.Add(new Exception("ID Not Valid string"));
}
else
{
// Category ID exists.
// Common validation point (7).
if (!context.Employees.Any(x => x.LastName == lastName))
{
exception.ValidationExceptions.Add(new Exception("Last Name Does Not Exist"));
}
}
if (exception.ValidationExceptions.Count > 0)
{
throw exception;
}
}
var employees = _context.Employees.Where(m => m.LastName == lastName);
ViewBag.Message = $"Successfully Found {lastName}!";
return View(employees);
}
// Catch ONLY ValidationException here.
catch (ValidationException e)
{
ViewBag.LastName = lastName;
ViewBag.Message = "There exist problem(s) with your submission, see below.";
ViewBag.Exception = e;
ViewBag.Error = true;
return View(e);
}
}
return View();
}
finally here is code for the search field inside Index.cshtml view:
#model IEnumerable<codeRed_Capstone.Models.Employee>
#{
ViewData["Title"] = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<a class="navbar-brand" href="#">Navbar</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mr-auto">
<li class="nav-item active">
</li>
<li class="nav-item dropdown">
<form action="/Employee/Index" method="get">
<lable for="filter"> Show Laid of Staff</lable>
<input type="checkbox" id="filter" name="filter" value="laidoff" />
<input class="btn btn-outline-success my-2 my-sm-0" type="submit" value="Go!" />
</form>
</li>
</ul>
<form action="/Employee/DetailsByEmail" method="get" class="form-inline my-2 my-lg-0">
<input id="email" name="email" data-val="true" data-val-required="Email is required" class="form-control mr-sm-2" type="search" placeholder="Search by Email" aria-label="Search">
<span class="field-validation-valid" data-valmsg-for="email" data-valmsg-replace="true"></span>
<button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
</form>
<form action="/Employee/DetailsBySurname" method="get" class="form-inline my-2 my-lg-0">
<input id="lastName" name="lastName" data-val="true" data-val-required="Last Name is required" class="form-control mr-sm-2" type="search" placeholder="Search by Last Name" aria-label="Search">
<span class="field-validation-valid" data-valmsg-for="lastName" data-valmsg-replace="true"></span>
<button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
</form>
</div>
</nav>
I watched debugging it works as expected goes all the way till the end, only when it jumps to Razor View it gives me this error that i mentioned above.
I also have Class created to handle all Validation exceptions but its working fine. I'm sure problem is some where here between Controller and Razor view. Or maybe problem somewhere else, i'm new to ASP .Net MVC, any suggestions?

I fixed it with a different validation approach.
For the DetailsBySurname i removed if(ViewBag... and added different if(ViewData... - statement to check if returned result is null then don't run foreach loop). To catch error messages use another if statement #if(!ViewData.ModelState.IsValid) like this:
#model IEnumerable<codeRed_Capstone.Models.Employee>
#{
ViewData["Title"] = "DetailsBySurname";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h1>Details</h1>
<div>
#if (ViewData.ModelState.IsValid)
{
<h4>Employee</h4>
<hr />
#foreach (var item in Model)
{
<dl class="row">
<dt class="col-sm-2">
#Html.DisplayNameFor(item => item.FirstName)
</dt>
<dd class="col-sm-10">
#Html.DisplayFor(modelItem => item.FirstName)
</dd>
<dt class="col-sm-2">
#Html.DisplayNameFor(item => item.LastName)
</dt>
<dd class="col-sm-10">
#Html.DisplayFor(modelItem => item.LastName)
</dl>
}
}
</div>
<div class="form-row">
<div class="form-group col-md-2">
#if (!ViewData.ModelState.IsValid)
{
<span class="field-validation-error">#ViewData.ModelState["LastName"].Errors[0].ErrorMessage</span>
}
</div>
</div>
Then inside Controller for the IAction result DetailsBySurname I changed validation method to built-in validation which looks something like this:
public async Task<IActionResult> DetailsBySurname(string lastName)
{
lastName = !string.IsNullOrWhiteSpace(lastName) ? lastName.Trim() : null;
if (string.IsNullOrWhiteSpace(lastName))
{
ModelState.AddModelError("LastName", "Last Name not Provided");
//exception.ValidationExceptions.Add(new Exception("Last Name Not Provided"));
}
bool exists;
if (!(exists = _context.Employees.Any(m => m.LastName == lastName)))
{
//return NotFound(new Exception("Email not found"));
ModelState.AddModelError("LastName", "Last Name not found");
}
if (!ModelState.IsValid)
{
return View();
}
else
{
var employee = _context.Employees.Where(m => m.LastName == lastName);
return View(employee);
}
}

Related

Edit action has not been hitting while I push the submit button

I have an edit button in each row of my Datatable. I have two actions for editing. One for Getting data in a Datatable and the other one for posting my information. The code behind my Edit button in the my Home Index is:
{
"data": "Id",
"render": function (data, type, full, meta) {
return `<div class="text-center"> <a class="btn btn-info"
href="/Home/EditGet/` + data + `" >Edit</a> </div> `;
}
and my home controller methods are:
/// Get Edit
[HttpGet]
[Route("{Id}")]
public IActionResult EditGet(int? id)
{
if (id == null || id == 0)
{
return NotFound();
}
var obj = _sv.OpenRecord(id);
if (obj == null)
{
return NotFound();
}
return View("EditGet", obj);
}
/// Post Edit
[HttpPost]
public IActionResult EditPost(SalesVeiwModel sales)
{
if (ModelState.IsValid)
{
var res= _sv.Update(sales.Comment);
if (res==null )
{
return Json(data: "Not found");
}
return RedirectToAction("EditGet");
}
return Json(data: "Is not valid");
}
And finally my EditGet view is like bellow:
<form id="contact-form" method="post" asp-controller="Home" asp-
action="EditPost" role="form" >
<input asp-for="Id" hidden />
<div class="form-group">
<label>Invoice Nomber</label>
<input id="form_IBNo" type="text" class="form-control" disabled asp-for="IBNo">
</div>
.
.
.
<div class="col-md-12">
<input type="submit" class="btn btn-success btn-send" value="Confirm" asp-
controller="Home" asp-action="EditGet">
</form>
You should have two buttons,one call EditGet,one call EditPost,here is a demo:
<form id="contact-form" method="post" asp-controller="Home" asp-
action="EditPost" role="form" >
<input asp-for="Id" hidden />
<div class="form-group">
<label>Invoice Nomber</label>
<input id="form_IBNo" type="text" class="form-control" disabled asp-for="IBNo">
</div>
.
.
.
<div class="col-md-12">
<input type="submit" class="btn btn-success btn-send" value="Confirm">
<a class="btn btn-success btn-send" value="Confirm" asp-controller="Home" asp-action="EditGet" asp-route-id="1">EditGet</a>
</div>
</form>

How to do products sorting?

I need to make a food ordering site for a university graduation project and I have no previous experience in the subject. I did most of the site, but I want to sort with the blue buttons in the menu, but I couldn't do it. I created #Html.ActionLink Name and Price links to try it but it doesn't work. That's why I couldn't assign tasks to the blue buttons. Alphabetically, best seller, price ascending, price descending. Can you help me?
Controller
```
public class MenuController : Controller
{
// GET: Menu
Context c = new Context();
public ActionResult Index(string sortBy)
{
ViewBag.SortNameParameter = string.IsNullOrEmpty(sortBy) ? "Name desc" : "";
ViewBag.SortPriceParameter = sortBy == "Price" ? "Price desc" : "Price";
var uruns = c.Uruns.AsQueryable();
switch(sortBy)
{
case "Name desc":
uruns = uruns.OrderByDescending(x => x.UrunAdi);
break;
case "Price desc":
uruns = uruns.OrderByDescending(x => x.UrunFiyat);
break;
case "Price":
uruns = uruns.OrderBy(x => x.UrunFiyat);
break;
default:
uruns = uruns.OrderBy(x => x.UrunAdi);
break;
}
Context _db = new Context();
Menu vm = new Menu();
//vm.Deger1 = (_db.Uruns.Where(i=>i.Durum)&&_db.Kategoris.Where(i=>i.Durum)).ToList();
vm.Deger1 = _db.Uruns.Where(i=>i.Durum).ToList();
vm.Deger2 = _db.Kategoris.Where(i=>i.Durum).ToList();
return View(vm);
}
View
<ul class="filters_menu">
<li class="active" data-filter="*">All</li>
#foreach (var k in Model.Deger2)
{
if (k.Durum != false)
{
<li class="" data-filter=".#k.KategoriAdi">#k.KategoriAdi</li>
}
}
</ul>
<p class="filters_menu">
<button class="btn btn-primary btn-round" type="button">A/Z</button>
<button class="btn btn-primary btn-round" type="button">En çok satan</button>
<button class="btn btn-primary btn-round" type="button">Fiyat (Artan)</button>
<button class="btn btn-primary btn-round" type="button">Fiyat (Azalan)</button>
#Html.ActionLink("Name", "Index", new { sortBy = ViewBag.SortNameParameter })
#Html.ActionLink("Price", "Index", new { sortBy = ViewBag.SortPriceParameter })
</p>
<div class="filters-content">
<div class="row grid">
#foreach (var item in Model.Deger1.OrderBy(item => item.UrunFiyat))
{
//if (item. != false)
//{
using (Html.BeginForm("SepeteEkle", "Sepet", FormMethod.Post, new { Id = item.Urunid }))
{
<div class="col-sm-6 col-lg-4 all #item.Kategori.KategoriAdi">
<div class="box">
<div>
<div class="img-box">
<img src="#item.UrunGorsel" alt="">
</div>
<div class="detail-box">
<h5>
#item.UrunAdi
</h5>
<div class="options">
<h6>
#item.UrunFiyat ₺
</h6>
<input name="Id" value="#item.Urunid" type="hidden" />
<input name="qty" class="form-control" type="number" name="" value="1" max="10" min="1" style="max-width: 60px; min-width: 60px;" />
<input type="submit" value="Sepete Ekle" class="btn btn-success btn-circle" />
#*<button class="btn btn-success btn-circle" type="button">Sepete Ekle</button>*#
</div>
</div>
</div>
</div>
</div>
}
}
</div>
</div>
</div>
```
[Menu][1]
[1] : https://i.stack.imgur.com/M1SVO.jpg

Concatenation of strings in Razor MVC 5 for "class" attribute

I'm building an ASP.NET MVC 5 application for a local inventory. This app shows items on a page with buttons to deliver the items.
I want the "Scarica" buttons to be greyed-out when items are not available, so I thought I could just delete the btn-info attribute and that should've done the trick, so I changed the relevant lines of code in the view from this
<div class="col-sm-2">
#using (Html.BeginForm("ScaricaItem", "Scarico"))
{
string Disabilitato = "";
if (i.Qty == 0)
{
Disabilitato += "disabled";
}
<div class="pull-right">
#Html.HiddenFor(x => #i.Item.Modello)
#Html.Hidden("returnUrl", Request.Url.PathAndQuery)
<input type="submit" class="btn btn-info" value="Scarica" #Disabilitato />
</div>
}
</div>
to this:
<div class="col-sm-2">
#using (Html.BeginForm("ScaricaItem", "Scarico"))
{
string Disabilitato = "";
string Classe = "";
if (i.Qty == 0)
{
Disabilitato += "disabled";
Classe = "btn";
}
else
{
Classe = "btn btn-info";
}
<div class="pull-right">
#Html.HiddenFor(x => #i.Item.Modello)
#Html.Hidden("returnUrl", Request.Url.PathAndQuery)
<input type="submit" class=#Classe value="Scarica" #Disabilitato />
</div>
}
</div>
but now I have all the buttons greyed-out because the btn-info attribute value is treated as if it was an attribute itself
<input type="submit" class="btn" btn-info="" value="Scarica">
I also tried
<input type="submit" class=#(Classe) value="Scarica" #Disabilitato />
and
<input type="submit" class=#(String.Format("{0}", Classe)) value="Scarica" #Disabilitato />
but nothing changes.
Thanks,
Davide.

ASP.Net MVC Show/Hide Content

Ok I have the following View
#model IEnumerable<WebApplication3.Models.user>
#{
ViewBag.Title = "Password Management";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#section title {<h1>#ViewBag.Title</h1>}
<div id="page-block" class="page-block-three row">
<div style="margin-top: 30px;" class="col-lg-offset-2 col-lg-8">
#using (Html.BeginForm())
{
<div class="input-group">
#Html.TextBox("SearchString", null, new { #class = "form-control ccl-form", #style = "z-index: 10", #placeholder = "Enter Username"})
<div class="input-group-btn">
<button class="btn ccl-btn ccl-btn-red ccl-btn-search" type="submit"><i class="fa fa-search"></i></button>
</div>
</div>
}
</div>
<div class="col-lg-offset-3 col-lg-6">
#foreach (var item in Model)
{
<div class="details-block">
#Html.DisplayFor(modelItem => item.UserName)
<button type="button" class="btn ccl-btn ccl-btn-green ccl-btn-search pull-right">Select User</button>
</div>
}
</div>
</div>
What I want to be able to do is hide the following div
<div class="col-lg-offset-3 col-lg-6">
#foreach (var item in Model)
{
<div class="details-block">
#Html.DisplayFor(modelItem => item.UserName)
<button type="button" class="btn ccl-btn ccl-btn-green ccl-btn-search pull-right">Select User</button>
</div>
}
</div>
Then show that Div when the submit button is clicked
My Controller looks like the following
public class PasswordController : Controller
{
private CCLPasswordManagementDBEntities db = new CCLPasswordManagementDBEntities();
public ActionResult Search(string searchString)
{
var users = from x in db.users select x;
if (!String.IsNullOrEmpty(searchString))
{
users = users.Where(x => x.UserName.ToUpper().Contains(searchString.ToUpper()));
}
return View(users);
}
}
At the moment the div is constantly shown and updates when the submit button is pressed but I want to hide that div until someone presses the submit button then it can show.
Thanks in advance for the help.
Change your code in the controller to this:
public ActionResult Search(string searchString)
{
var users = from x in db.users select x;
ViewBag.ShowList = false;
if (!String.IsNullOrEmpty(searchString))
{
ViewBag.ShowList = true;
users = users.Where(x => x.UserName.ToUpper().Contains(searchString.ToUpper()));
}
return View(users);
}
And change your view to this:
#model IEnumerable<WebApplication3.Models.user>
#{
ViewBag.Title = "Password Management";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#section title {<h1>#ViewBag.Title</h1>}
<div id="page-block" class="page-block-three row">
<div style="margin-top: 30px;" class="col-lg-offset-2 col-lg-8">
#using (Html.BeginForm())
{
<div class="input-group">
#Html.TextBox("SearchString", null, new { #class = "form-control ccl-form", #style = "z-index: 10", #placeholder = "Enter Username"})
<div class="input-group-btn">
<button class="btn ccl-btn ccl-btn-red ccl-btn-search" type="submit"><i class="fa fa-search"></i></button>
</div>
</div>
}
</div>
#if(ViewBag.ShowList){
<div class="col-lg-offset-3 col-lg-6">
#foreach (var item in Model)
{
<div class="details-block">
#Html.DisplayFor(modelItem => item.UserName)
<button type="button" class="btn ccl-btn ccl-btn-green ccl-btn-search pull-right">Select User</button>
</div>
}
</div>
}
</div>
You can try having a flag (ViewBag.isShown = false;)
When the page refreshes, it will show your div.
Code should be like below:
if (ViewBag.isShown == true)
{
..your for each block..
}

get additional value from form

my form and controller below. basically I'm trying to obtain the form value mode in the controller, the cmd value is always set but my mode isn't set and i don't know how to obtain the value, can anyone tell me how to get it?
or how to get it using the same method as the cmd string?
Thanks
using (Ajax.BeginForm("AddEditRecord", "Equipment", new AjaxOptions { HttpMethod = "POST",OnSuccess = "onSuccess()", LoadingElementId = "dvLoading" }))
{
#Html.ValidationSummary(true)
<div id="equipmentDialog">
#Html.Hidden("hidMode", Request.QueryString["mode"].ToString())
<fieldset>
<legend>Product</legend>
#if (ViewBag.IsUpdate == true)
{
#Html.HiddenFor(model => model.ID)
}
<div class="editor-label">
#Html.LabelFor(model => model.MachineName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.MachineName)
#Html.ValidationMessageFor(model => model.MachineName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.AssetNo)
</div>
<div class="editor-field">
#Html.TextAreaFor(model => model.AssetNo)
#Html.ValidationMessageFor(model => model.AssetNo)
</div>
<p>
#if (ViewBag.IsUpdate == true)
{
<input type="submit" value="Update" id="btnUpdate" name="cmd" class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only" />
}
else
{
<input type="submit" value="Add" id="btnSave" name="cmd" class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only" />
}
<input type="button" value="Cancel" id="btncancel" class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only" />
</p>
</fieldset>
</div>
}
my addedit controller is this
public ActionResult AddEditRecord(tblEquipment Equipment, string cmd, string mode)
{
if (ModelState.IsValid)
{
switch (cmd)
{
case "Add":
try
{
db.tblEquipments.Add(Equipment);
db.SaveChanges();
return RedirectToAction(mode);
}
catch { }
break;
case "Update":
try
{
tblEquipment Item = db.tblEquipments.Where(m => m.ID == Equipment.ID).FirstOrDefault();
if (Item != null)
{
Item.AssetNo = Equipment.AssetNo;
Item.MachineName = Equipment.MachineName;
db.SaveChanges();
}
return RedirectToAction(mode);
}
catch { }
break;
}
}
if (Request.IsAjaxRequest())
{
return PartialView("_AddEdit", Equipment);
}
else
{
return View("AddEdit", Equipment);
}
}
Error is here:
#Html.Hidden("hidMode", Request.QueryString["mode"].ToString())
You give name hidMode to hidden field and expect it as cmd in your controller. So either rename hidden field or rename input parameter in a controller action

Resources