Input validation in MVC 3 - asp.net-mvc

I am developing the CRM and facing some troubles in model validation.The process looks simple when only one object in the model(i am using EF) is validated on the form. But when i am trying to process validation on multiply objects, only one top record got validated. Here is the code:
#model List<CROS1.Models.GetParams_Result> //
<h3 align="center">
Please fill report params
</h3>
<div class="sidebar_item">
#using (#Ajax.BeginForm("ConfirmGeneration", "Home", ajaxOptions: new AjaxOptions
{
HttpMethod = "GET",
UpdateTargetId = "params",
InsertionMode = InsertionMode.Replace,
LoadingElementId = "resultLoadingDiv",
}, htmlAttributes: new { id = "Form2" }))
{
<table id="hor-minimalist-b">
<tread>
<tr>
<th scope ="col">Report</th>
<th scope ="col">Filter</th>
<th scope ="col">Value</th>
</tr>
</tread>
#foreach (CROS1.Models.GetParams_Result res in Model)
{
<tbody>
<tr>
<td>#Html.DisplayTextFor(r => res.R_name)
</td>
<td>#Html.DisplayTextFor(r => res.Filter_name)
</td>
<td>#Html.EditorFor(r => res.Value)
#Html.ValidationMessageFor(r=>res.Value)
</td>
<td>#Html.DisplayFor(r => res.Unity)
</td>
#Html.HiddenFor(r=>res.F_id)
#Html.HiddenFor(r=>res.R_id)
#Html.HiddenFor(r=>res.Filter_id,new{id="some"})
#Html.HiddenFor(r => res.F_name)
#Html.HiddenFor(r => res.Filter_name)*#
#Html.HiddenFor(r=>res.DefaultValue)
#Html.HiddenFor(r=>res.Visibles)
</tr>
</tbody>
}
</table>
#* <input type="submit" id="submGetParams" />*#
}
</div>
What i should do in this case? How the model must look like to be able to perform such validation?

You need to iterate through each item in your list of items returned, appending the iteration number to each items element, this should help: mvc clientside validation for nested (collection) properties

Related

ASP MVC 5 Post a form from a link

I need to make a custom data grid view with multi column filtering and pagination. so i made a view model winch will encapsulate three class
IEnumerable from the data.
Filter class with some properties
Pager to holder page size, current page, total pages etc ..
Filtering working fine but pagination not :(. as i loose the view model when pressing pagination link "It seems that i need to also submit the search form"
Any one can show how i can submit the form when pressing a link.
here is my view
#model TestFilteringAndPagination.ViewModels.CarViewModel
#{
ViewBag.Title = "Home Page";
}
#*Search form*#
#using (Html.BeginForm("Index", "Home", FormMethod.Post, new { id = "frm" }))
{
#Html.HiddenFor(m => Model.Pager.CurrentPage)
#Html.HiddenFor(m => Model.Pager.PageSize)
#Html.HiddenFor(m => Model.Pager.EndPage)
#Html.HiddenFor(m => m.Pager.StartPage)
<div class="form-inline">
<div class="form-group">
<label>Car No</label>
#Html.EditorFor(x => x.Filter.CarNumber, new { #class = "form-control" })
</div>
<div class="form-group">
<label>Line name</label>
#Html.EditorFor(x => x.Filter.LineName, new { #class = "form-control" })
</div>
<button type="submit" class="btn btn-default">Search</button>
</div>
<ul class="pagination">
#for (var page = Model.Pager.StartPage; page <= Model.Pager.EndPage; page++)
{
<li class="#(page == Model.Pager.CurrentPage ? "active" : "")">
#page
</li>
}
</ul>
}
#*Data grid*#
<table class="table">
<thead>
<tr>
<th>
Car number
</th>
<th>
Car Line
</th>
</tr>
</thead>
<tbody>
#foreach (var car in Model.Cars)
{
<tr>
<td>
#Html.DisplayFor(x => car.CarNumber)
</td>
<td>
#Html.DisplayFor(x => car.LineName)
</td>
</tr>
}
</tbody>
</table>
You can install the PagedList.MVC NuGet Package, see this post for more info about how to create exactly what you want.
Sorting, Filtering, and Paging with the Entity Framework in an ASP.NET MVC Application

Add table controls for asp.net mvc web application using signalR

