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());
}
Related
This question already has answers here:
Post an HTML Table to ADO.NET DataTable
(2 answers)
Closed 6 years ago.
Hi I want to grab all user modify data.
My question is why controller can't receive the model data from View in my project.
Please explain why this error was caused and how to solve it.
Models:
public class ShoppingCart
{
public List<ShoppingCartItemModel> items = new List<ShoppingCartItemModel>();
public IEnumerable<ShoppingCartItemModel> Items
{
get { return items; }
}
}
public class ShoppingCartItemModel
{
public Product Product
{
get;
set;
}
public int Quantity { get; set; }
}
Controller
[HttpPost]
public RedirectToRouteResult EditFromCart(ShoppingCart MyModel)
{
ShoppingCart cart = GetCart();
foreach (var CartItem in cart.items)
{
foreach (var ReceiveModelItem in MyModel.items)
{
if (CartItem.Product.ProductID == ReceiveModelItem.Product.ProductID)
{
CartItem.Quantity = ReceiveModelItem.Quantity;
}
}
}
return RedirectToAction("Index", "ShoppingCart");
}
View
#model ShoppingCart
#{
ViewBag.Title = "購物車內容";
}
<h2>Index</h2>
<table class="table">
<thead>
<tr>
<th>
Quantity
</th>
<th>
Item
</th>
<th class="text-right">
Price
</th>
<th class="text-right">
Subtotal
</th>
</tr>
</thead>
<tbody>
#using (Html.BeginForm("EditFromCart", "ShoppingCart", FormMethod.Post))
{
foreach (var item in Model.items)
{
<tr>
<td class="text-center">
#item.Product.ProductName
</td>
<td class="text-center">
#item.Product.Price.ToString("c")
</td>
<td class="text-center">
#( (item.Quantity * item.Product.Price).ToString("c"))
</td>
<td class="text-left">
#Html.EditorFor(model => item.Quantity, null, "UserInputQuantity")
#Html.Hidden("ProductId", item.Product.ProductID)
</td>
</tr>
}
<tr>
<td colspan="3">
<input class="btn btn-warning" type="submit" value="Edit">
</td>
</tr>
}
</tbody>
</table>
You must explicitly create a hidden input for each property in your complex object that you want to be bound. IEnumerables and binding don't play very nicely directly out of the box - it looks like MVC has better base support for IList<> and arrays, but you'll still have to enumerate the collection and create hidden inputs for each item. Have a look at this link. So, ideally your view should be:
#model ShoppingCart
#{
ViewBag.Title = "購物車內容";
}
<h2>Index</h2>
<table class="table">
<thead>
<tr>
<th>
Quantity
</th>
<th>
Item
</th>
<th class="text-right">
Price
</th>
<th class="text-right">
Subtotal
</th>
</tr>
</thead>
<tbody>
#using (Html.BeginForm("EditFromCart", "ShoppingCart", FormMethod.Post))
{
for (int i = 0; i < Model.items.Count(); ++i)
{
<tr>
<td class="text-center">
#Model.items[i].Product.ProductName
</td>
<td class="text-center">
#Model.items[i].Product.Price.ToString("c")
</td>
<td class="text-center">
#( (Model.items[i].Quantity * Model.items[i].Product.Price).ToString("c"))
</td>
<td class="text-left">
#Html.EditorFor(model => Model.items[i].Quantity)
#Html.HiddenFor(model => Model.items[i].Product.ProductID)
#Html.HiddenFor(model => Model.items[i].Product.ProductName)
#Html.HiddenFor(model => Model.items[i].Product.Price)
</td>
</tr>
}
<tr>
<td colspan="3">
<input class="btn btn-warning" type="submit" value="Edit">
</td>
</tr>
}
</tbody>
</table>
Names are not correctly set for your text and hidden inputs:
#Html.EditorFor(model => item.Quantity, null, "UserInputQuantity")
#Html.Hidden("ProductId", item.Product.ProductID)
If you inspect elements you can see names are UserInputQuantity and ProductId, but they should be
items[i].Quantity and items[i].Product.ProductID respectively.
You can take a look at this link:
MVC Model binding of complex objects
How to handle errors in Razor (i.e. Null Exception)other than (try/catch)?
I do not want to insert (try/catch) block in every razor block.
Example (The (Model.ListofEntity) or (Item.Values) may be null and an exception might occur):
<table class="table">
<tr>
<th>
<div id="chkCheckAll" class="divCheckbox">
</div>
</th>
#foreach (var column in Model.ListofEntity.Columns)
{
int t = Convert.ToInt32(" ");
<th>
#column
</th>
}
</tr>
#foreach (CVMEntities.Item Item in Model.ListofEntity.Items)
{
<tr>
<td>
<div id=#Item.ID class="divCheckbox">
</div>
</td>
#foreach (var Value in Item.Values)
{
<td>
#Value
</td>
}
</tr>
}
</table>
During debugging, my MVC model and Formcollection are blank with no values in FireFox (15) or Chrome (latest version).
During debugging using IE (9), I can see these values just fine.
Do you know what the solution is for this? This is very serious for public facing web sites not being able to do any programming angainst these browsers.
Here is my View...
#model PDFConverterModel.ViewModels.ViewModelTemplate_Guarantors
#{
ViewBag.Title = "BHG :: PDF Generator";
}
<h2>#ViewBag.Message</h2>
<div>
<table style="width: 1000px">
<tr>
<td colspan="5">
<img alt="BHG Logo" src="~/Images/logo.gif" />
</td>
</tr>
#using (Html.BeginForm("ProcessForm", "Home", FormMethod.Post))
{
<tr>
<td>
#(Html.Kendo().IntegerTextBox()
.Name("LoanID")
.Placeholder("Enter Loan ID")
)
</tr>
<tr>
<td>#Html.LabelFor(model => model.LoanType)
#Html.DisplayFor(model => model.LoanType)
</td>
<td>
<label for="ddlDept">Department:</label>
#(Html.Kendo().DropDownList()
.Name("ddlDept")
.DataTextField("DepartmentName")
.DataValueField("DepartmentID")
.Events(e => e.Change("Refresh"))
.DataSource(source =>
{
source.Read(read =>
{
read.Action("GetDepartments", "Home");
});
})
)
</td>
</tr>
if (Model.ShowGeneratePDFBtn == true)
{
if (Model.ErrorT == string.Empty)
{
<tr>
<td colspan="5">
<u><b>#Html.Label("Templates:")</b></u>
</td>
</tr>
<tr>
#for (int i = 0; i < Model.Templates.Count; i++)
{
<td>
#Html.CheckBoxFor(model => Model.Templates[i].IsChecked)
#Html.DisplayFor(model => Model.Templates[i].TemplateId)
</td>
}
</tr>
}
else
{
<tr>
<td>
<b>#Html.DisplayFor(model => Model.ErrorT)</b>
</td>
</tr>
}
if (Model.ErrorG == string.Empty)
{
<tr>
<td colspan="5">
<u><b>#Html.Label("Guarantors:")</b></u>
</td>
</tr>
<tr>
#for (int i = 0; i < Model.Guarantors.Count; i++)
{
<td>
#Html.CheckBoxFor(model => Model.Guarantors[i].isChecked)
#Html.DisplayFor(model => Model.Guarantors[i].GuarantorFirstName) #Html.DisplayFor(model => Model.Guarantors[i].GuarantorLastName)
</td>
}
</tr>
}
else
{
<tr>
<td>
<b>#Html.DisplayFor(model => Model.ErrorG)</b>
</td>
</tr>
}
}
<tr>
<td colspan="3">
<input type="submit" name="submitbutton" id="btnRefresh" value='Refresh' />
</td>
#if (Model.ShowGeneratePDFBtn == true)
{
<td>
<input type="submit" name="submitbutton" id="btnGeneratePDF" value='Generate PDF' />
</td>
}
</tr>
<tr>
<td colspan="5">
#Model.Error
</td>
</tr>
}
</table>
</div>
<script type="text/javascript">
$('btnRefresh').on('click', '#btnRefresh', function () {
Refresh();
});
function Refresh() {
var LoanID = $("#LoanID").val();
if (LoanID != "") {
document.forms[0].submit();
}
else {
alert("Please enter a LoanId");
}
}
</script>
I know this is a very old question, but answering this might help people like who are struggling with this issue.
I had a similar issue. The problem lies here:
<table style="width: 1000px">
<tr>
<td colspan="5">
<img alt="BHG Logo" src="~/Images/logo.gif" />
</td>
</tr>
#using (Html.BeginForm("ProcessForm", "Home", FormMethod.Post))
{
<tr>
<td>
#(Html.Kendo().IntegerTextBox()
.Name("LoanID")
.Placeholder("Enter Loan ID")
)
</td>
</tr>
}
</table>
After begin form there are <tr> tags directly! Browsers like chrome and mozilla get confused in such cases. The <table> tag should be inside the form. If we look at your code, which was exactly what I had done, <table> tag was before #using Html.BeginForm.
Internet Explorer somehow understands this, but the other browsers don't.
When I did an inspect element I found that there was a form tag within each <tr> tag and it always returned FormCollection as null. Simply defining <table> within form solved my problem.
So here's how it should be:
<table style="width: 1000px">
<tr>
<td colspan="5">
<img alt="BHG Logo" src="~/Images/logo.gif" />
</td>
</tr>
<tr><td>
#using (Html.BeginForm("ProcessForm", "Home", FormMethod.Post))
{
<table>
<tr>
<td>
#(Html.Kendo().IntegerTextBox()
.Name("LoanID")
.Placeholder("Enter Loan ID")
)
</td>
</tr>
</table>
}
</td></tr>
</table>
I just found out what the issue is by experimneting.
The Telerik MVC widgets don't emit any FormCollection data!!!!
Only EditorFor and TextBoxFor emit these values, plus the input buttons.
What good are these widgets if I can't use the FormCollection values from them???? Especially the DropDownList where I can retrireve data and need the selected value to pass onto other methods.
(This would be better suited as comment, but I can't comment yet)
For future reference, here's a spec (W3C might have something different) for what gets submitted when a form is submitted:
http://www.whatwg.org/specs/web-apps/current-work/multipage/forms.html#category-submit
You can look at whatever HTML was generated to make sure it gets submitted. You could also use something like Fiddler to look at the Http request
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.......
I am new at MVC asp .net.
I have a grid in which I am adding rows.
Now I want to perform mulitple rows insertion in a table at once.
How can I do that. SO multiple rows will be added in MVC.
Any help would be appericiated.
You want to learn how to ModelBind to a Collection. There are many answers here already for this technique.
https://stackoverflow.com/search?q=model+binding+to+a+collection
http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx
Do you mean something like this?.
<table class="table" style="vertical-align: middle;">
<thead>
<tr>
<th>
#Html.DisplayNameFor(model => model.title)
</th>
<th style="text-align: center;">
#Html.DisplayNameFor(model => model.imgAr)
</th>
<th>
#Html.DisplayNameFor(model => model.created)
</th>
<th></th>
</tr>
</thead>
<tbody id="tblOfContent">
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.title)
</td>
<td style="text-align: center;">
<img src="~/newsImages/#item.imgAr" class="img-thumbnail" />
</td>
<td>
#item.created.ToShortDateString()
</td>
<td>
#Html.ActionLink("Details", "Edit", new { id = item.id }) |
#Html.ActionLink("Details", "Details", new { id = item.id })
</td>
</tr>
}
</tbody>
</table>
and in the Controller something like this:
public ActionResult Index()
{
return View(newsService.GetAll().OrderByDescending(x => x.created));
}