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
Related
This question already has answers here:
Post an HTML Table to ADO.NET DataTable
(2 answers)
Closed 5 years ago.
I am trying to display and edit a 'Permit Application'.
If it was a piece of paper the top portion would have personal details to fill in.
The bottom portion would be a vertical list of questions with a blank space at the end of each row to write an answer to each question.
So my model is a PermitApplication object which contains with a 'Requestor' object (The applicant) and an array of 'Response' objects which are questions with a string 'Answer' property.
After a lot of thrashing about I am coming to the conclusion maybe what I am trying to does not work under MVC. i.e. Give this sort of model to the view, edit the personal details, fill in the answers to the questions and post the model back.
The view displays OK but when the submit button is pressed the PermitApplication object passed back to the controller only has the personnel details filled in. The returned Responses object is null.
My MVC skills and understanding is limited so my question is 'What is the correct way to tackle this situation? My View (latest attempt) follows:
#model PermitApply.Models.LclPermitApplication
#using (Html.BeginForm())
{
<div class="form-group">
#Html.LabelFor(model => model.Requestor.FirstName, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Requestor.FirstName, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Requestor.FirstName, "", new { #class = "text-danger" })
</div>
</div>
<h2>Permit Questions</h2>
<table class="table">
<tr>
<th>
Question Id
</th>
<th>Question</th>
<th>QuestionTypeId</th>
</tr>
#foreach (var item in Model.Responses)
{
<tr>
<td>
#Html.DisplayFor(p => item.QuestionId)
</td>
<td>
#Html.DisplayFor(p => item.Question)
</td>
<td>
#Html.DisplayFor(p => item.QuestionTypeId)
</td>
<td>
<div class="col-md-10">
#Html.EditorFor(p => item.Answer, new { id = item.QuestionId })
#Html.ValidationMessageFor(p => item.Answer, "", new { #class = "text-danger" })
</div>
</td>
</tr>
}
</table>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
}
Try updating the foreach loop to below:
#count = 0;
#foreach (var item in Model.Responses)
{
<tr>
<td>
#Html.DisplayFor(p => item.QuestionId)
</td>
<td>
#Html.DisplayFor(p => item.Question)
</td>
<td>
#Html.DisplayFor(p => item.QuestionTypeId)
</td>
<td>
<div class="col-md-10">
#Html.EditorFor(p => item.Answer, new {name="Responses["+count+"].Answer", id = item.QuestionId })
#Html.ValidationMessageFor(p => item.Answer, "", new { #class = "text-danger" })
</div>
</td>
</tr>
count=count+1;
}
Please read MVC model binding to better understand how MVC binds values to send to controllers. Hope this helps.
I m stuck on this for a while now and will appreciate any help.
The value of ViewBag.SearchTerm is null when I click on the 2 item in the paged list. My List page is present in a partial view (_CentraladdrcdoQuery) as below
#using SFRS.GazMatching.Web.DAL
#model IPagedList<CentraladdrcdoQuery>
#using PagedList;
#using PagedList.Mvc;
<div id="results" class="col-md-10">
<div class="row">
<div class="col-md-4">
<table class="table pull-left table-condensed">
<tr>
<td>
#Html.DisplayNameFor(model => model.First().RecordId)
</td>
</tr>
</table>
</div>
<div class="col-md-4">
<table class="table pull-left table-condensed">
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.RecordId)
</td>
</tr>
}
</table>
</div>
<br />
</div>
<div class="row">
<div class="col-md-4 clearfix">
#Html.PagedListPager(Model, page => Url.Action("Search", new { page, ViewBag.SearchTerm }), new PagedListRenderOptions
{
LinkToFirstPageFormat = "<<",
LinkToPreviousPageFormat = "prev",
LinkToNextPageFormat = "next",
LinkToLastPageFormat = ">>",
})
</div>
</div>
The main search view is
#model IPagedList<CentraladdrcdoQuery>
#{
SearchFormViewModel searchFormViewModel = new SearchFormViewModel();
}
#Html.Partial("_SearchForm",searchFormViewModel)
<h2>Search Results</h2>
#Html.Partial("_CentraladdrcdoQuery", Model)
and the Search Controller action is
public ActionResult Search(string searchTerm, int? page)
{
var centraladdrcdoQuerylst= GetCentraladdrcdoQueryData(searchTerm,page);
ViewBag.SourceList = GetSourceList();
ViewBag.SearhTerm = searchTerm;
return View(centraladdrcdoQuerylst);
}
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);
}
I have a form that has an input section at the top of the page and in the bottom half it displays a list of the objects that were added. I need to be able to Edit and Delete these objects and I'm not sure where to start or how to do it.
This code display the list of objects.
#if (Model.ListOfRecipients != null)
{
for (int i = 0; i < Model.ListOfRecipients.Count; i++)
{
<div class='recipient-wrapper'>
<div class='decision_block'>
<table class='recipient'>
<tr>
<td class='recipient-title'>
#Html.HiddenFor(model=>model.ListOfRecipients[i].RecipientId)
<h3>
#Html.DisplayTextFor(model => model.ListOfRecipients[i].RecipientName)
#Html.HiddenFor(model => model.ListOfRecipients[i].RecipientName)
</h3>
<div class='delivery-type'>
Delivery Type: #Html.DisplayTextFor(model => model.ListOfRecipients[i].DeliveryType)
#Html.HiddenFor(model => model.ListOfRecipients[i].DeliveryType)
</div>
</td>
<td class='na express'>
#Html.CheckBoxFor(model => model.ListOfRecipients[i].ExpressIndicator)
#Html.HiddenFor(model => model.ListOfRecipients[i].ExpressIndicator)
</td>
<td class='quantity'>
<h3>
Qty #Html.DisplayTextFor(model => model.ListOfRecipients[i].Quantity)
#Html.HiddenFor(model => model.ListOfRecipients[i].Quantity)
</h3>
</td>
<td class='action'>
<input class='button edit_recipient' type='button' value='Edit' />
<input class='button delete_recipient' type='button' value='Delete' />
</td>
</tr>
</table>
<input class='button update_recipient' type='button' value='Update' />
<a class='cancel_update' href='#'>Cancel</a>
</div>
</div>
</div>
}
}
You need to write Edit and Delete action methods in your controller and then set your two buttons to call the appropriate method.
The code for the action methods will depend on several factors that may to broad to address here.
Using Razor Syntax -- sorry the others were using wrong markup:(
<input class='button edit_recipient' type='button' value='Edit'
onclick="location.href='#Url.Action("Edit", "Controller", new { id = Model.Id } )'" />
You could create a delete controller and an edit controller and in the above view have a beside each one that has a delete and edit which recieves the objects id and each button goes to it's own view where they can edit or delete
I have created a ViewModel with two things, a Contact and a list of Phones for that Contact.
My goal is to add data for a new Contact, and add a few Phones, and then save by a Controller action.
I've edited the scaffolded Create.cshtml for my Contact, added a grid for the phones. Added a javascript for creating the phones. So far so good.
The problem is when I click the Create button, and I get back to the Controller, I get no Phones. How do I (in the View) add the phone-rows to my IEnumerable?
EDIT:
Took out code in view that was not correct in this context.
My ViewModel:
public class ContactViewModel
{
public Contact Contact {get; set;}
public IEnumerable<Phone> Phones { get; set; }
}
My view:
#model PilotKibsNet.Controllers.ContactViewModel
<script type="text/javascript" src="../../Scripts/jquery-1.5.1.js"></script>
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
<script type="text/javascript">
function Add() {
$("#tbl > tbody:last").append("<tr><td>" + $("#Number").val() + "</td><td>" + $("#Kind").val() + "</td><td></td></tr>");
$("#Number").val("");
$("#Kind").val("");
}
</script>
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Contact</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Contact.Name)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Contact.Name)
#Html.ValidationMessageFor(model => model.Contact.Name)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Contact.Address)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Contact.Address)
#Html.ValidationMessageFor(model => model.Contact.Address)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Contact.City)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Contact.City)
#Html.ValidationMessageFor(model => model.Contact.City)
</div>
<legend>Phone numbers</legend>
<label>Number :</label>
#Html.TextBox("Number")
<label>Kind :</label>
#Html.TextBox("Kind")
<input type="button" value="Add" onclick="Add()" />
<table id="tbl">
<tr>
<th>
Phone
</th>
<th>
Kind
</th>
<th></th>
</tr>
<tbody>
</tbody>
</table>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
And then, in by Controller action, the Contact has the data, but the Phone is an empty list.
[HttpPost]
public ActionResult Create(ContactViewModel contactViewModel)
{
if (ModelState.IsValid)
{
contactViewModel.Contact.id = Guid.NewGuid();
db.Contacts.AddObject(contactViewModel.Contact);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(contactViewModel.Contact);
}
How do I get the Phones back to the server?!?
You have only display templates for those Phones collection. No value at all will be sent to the server. You could use hidden fields if the user is not supposed to edit the values or textboxes if he is.
Also I would replace this foreach loop in your view by an editor template:
if (Model != null)
{
#Html.EditorFor(x => x.Phones)
}
and then I will define an editor template which would be rendered for each element of the Phones collection (~/Views/Shared/EditorTemplates/Phone.cshtml):
#model Phone
<tr>
<td>
#Html.DisplayFor(x => x.Number)
#Html.HiddenFor(x => x.Number)
</td>
<td>
#Html.DisplayFor(x => x.Type)
#Html.HiddenFor(x => x.Type)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id = Model.id }) |
#Html.ActionLink("Details", "Details", new { id = Model.id }) |
#Html.ActionLink("Delete", "Delete", new { id = Model.id })
</td>
</tr>
I have used hidden fields here to persist the values of the model so that when you post the form to the server they would be sent.
Another and IMHO better approach if the user is not supposed to edit those values in the table is to simply refetch them in your POST action from your database.