I want to add controls to sort a table which is rendered in a partial view. The partial view is called using a signalR method. Every time the server updates the database with new information it calls the javascript method to return a new partial view to <div id="customersTable">.
I need a way to pass a query to the controller, and make the last query sent persistent so that when signalR calls the controller action again, the clients actions are remembered.
In addition to sorting I would also like to implement child rows that are expandable via a toggle button in an additional column. I'm not sure how feasible that is using partial views and signalR in this way.
I have partially solved this by adding JQuery controls to the main page. However when AJAX updates the DOM, the controls are reset to their default state, which is something I ultimately want to avoid happening.
Here is the partial view:
#model IEnumerable<XXXX.Models.CustomerModel>
<table class="table table-hover">
<tbody>
<tr>
<th class="col-sm-2">
Name
</th>
<th class="col-sm-2">
SO Number
</th>
<th class="col-sm-2">
Report Time
</th>
<th class="col-sm-2">
Report Date
</th>
<th align="center" class="col-sm-1">
System Status
</th>
</tr>
#foreach (var item in Model)
{
<tr onclick="location.href = '#(Url.Action("SystemDetails", "Monitoring", new { id = item.ID }))'" #(item.Errors == 0 ? String.Empty : "class=danger")>
<td class="col-sm-2">
#Html.DisplayFor(modelItem => item.Name)
</td>
<td class="col-sm-2">
#Html.DisplayFor(modelItem => item.SONumber)
</td>
<td class="col-sm-2">
#Html.DisplayFor(modelItem => item.ReportTime)
</td>
<td class="col-sm-2">
#Html.DisplayFor(modelItem => item.ReportDate)
</td>
<td align="center" class="col-sm-1">
#if (item.Errors == 0)
{
<i class="glyphicon glyphicon-ok"></i>
}
else if (item.Errors > 0)
{
<i class="glyphicon glyphicon-warning-sign"></i>
}
</td>
</tr>
}
</tbody>
</table>
Here is the javascript method client side:
function getAllCustomers()
{
var tbl = $('#customersTable');
$.ajax({
url: '/Monitoring/GetCustomers',
contentType: 'application/html ; charset:utf-8',
type: 'GET',
dataType: 'html'
}).success(function (result) {
tbl.empty().append(result);
}).error(function () {
});
}
And the controller method where the db context is sorted:
public ActionResult GetCustomers()
{
return PartialView("~/Views/Monitoring/_CustomersList.cshtml", db.Customers.OrderBy(c => c.SONumber).ToList());
}

How to update Partial View without full replacement

I have this partial view. This works, ie, when the user clicks the button, an ajax trip is made to the server, and it updates the partial view and it comes down and replaces the current div with the updated Div and shows the Promo Message.
However, it seems there should be a better way to do this. In other words, is it necessary to replace the entire partial view? Isn't there a way to send just the data up to the server, and then update just the message when it gets back, like maybe via a JSON call?
Controller:
public ActionResult ApplyPromoCode(OrderViewModel orderViewModel) {
orderViewModel.PromoMessage = "Promo has been applied";
return PartialView("PromoPartial", orderViewModel);
}
Partial View:
#model NTC.PropertySearch.Models.OrderViewModel
#using (Ajax.BeginForm("ApplyPromoCode", "OrderSummary", new AjaxOptions { InsertionMode = InsertionMode.Replace, UpdateTargetId = "promo" }))
{
<div id="promo">
<table>
<td>
#Html.LabelFor(m => m.PromoCode)
</td>
<td>
#Html.TextBoxFor(m => m.PromoCode)
</td>
<td>
#Html.ValidationMessageFor(m => m.PromoCode)
</td>
<td>
<input type="submit" value="Apply Promo Code" />
</td>
<td>
#Html.DisplayFor(m=> m.PromoMessage)
</td>
</table>
</div>
}
you can do this to
Controller
public ActionResult ApplyPromoCode(OrderViewModel orderViewModel) {
//your processing code
return Content("Promo has been applied");
}
View
#model NTC.PropertySearch.Models.OrderViewModel
#using (Ajax.BeginForm("ApplyPromoCode", "OrderSummary", new AjaxOptions { UpdateTargetId = "pcode" }))
{
<div id="promo">
<table>
<td>
#Html.LabelFor(m => m.PromoCode)
</td>
<td>
#Html.TextBoxFor(m => m.PromoCode)
</td>
<td>
#Html.ValidationMessageFor(m => m.PromoCode)
</td>
<td>
<input type="submit" value="Apply Promo Code" />
</td>
<td>
<div id="pcode"></div>
</td>
</table>
</div>
}
Instead of returning a PartialView you can always return a JSON object/array or some XML and use jQuery/JavaScript on your callback function to update the values of your input fields.
Here's an example of some code I use to return JSON from a Controller:
public ActionResult CurrentTags(int entityID)
{
Entity entity = db.Entity.Find(entityID);
var tags = from tag in entity.Tag
select new
{
id = tag.Name,
text = tag.Name
};
return this.Json(tags, JsonRequestBehavior.AllowGet);
}

jQuery-ui autocomplete causes validation to fail if result is null

Long day and I'm still beating my head against the desk over this one. I think I've read every jQuery ui autocomplete post here on stack overflow as well as most of the jQuery ui documentation.
The Problem:
I have a form in an asp.net mvc 4 application. The form is for submitting a timesheet/work ticket. The user selects a project and based upon that project an autocomplete field for work order number is enabled. If the user chooses and existing work order number for the project, I populate two additional inputs with information about the work order. I need to allow the user to type in a completely new work order with out selecting an autocomplete suggested work order and still have the form validate. The problem is that validation fails if I do not select a suggestion from the autocomplete.
The jQuery-ui documentation does show that the methods close, disable, and destroy available to be used but I'm not finding a good example of how to use them and which would actually be best to use in my situation. Also it might be worth noting that I am using jQuery-ui 1.9
The error I get:
System.Data.Entity.Validation.DbEntityValidationException: Validation failed for one or more entities. See 'EntityValidationErrors' property for more details.
The error points to the line of code on my controller where I call _db.SaveChanges();
if ( ModelState.IsValid )
{
_db.WorkTickets.Add(workticket);
_db.SaveChanges();
}
The model state is valid and I have no nulls trying to be saved. My model does allow nulls on a few fields but in this case all fields are complete.
The form works great if I choose an existing work order from the autocomplete widget or if I leave it blank. It only fails if I type in a new work order. I have set a break point and verified that the model does have the value I typed in for work ticket.WONumber before calling save changes.
Here is my jQuery.
$(document).ready(function () {
$("#ProjectID").change(function () {
var id = $(this).val();
var results = "result";
var source1 = "Project/QuickCCSearch?project=" + id;
$("#ChargeCode").autocomplete({ source: source1 });
$("#ChargeCode").attr("disabled", false)
var source2 = "Project/QuickPOSearch?project=" + id;
$("#PONumber").autocomplete({ source: source2 });
$("#PONumber").attr("disabled", false)
var source3 = "Project/QuickWOSearch?project=" + id;
$("#WONumber").attr("disabled", false)
$("#WONumber").autocomplete({
source: function (request, response) {
$.ajax({
url: source3,
data: request,
success: function (data) {
response(data);
if (data.length === 0) {
$("#WONumber").attr("check", false);
}
}
});
},
change: function () {
if ($("#WONumber").attr("check") != false) {
$.getJSON("Project/JobLocation", { wo: $("#WONumber").val() },
function (data) {
$("#JobLocation").val(data);
});
$.getJSON("Project/JobDescription", { wo: $("#WONumber").val() },
function (data) {
$("#JobDescription").val(data);
});
}
}
});
$.getJSON("WorkTicket/GetClient/", { id: id },
function (data) {
$("#Client").html(data);
});
$.getJSON("WorkTicket/GetClientRep/", { id: id },
function (data) {
$("#ClientRep").html(data);
});
$.getJSON("WorkTicket/GetManager/", { id: id },
function (data) {
$("#Manager").html(data);
});
});
})
Edit:
Here is my Html
#model WorkTicket
#{
ViewBag.Title = "Create";
}
<article>
<div class="linearBg1">
Create Daily Work Ticket
</div>
<br />
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<div class="linearBg1">
General Information
</div>
<div class="section-span-body">
<table>
<tr class="empTableRowBody2">
<th class="empTableRowBody2">
#Html.LabelFor(Model => Model.DateWorked)
</th>
<th class="empTableRowBody2" colspan="2">
#Html.LabelFor(Model => Model.ProjectName)
</th>
</tr>
<tr>
<td>
#Html.EditorFor(Model => Model.DateWorked)
</td>
<td colspan="2">
#Html.DropDownList("ProjectID")
</td>
</tr>
<tr class="empTableRowBody2">
<th class="empTableRowBody2">
Client
</th>
<th class="empTableRowBody2">
Client Rep
</th>
<th class="empTableRowBody2">
Manager
</th>
</tr>
<tr>
<td>
<div id="Client"></div>
</td>
<td>
<div id="ClientRep"></div>
</td>
<td>
<div id="Manager"></div>
</td>
</tr>
<tr class="empTableRowBody2">
<th class="empTableRowBody2">
Charge Code
</th>
<th class="empTableRowBody2">
PO Number
</th>
<th class="empTableRowBody2">
Work Order
</th>
</tr>
<tr>
<td>
#Html.TextBoxFor(Model => Model.ChargeCode, new { disabled = true })
</td>
<td>
#Html.TextBoxFor(Model => Model.PONumber, new { disabled = true })
</td>
<td>
#Html.TextBoxFor(Model => Model.WONumber, new { disabled = true, check = true })
</td>
</tr>
<tr class="empTableRowBody2">
<th class="empTableRowBody2" colspan="3">
Job Location
</th>
</tr>
<tr>
<td colspan="3">
#Html.TextBoxFor(Model => Model.JobLocation, new { #class = "inputWidth500" })
</td>
</tr>
<tr class="empTableRowBody2">
<th class="empTableRowBody2" colspan="3">
Job Description
</th>
</tr>
<tr>
<td colspan="3">
#Html.TextBoxFor(Model => Model.JobDescription, new { #class = "inputWidth500" })
</td>
</tr>
</table>
</div>
<div class="section-span-footer"></div>
<br />
<div>
<input type="submit" value="Next" />
</div>
}
</article>
#section Menu{
#Html.Partial("_MainMenu")
#Html.Partial("_MenuFooter")
}
#section scripts{
#Scripts.Render("~/bundles/jqueryval")
#Scripts.Render("~/Scripts/WorkTicket.js")
}
I'm sure I'm doing many things wrong as I am new to jQuery and still learning. Is there a way to disable the autocomplete if the user does not choose an option from the autocomplete widget or if the result of the widget is null? Thank you in advance!
T.
Ok, I finally solved it. It has nothing to do with autocomplete. Just goes to show how much I need to learn about jQuery. I had a bad line of code in my controller where I was saving information about the new work order back to the project. I was missing one required item and I was just over looking it. Sorry for being an idiot and ignorant about jQuery. Thanks anyone that looked. Can't believe that took me so long to see.......

How to update different targets with MVC Ajax helper?

i'm having a hard time dealing with MVC Ajax helper and trying to refresh certain part of the page. In my code, I have a situation like this:
<div id="ajaxLoadedContent">
<table>
<tr>
<th>
<%: Html.Label("ProductId") %>
</th>
<th>
<%: Html.Label("ProductName") %>
</th>
<th>
</th>
</tr>
<% foreach (var product in Model.Products)
{
%>
<tr>
<td>
<%: direccion.ProductId %>
</td>
<td>
<%: direccion.ProductName %>
</td>
<td>
<% using (Ajax.BeginForm("EditProduct", "MyController",
new { ContainerDiv = "ShowEditProducts" },
new AjaxOptions() { UpdateTargetId = "ShowEditProducts", OnSuccess = "updatePlaceholder" }))
{%>
<%: Html.Hidden("ProductId", product.ProductId)%>
<input type="submit" value="Edit" />
<%} %>
</td>
</tr>
<% } %>
</table>
<script type="text/javascript">
function updatePlaceholder(context) {
var html = context.get_data();
var placeholder = context.get_updateTarget();
$(placeholder).html(html);
return false;
}
</script>
<div id="ShowEditProducts"></div>
</div>
Now, when I press the Edit button, then the 'Editor View' appears, but the problem is that when i Submit that form, then there are two options:
The data is OK, the changes are made, the form dissapears and the list is refreshed.
The data is NOT OK, the forms stays and the validation messages appear.
The problem is that the UpdateTargetId are different for each option.
Option 1 refreshes "ShowEditProducts", while Option 2 refreshes "ajaxLoadedContent". Also, ehe 'Edit View' contains JavaScript that is executed when the view is loaded using the "Edit" button but is not executed when the form contains errors and is re-rendered.
The code of the EditView looks like this:
<% using (Ajax.BeginForm("SubmitEdit", new AjaxOptions() { UpdateTargetId = Model.ContainerDiv}))
{%>
<script type="text/javascript">
// My JavaScript
</script>
<table>
<tr>
<td>
<%: Html.Label("Id")%></br>
<%: Html.TextBoxFor(x => x.Product.ProductId)%></br>
</td>
<td>
<%: Html.Label("Name")%></br>
<%: Html.TextBoxFor(x => x.Product.ProductName)%><
</td>
</tr>
</table>
<input type="submit" value="Save" />
<%: Ajax.ActionLink("Cancel", "EmptyView","Shared", new AjaxOptions() { UpdateTargetId = Model.ContainerDiv})%>
<% } %>
So, now my two big problems are:
1. The JavaScript of the 'Edit View' don't get executed when the the view is re-renderd.
2. How can i update one target is there are errors and another one when there are not.
Thanks
The object being replaced is being set on this line:
var placeholder = context.get_updateTarget();
So instead, you should add a condition here. Eg, instead of returning HTML directly, if you return an object that looks like this:
public class Result
{
public bool Success { get; set; }
public string Html { get; set; }
}
Then you could do something like this:
var result = response.get_response().get_object();
if (result.Success)
$("#ShowEditProducts").html(html);
else
$("#ajaxLoadedContent").html(html);
Alternatively, instead of returning a Success boolean, you could have a property for the ID of the control to replace. This would be more reusable, and might make sense if you want the decision of which control to replace to be done server-side.

Resources