This question already has answers here:
Two models in one view in ASP MVC 3
(12 answers)
Closed 6 years ago.
How can I put two models in one view. Im just new so thats why I cant understand some other answers about this question. Help me please. thank you very much for understanding. I need to finish it in time.
VIEW
#model IEnumerable, PagedList.IPagedLis<ARM2.Models.Institution>
#model PagedList.IPagedList<ARM2.Models.Institution>,
#using PagedList.Mvc;
<link href="~/Content/PagedList.css" rel="stylesheet" type="text/css" />
#{
ViewBag.Title = "Insitution";
Layout = "~/Views/Shared/_Layout.cshtml";
}
}
<div class="container-fluid" id="page-content-wrapper">
<h2>INSTITUTION MANAGEMENT</h2>
<br />
<div class="panel panel-default">
<div class="panel-heading">List of Institutions</div>
<div class="panel-body">
<button type="button" class="btn btn-primary pull-right btn-sm" data-toggle="modal" data- target="#addInstitutionModal"> Add   ; </button>
<br /><br />
<p>
#Html.ActionLink("Create New", "Create")
</p>
#using (Html.BeginForm("Index", "Insitution", FormMethod.Get))
{
<p>
Find by name: #Html.TextBox("SearchString", ViewBag.CurrentFilter as string)
<input type="submit" value="Search" />
</p>
}
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.InstitutionID)
</th>
<th>
#Html.ActionLink("Institution Name", "Index", new { sortOrder = ViewBag.NameSortParm, currentFilter = ViewBag.CurrentFilter })
</th>
<th>
#Html.DisplayNameFor(model => model.IIN)
</th>
<th>
#Html.ActionLink("Date Added", "Index", new { sortOrder = ViewBag.DateSortParm, currentFilter = ViewBag.CurrentFilter })
</th>
<th>
Action
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.InstitutionID)
</td>
<td>
#Html.DisplayFor(modelItem => item.InstitutionName)
</td>
<td>
#Html.DisplayFor(modelItem => item.IIN)
</td>
<td>
#Html.DisplayFor(modelItem => item.DateAdded)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.InstitutionID }) |
#Html.ActionLink("Details", "Details", new { id=item.InstitutionID }) |
#Html.ActionLink("Delete", "Delete", new { id=item.InstitutionID })
</td>
</tr>
}
</table>
<br />
Page #(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber) of #Model.PageCount
#Html.PagedListPager(Model, page => Url.Action("Index",
new { page, sortOrder = ViewBag.CurrentSort, currentFilter = ViewBag.CurrentFilter }))
</div>
</div>
CONTROLLER
namespace ARM2.Controllers
{
public class InstitutionsController : Controller
{
private InstitutionDBContext db = new InstitutionDBContext();
// GET: Institutions
public ActionResult Index(string sortOrder, string currentFilter, string searchString, int? page)
{
ViewBag.CurrentSort = sortOrder;
ViewBag.IDParm = String.IsNullOrEmpty(sortOrder) ? "ID_desc" : "";
ViewBag.NameSortParm = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
ViewBag.DateSortParm = sortOrder == "Date" ? "date_desc" : "Date";
if (searchString != null)
{
page = 1;
}
else
{
searchString = currentFilter;
}
ViewBag.CurrentFilter = searchString;
var insti = from s in db.institutions
select s;
if (!String.IsNullOrEmpty(searchString))
{
insti = insti.Where(s => s.InstitutionName.Contains(searchString));
}
switch (sortOrder)
{
case "ID_desc":
insti = insti.OrderByDescending(s => s.InstitutionID);
break;
case "name_desc":
insti = insti.OrderByDescending(s => s.InstitutionName);
break;
case "Date":
insti = insti.OrderBy(s => s.DateAdded);
break;
case "date_desc":
insti = insti.OrderByDescending(s => s.DateAdded);
break;
default:
insti = insti.OrderBy(s => s.InstitutionID);
break;
}
int pageSize = 10;
int pageNumber = (page ?? 1);
return View(insti.ToPagedList(pageNumber, pageSize));
}
MODEL
namespace ARM2.Models
{
public class Institution
{
public int InstitutionID { get; set; }
public string InstitutionName { get; set; }
public int IIN { get; set; }
public DateTime DateAdded { get; set; }
}
public class InstitutionDBContext : DbContext
{
public DbSet<Institution> institutions { get; set; }
}
}
This is not possible. You should create a ViewModel that includes both these models.
Related
Good evening,
Now I'll describe my situation:
Here is my Model:
[Table("Items")]
public class Item
{
[Key]
public string Id { get; set; }
public DateTime Generated { get; set; }
public string Content { get; set; }
public string UrlSeo { get; set; }
public bool IsActive { get; set; }
public int Quantity { get; set; }
public decimal Price { get; set; }
}
I;m implementing CRUD operations to DB records, but I need implement one more Action, I need to Update for example UrlSeo property in selected records in one action.
So here is my view:
#model IEnumerable<CheckBoxes.Models.Item>
#{
ViewBag.Title = "Items";
}
<dv class="page-header">
<h3>Items</h3>
</dv>
<p>
#Html.ActionLink("Create New", "Create")
</p>
#using (Html.BeginForm("ChangeUrl", "Items", FormMethod.Post))
{
<div class="row">
<div class="form-group-sm">
<div class="col-md-4">
#Html.TextBox("urlSeo", null, new { #class = "form-control" })
</div>
<div class="col-md-offset-2 col-md-4">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
<p>
</p>
</div>
<table class="table">
<tr>
<th>
<input type="checkbox" id="checkAll" />
</th>
<th>
#Html.DisplayNameFor(model => model.Generated)
</th>
<th>
#Html.DisplayNameFor(model => model.Content)
</th>
<th>
#Html.DisplayNameFor(model => model.UrlSeo)
</th>
<th>
#Html.DisplayNameFor(model => model.IsActive)
</th>
<th>
#Html.DisplayNameFor(model => model.Quantity)
</th>
<th>
#Html.DisplayNameFor(model => model.Price)
</th>
<th></th>
</tr>
#foreach (var item in Model)
{
<tr>
<th>
<input type="checkbox" class="checkBox" value="#item.Id" />
</th>
<td>
#Html.DisplayFor(modelItem => item.Generated)
</td>
<td>
#Html.DisplayFor(modelItem => item.Content)
</td>
<td>
#Html.DisplayFor(modelItem => item.UrlSeo)
</td>
<td>
#Html.DisplayFor(modelItem => item.IsActive)
</td>
<td>
#Html.DisplayFor(modelItem => item.Quantity)
</td>
<td>
#Html.DisplayFor(modelItem => item.Price)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id = item.Id }) |
#Html.ActionLink("Details", "Details", new { id = item.Id }) |
#Html.ActionLink("Delete", "Delete", new { id = item.Id })
</td>
</tr>
}
</table>
}
#section Scripts{
#Scripts.Render("~/bundles/toastr")
<!--მასიური წაშლა-->
<script>
$(document).ready(function () {
$("#checkAll").click(function () {
$(".checkBox").prop('checked',
$(this).prop('checked'));
});
});
</script>
}
And Finally My Controller:
[HttpPost]
public async Task<ActionResult> ChangeUrl(string urlSeo, string[] id)
{
foreach (var itemId in id)
{
Item item = await db.Items.FindAsync(itemId);
item.UrlSeo = urlSeo;
db.Entry(item).State = EntityState.Modified;
db.Entry(item).Property(x => x.Generated).IsModified = false;
db.Entry(item).Property(x => x.Content).IsModified = false;
db.Entry(item).Property(x => x.IsActive).IsModified = false;
db.Entry(item).Property(x => x.Price).IsModified = false;
db.Entry(item).Property(x => x.Quantity).IsModified = false;
}
await db.SaveChangesAsync();
return Json(new { success = true });
}
Now Question
How to pass all checked items to controller and input from field.
I home someone will help me.
Where was problem in view here is necessary give name for checkbox, witch equals part of controller.
#foreach (var item in Model)
{
<tr>
<th>
<input type="checkbox" class="checkBox" value="#item.Id" name="id" />
</th>
Everything worked fine, yes one more thing, better to use:
return RedirectToAction("Index");
So this is working solution.
I want to take the service information from Cshtml . But I get the error .
public class HomeController : Controller
{
[HttpGet]
public ActionResult Index()
{
ServiceController[] Services;
Services = ServiceController.GetServices();
ServicesViewModel servicesViewModel = new ServicesViewModel();
ServisModel servisler = new ServisModel();
List<ServicesViewModel> list = new List<ServicesViewModel>();
foreach (ServiceController svc in Services)
{
servicesViewModel.ServiceName = svc.ServiceName;
servicesViewModel.ServiceDisplayName = svc.DisplayName;
servicesViewModel.ServiceStatus = svc.Status;
list.Add(servicesViewModel);
}
return View(ServicesList(list));
}
public class ServicesList : IEnumerable
{
List<ServicesViewModel> liste = new List<ServicesViewModel>();
public IEnumerator GetEnumerator()
{
return new MyEnumerator(liste);
}
}
Error: CS1955 Non-invocable member 'HomeController.ServicesList' cannot be used like a method.
This is the class MyEnumerator:
public class MyEnumerator : IEnumerator
{
List<ServicesViewModel> lst = new List<ServicesViewModel>();
int CurrentLocation = -1;
public MyEnumerator(List<ServicesViewModel> p) {
this.lst = p;
}
public object Current
{
get
{
return this.lst[CurrentLocation];
}
}
public bool MoveNext()
{
CurrentLocation++;
return (CurrentLocation < this.lst.Count);
}
public void Reset()
{
CurrentLocation = -1;
}
}
And finally this is the cshtml file:
#model IEnumerable<ExampleProject.ViewModel.ServicesViewModel>
#{
Layout = "~/Views/shared/_Layout.cshtml";
ViewBag.Title = "Sunucu Yönetim Paneli | Ana Sayfa";
ViewBag.Description = "Sunucu Yönetim Paneli";
ViewBag.Keywords = "sunucu, yönetim,paneli";
}
#using (Html.BeginForm("Ara", "Home", FormMethod.Get))
{
<p>
Aranacak Kelime: #Html.TextBox("SearchString", ViewBag.CurrentFilter as string)
<input type="submit" value="Ara" />
</p>
}
<table class="table">
<tr>
<th>
Servis Adı
</th>
<th>
Servis Açıklaması
</th>
<th>
Servis Durumu
</th>
<th>
Servis Başlangıç Türü
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#item.ServiceName
#*#Html.DisplayFor(modelItem => item.allServices)*#
</td>
<td>
#*#Html.DisplayFor(modelItem => item.ServiceDisplayName)*#
</td>
<td>
#*#Model.ServiceStatus*#
#*#Html.DisplayFor(modelItem => item.ServiceDisplayName)*#
</td>
<td>
#*#Model.ServiceStartMode*#
#*#Html.DisplayFor(modelItem => item.ServiceDisplayName)*#
</td>
<td>
#*#Html.ActionLink("Başlat", "ServiceStart", "ServicesStartStop", new { #id = item.ServiceName }) |
#Html.ActionLink("Durdur", "ServiceStop", "ServicesStartStop", new { #id = item.ServiceName }) |
#Html.ActionLink("", "", "Başlatma Türü", new { #id = item.ServiceName }, null)*#
#*<input type="submit" value="Başlat" />
<input type="submit" value="Durdur" />
<input type="submit" value="Başlatma Türü" />*#
</td>
</tr>
}
</table>
public class MyEnumerator : IEnumerator
{
List<ServicesViewModel> lst = new List<ServicesViewModel>();
int CurrentLocation = -1;
public MyEnumerator(List<ServicesViewModel> p) {
this.lst = p;
}
public object Current
{
get
{
return this.lst[CurrentLocation];
}
}
public bool MoveNext()
{
CurrentLocation++;
return (CurrentLocation < this.lst.Count);
}
public void Reset()
{
CurrentLocation = -1;
}
}
My Cshtml Class.
#model IEnumerable<ExampleProject.ViewModel.ServicesViewModel>
#{
Layout = "~/Views/shared/_Layout.cshtml";
ViewBag.Title = "Sunucu Yönetim Paneli | Ana Sayfa";
ViewBag.Description = "Sunucu Yönetim Paneli";
ViewBag.Keywords = "sunucu, yönetim,paneli";
}
#using (Html.BeginForm("Ara", "Home", FormMethod.Get))
{
<p>
Aranacak Kelime: #Html.TextBox("SearchString", ViewBag.CurrentFilter as string)
<input type="submit" value="Ara" />
</p>
}
<table class="table">
<tr>
<th>
Servis Adı
</th>
<th>
Servis Açıklaması
</th>
<th>
Servis Durumu
</th>
<th>
Servis Başlangıç Türü
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#item.ServiceName
#*#Html.DisplayFor(modelItem => item.allServices)*#
</td>
<td>
#*#Html.DisplayFor(modelItem => item.ServiceDisplayName)*#
</td>
<td>
#*#Model.ServiceStatus*#
#*#Html.DisplayFor(modelItem => item.ServiceDisplayName)*#
</td>
<td>
#*#Model.ServiceStartMode*#
#*#Html.DisplayFor(modelItem => item.ServiceDisplayName)*#
</td>
<td>
#*#Html.ActionLink("Başlat", "ServiceStart", "ServicesStartStop", new { #id = item.ServiceName }) |
#Html.ActionLink("Durdur", "ServiceStop", "ServicesStartStop", new { #id = item.ServiceName }) |
#Html.ActionLink("", "", "Başlatma Türü", new { #id = item.ServiceName }, null)*#
#*<input type="submit" value="Başlat" />
<input type="submit" value="Durdur" />
<input type="submit" value="Başlatma Türü" />*#
</td>
</tr>
}
</table>
So, first error: you try to use ServicesList like a method but it is a class so you need the new keyword before class name.
Second error: in your ServicesList class you don't have a constructor with list as parameters.
To solve the problem you need to change your code in this way:
public class HomeController : Controller
{
[HttpGet]
public ActionResult Index()
{
ServiceController[] Services;
Services = ServiceController.GetServices();
ServisModel servisler = new ServisModel();
List<ServicesViewModel> list = new List<ServicesViewModel>();
foreach (ServiceController svc in Services)
{
ServicesViewModel servicesViewModel = new ServicesViewModel();
servicesViewModel.ServiceName = svc.ServiceName;
servicesViewModel.ServiceDisplayName = svc.DisplayName;
servicesViewModel.ServiceStatus = svc.Status;
list.Add(servicesViewModel);
}
return View(new ServicesList(list));
}
public class ServicesList : IEnumerable
{
private List<ServicesViewModel> liste = new List<ServicesViewModel>();
public ServicesList(List<ServicesViewModel> l) {
liste = l;
}
public IEnumerator GetEnumerator()
{
return new MyEnumerator(liste);
}
}
Then in your view (cshtml) file you need to change model type from:
#model IEnumerable<ExampleProject.ViewModel.ServicesViewModel>
To:
#model IEnumerable<ExampleProject.[PartThatIDontKnow].ServicesList>
And to solve the issues relative to this change like:
#foreach (var item in Model)
That become:
#foreach (var item in Model.GetEnumerator())
I realy don't understand what you try to do but in this way the code should be build and run without problems. In your cshtml file I can't see any part of code that try to use ServicesList. I hope to be a help. Let me know if all works fine.
Note: when you need to add informations to your question use edit (is under the text of your question) instead of write an answer. I updated your question for you.
I have two tables. First is Development region and second is Zone. Zone has got RegionID as a foreign key. I would like to populate all the row from Zone table that is related with the Region selected from the dropdown list. I cannot figure out why the value is not being passed in url string. Please help me out and suggest the best way to accomplish it. Below are the models, controllers and view.
Model Zone
public class Zone
{
[Key]
public int ZoneID { get; set; }
[Required]
[Display(Name = "Zone Code")]
[RegularExpression(#"^[a-zA-Z]*$"), StringLength(5, ErrorMessage = "Code cannot be more than 5 charachter long")]
[Column("ZCode")]
public string ZoneCode { get; set; }
[Display(Name ="Zone"),RegularExpression(#"^[A-Z]+[a-z]*$"),Required]
public string ZoneName { get; set; }
public int RegionID { get; set; }
public virtual DevRegion devregion { get; set; }
[Required]
[Display(Name ="Active")]
public Boolean isActive { get; set; }
}
Model DevRegions
public class DevRegion
{
[Key]
public int RegionID { get; set; }
[Required]
[Display(Name = "Code")]
[RegularExpression(#"^[a-zA-Z]*$"), StringLength(5, ErrorMessage = "Code cannot be more than 5 charachter long")]
[Column("RCode")]
public string RegionCode { get; set; }
[Required]
[Display(Name ="Region")]
[Column("RName")]
[RegularExpression(#"^[A-Z]+[a-zA-Z\s-]*$", ErrorMessage ="Region can only consist of alphabets, space and dash")]
[StringLength(30,ErrorMessage ="Region cannot exceed 30 characters")]
public string RegionName { get; set; }
[Required]
[Display(Name ="Active")]
public Boolean isActive { get; set; }
}
ZonesController
public class ZonesController : Controller
{
private HuRISContext db = new HuRISContext();
// GET: Zones
public ActionResult Index(int? id)
{
ViewBag.RegionID = new SelectList(db.DevRegions, "RegionID", "RegionName");
var zones = db.Zones.Include(z => z.devregion).Where(x=>x.RegionID==(int)(id??x.RegionID));
return View(zones.ToList());
}
Index.cshtml
#model IEnumerable<HuRIS.Models.Zone>
....
<p>#Html.ActionLink("Create New", "Create")</p>
#using (Html.BeginForm("Index","Zones",FormMethod.Get))
{
#Html.AntiForgeryToken();
<div class="panel panel-info">
<div class="panel-body">
<div class="form-group center-block">
<label for="RegionID" class="control-label">Region:</label>
#Html.DropDownList("RegionID", null, "Show all Zones", htmlAttributes: new { #class = "form-control", #onchange = "this.form.submit();" })
</div>
</div>
</div>
}
<table class="table">
<tr>
<th>#Html.DisplayNameFor(model => model.devregion.RegionName)</th>
<th>#Html.DisplayNameFor(model => model.ZoneCode)</th>
<th>#Html.DisplayNameFor(model => model.ZoneName)</th>
<th>#Html.DisplayNameFor(model => model.isActive)</th>
<th></th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>#Html.DisplayFor(modelItem => item.devregion.RegionName</td>
<td>#Html.DisplayFor(modelItem => item.ZoneCode)</td>
<td>#Html.DisplayFor(modelItem => item.ZoneName)</td>
<td>#Html.DisplayFor(modelItem => item.isActive)</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id = item.ZoneID }) |
#Html.ActionLink("Details", "Details", new { id = item.ZoneID }) | #Html.ActionLink("Delete", "Delete", new { id = item.ZoneID })
</td>
</tr>
}
</table>
JQuery
$(document).ready(function () {
$(".form-control").change(function () {
$.ajax({
url: "~/ZonesController/Index",
type: 'GET',
cache: false,
data: { RegionID: $(".form-control").val() },
success: function (data) {
}
});
});
});
index method as shown below
public ActionResult Index()
{
ViewBag.Region = new SelectList(db.DevRegions, "RegionID", "RegionName");
var allzones = db.Zones.Include(z => z.devregion);
return View(allzones.ToList());
}
create new method as Shown below to accept the id selected on dropdown change event and create the partial view to load on the list of data from the table depending on what is selected on the dropdown:
public ActionResult ZoneList(int? id)
{
var zones = db.Zones.Include(z => z.devregion).Where(x => x.RegionID == (int)(id ?? x.RegionID));
return PartialView("~/Views/PartialViews/_ZoneList.cshtml", zones.ToList());
}
changed javascript as follows.
$("#Region").change(function () {
var selectedID = $(this).val();
$.get('/Zones/ZoneList/' + selectedID, function (data) {
$('.table').html(data);
//$('.table').fadeOut("linear");
//$('.table').fadeIn("linear");
});
});
});
on the index.cshtml changed the code as follows:
#model IEnumerable<HuRIS.Models.Zone>
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken();
<div class="panel panel-info">
<div class="panel-body">
<div class="form-group center-block">
<label for="RegionID" class="control-label">Region:</label>
#Html.DropDownList("Region", null, "Show all Zones", htmlAttributes: new { #class = "form-control"})
</div>
</div>
</div>
}
#{
Html.RenderPartial("~/Views/PartialViews/_ZoneList.cshtml", Model);
}
partial view _ZoneList.cshtml
#model IEnumerable<HuRIS.Models.Zone>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.devregion.RegionName)
</th>
<th>
#Html.DisplayNameFor(model => model.ZoneCode)
</th>
<th>
#Html.DisplayNameFor(model => model.ZoneName)
</th>
<th>
#Html.DisplayNameFor(model => model.isActive)
</th>
<th></th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.devregion.RegionName)
</td>
<td>
#Html.DisplayFor(modelItem => item.ZoneCode)
</td>
<td>
#Html.DisplayFor(modelItem => item.ZoneName)
</td>
<td>
#Html.DisplayFor(modelItem => item.isActive)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id = item.ZoneID }) |
#Html.ActionLink("Details", "Details", new { id = item.ZoneID }) |
#Html.ActionLink("Delete", "Delete", new { id = item.ZoneID })
</td>
</tr>
}
I am following Conto University tutorial concerning the paging and filtering implementation. I want to filter my results (IEnumerable) by passing multiple values and not just a string(for example idnumber,statusid...). I want to validate my filtering input values( idnumber,statusid..) So I decided to use a strongly typed viewModel and an Ajax Beginform as I want that to be done asynchronous.The problem I have is while in the Conto University tutorial the filter is just a string and can be passed through viewbag, I canot find a way to pass a viewmodel bag to the controoller.I can pass the viewmodel from controller to view and I can even implenet the filtering but whenever I click on change page the previously applied filter is removed. So back to the tutorial the use the viewbag to pass the previous applied filter from view back to the controller. Is there a way to pass a viewmodel(as I said i got a viewmodel as filter) back to the conrooler? My classes look like this
public class Student
{
public int ID
public int stasusid
public int idnumber
public string Lastname
public string Firstanme
public int Grade
public virtual School
}
The viewModel I use is almost the same with my student class but also contains an enumerator to check if is empty and does not contain any virtual memebers-navigation
public class FilterPerson
{
public int stasusid
public int idnumber
public string Lastname
public string Firstanme
public int Grade
public int SchoolID
public bool Empty
{
get
{
return (!stasusid.HasValue &&
!idnumber.HasValue&&
!Grade.HasValue &&
!SchoolID.HasValue &&
string.IsNullOrWhiteSpace(Lastname) &&
string.IsNullOrWhiteSpace(Firstanme));
}
}
}
My controller is almost the same with the tutorial with the difference that I use a model instead of searchstring to filter the results
public ViewResult Index(string sortOrder, string currentFilter, ViewModels.FilterPerson filter, int? page)
{
ViewBag.CurrentSort = sortOrder;
ViewBag.NameSortParm = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
ViewBag.GradeSortParm = sortOrder == "grade_asc" ? "grade_desc" : "grade_asc";
ViewBag.StatusSortParm=ortOrder == "status_asc" ? "status_desc" : "status_asc";
ViewBag.IdNumberSortParm=ortOrder == "idnumber_asc" ? "idnumber_desc" : "idnumber_asc";
ViewBag.SchoolSortParm = sortOrder == "school_asc" ? "school_desc" : "school_asc";
var students = from s in db.Students select s;
if (!filter.Empty )
{
Cards = db.Students.Where(
s => (String.IsNullOrEmpty(filter.FirstName) || s.Firstname.Contains(filter.FirstName))&&
(String.IsNullOrEmpty(filter.LastName) || s.Lastname.Contains(filter.LastName)) &&
(!filter.stasusid.HasValue || s.Status.stasusid== filter.stasusid) && (!filter.grade.HasValue || s.grade== filter.grade) &&
(!filter.idnumber.HasValue || s.idnumber== filter.idnumber)
(!filter.SchoolID.HasValue || s.School.ID== filter.SchoolID)
}
ViewBag.CurrentFilter = filter;
switch (sortOrder)
{
case "name_desc":
students = students.OrderByDescending(s => s.LastName);
break;
case "grade_asc":
students = students.OrderBy(s => s.grade);
break;
case "grade_desc":
students = students.OrderByDescending(s => s.grade);
break;
case "status_asc":
students = students.OrderBy(s => s.stasusid);
break;
case "status_desc":
students = students.OrderByDescending(s => s.stasusid);
break;
case "idnumber_asc":
students = students.OrderBy(s => s.idnumber);
break;
case "idnumber_desc":
students = students.OrderByDescending(s => s.idnumber);
break;
default: // Name ascending
students = students.OrderBy(s => s.LastName);
break;
}
int pageSize = 3;
int pageNumber = (page ?? 1);
return View(students.ToPagedList(pageNumber, pageSize));
}
and finally my view looks like this
#model PagedList.IPagedList<ContosoUniversity.Models.Student>
#using PagedList.Mvc;
table class="table">
<tr>
<th>
#Html.ActionLink("Last Name", "Index", new { sortOrder = ViewBag.NameSortParm, currentFilter = ViewBag.CurrentFilter })
</th>
<th>
#Html.ActionLink("First Name", "Index", new { sortOrder = ViewBag.NameSortParm, currentFilter = ViewBag.CurrentFilter })
</th>
<th>
#Html.ActionLink("Grade", "Index", new { sortOrder = ViewBag.GradeSortParm, currentFilter = ViewBag.CurrentFilter })
</th>
<th>
#Html.ActionLink("School id", "Index", new { sortOrder = ViewBag.SchoolSortParm , currentFilter = ViewBag.CurrentFilter })
</th>
<th>
#Html.ActionLink("ID", "Index", new { sortOrder = ViewBag.IdNumberSortParm, currentFilter = ViewBag.CurrentFilter })
</th>
<th>
#Html.ActionLink("Status", "Index", new { sortOrder = ViewBag.StatusSortParm, currentFilter = ViewBag.CurrentFilter })
</th>
<th></th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.LastName)
</td>
<td>
#Html.DisplayFor(modelItem => item.FirstMidName)
</td>
<td>
#Html.DisplayFor(modelItem => item.Grade)
</td>
<td>
#Html.DisplayFor(modelItem => item.SchoolID)
</td>
<td>
#Html.DisplayFor(modelItem => item.idnumber)
</td>
<td>
#Html.DisplayFor(modelItem => item.stasusid)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id = item.ID }) |
#Html.ActionLink("Details", "Details", new { id = item.ID }) |
#Html.ActionLink("Delete", "Delete", new { id = item.ID })
</td>
</tr>
}
</table>
<br />
Page #(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber) of #Model.PageCount
#Html.PagedListPager(Model, page => Url.Action("Index",
new { page, sortOrder = ViewBag.CurrentSort, currentFilter = ViewBag.CurrentFilter }))
and I implement my filter using a partial view and an ajax begin form:
#using (Ajax.BeginForm("Index", "Student", new AjaxOptions { UpdateTargetId = "Results", HttpMethod = "Post" }))
{
<div class="editor-label">
#Html.LabelFor(idnumber)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.idnumber)
#Html.ValidationMessageFor(model => model.idnumber)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.LastName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.LastName)
#Html.ValidationMessageFor(model => model.LastName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.FirstName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.FirstName)
#Html.ValidationMessageFor(model => model.FirstName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Grade)
#Html.ValidationMessageFor(model => model.Grade)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.SchoolID)
#Html.ValidationMessageFor(model => model.SchoolID)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.statusid)
#Html.ValidationMessageFor(model => model.statusid)
</div>
<input type="submit" class="SearchCards" value="Search" />
}
So the basic problem I face is that when i click on change page I can't pass the already applied filter back to the controller as it is not a string anymore but a viewmodel class filter. Any help would be really appreaciated
I have an MVC 5 app where I am using a for loop so I can bind a collection when passing back to the controller. This works fine for all my properties except for the one that is based on a DropDownFor type.
The problem is the name of the property is not getting set to "product.[0].TypeOfSubscription.
I have tried 3 different ways: The first 2 method end up with a name of [0].TypeOfSubscription and the 3rd one does have the correct name product[0].TypeOfSubscription but there is no binding occuring when I pass it back to the controller.
I think the problem is that the 3rd option is binding but because it is hidden it is not getting the selected value assigned.
#Html.EnumDropDownListFor(modelItem => Model[i].TypeOfSubscription)
#Html.EnumDropDownListFor(modelItem => Model[i].TypeOfSubscription,
new { name = "product[" + #i + "].TypeOfSubscription"})
#Html.Hidden("product[" + #i + "].TypeOfSubscription",
Model[i].TypeOfSubscription)
Model
public class VmStoreProducts
{
public VmStoreProducts()
{
NoOfUsers = 1;
}
public enum SubscriptionType
{
Monthly,
Annual
}
public int MojitoProductId { get; set; }
[Display(Name = "Category")]
public string ProductCategory { get; set; }
public virtual string Name { get; set; }
public string Description { get; set; }
[Display(Name = "Image")]
public byte[] ImageData { get; set; }
[Display(Name = "Type of Subscription")]
public SubscriptionType TypeOfSubscription { get; set; }
public decimal Price { get; set; }
[Display(Name = "No. of Users")]
public int NoOfUsers { get; set; }
[Display(Name = "Total Price")]
[DisplayFormat(DataFormatString = "{0:C}")]
public decimal TotalPrice { get; set; }
}
For Loop - View
#model PagedList.IPagedList<VmStoreProducts>
#using Mojito.Domain
#using PagedList.Mvc;
<link href="~/Content/PagedList.css" rel="stylesheet" type="text/css" />
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Mojito Products</h2>
<div class="col-md-9"></div>
<div class="col-md-3">
#using (Html.BeginForm("Index", "MojitoProducts", FormMethod.Get))
{
<p>
#Html.TextBox("SearchString", ViewBag.CurrentFilter as string)
<input type="submit" value="Search" />
</p>
}
</div>
#using (Html.BeginForm("AddToCart", "ShoppingCart", FormMethod.Post))
{
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.FirstOrDefault().ImageData)
</th>
<th>
#Html.ActionLink("Category", "Index", new { sortOrder = ViewBag.SortByCategory, currentFilter = ViewBag.CurrentFilter })
</th>
<th>
#Html.ActionLink("Product", "Index", new { sortOrder = ViewBag.SortByProduct, currentFilter = ViewBag.CurrentFilter })
</th>
<th>
#Html.DisplayNameFor(model => model.FirstOrDefault().Description)
</th>
<th>
#Html.DisplayNameFor(model => model.FirstOrDefault().TypeOfSubscription)
</th>
<th>
#Html.ActionLink("Price", "Index", new { sortOrder = ViewBag.SortByPrice, currentFilter = ViewBag.CurrentFilter })
</th>
<th>
#Html.DisplayNameFor(model => model.FirstOrDefault().NoOfUsers)
</th>
<th>
#Html.DisplayNameFor(model => model.FirstOrDefault().TotalPrice)
</th>
<th></th>
</tr>
#for (int i = 0; i < Model.Count; i++)
{
<tr>
<td>
#if (Model[i].ImageData != null)
{
<div class="pull-left" style="margin-right: 10px">
<img class="img-thumbnail" width="75" height="75"
src="#Url.Action("GetImage", "MojitoProducts",
new { Model[i].MojitoProductId })" />
</div>
}
</td>
<td>
#Html.DisplayFor(modelItem => Model[i].ProductCategory)
</td>
<td>
#Html.TextBox("product[" + #i + "].Name",
Model[i].Name, new { #readonly = "readonly" })
</td>
<td>
#Html.DisplayFor(modelItem => Model[i].Description)
</td>
<td>
#Html.EnumDropDownListFor(modelItem => Model[i].TypeOfSubscription)
#Html.EnumDropDownListFor(modelItem => Model[i].TypeOfSubscription,
new { name = "product[" + #i + "].TypeOfSubscription"})
#Html.TextBox("product[" + #i + "].TypeOfSubscription",
Model[i].TypeOfSubscription, new { hidden=true })
</td>
<td>
#Html.TextBox("product[" + #i + "].Price",
Model[i].Price, new { #readonly = "readonly", style = "width:50px" })
</td>
<td>
#Html.TextBox("product[" + #i + "].NoOfUsers",
Model[i].NoOfUsers, new { type = "number", min = "0", style = "width:50px" })
</td>
<td>
#Html.TextBox("product[" + #i + "].TotalPrice",
Model[i].TotalPrice, new { style = "width:50px" })
</td>
<td>
<div class="pull-right">
#if (Request.Url != null)
{
#Html.Hidden("product[" + #i + "].MojitoProductId",
Model[i].MojitoProductId)
#Html.Hidden("returnUrl", Request.Url.PathAndQuery)
}
</div>
</td>
</tr>
}
<tr>
<td colspan="6">
<div class="pull-right">
<input type="submit" class="btn btn-success" value="Add to cart" />
</div>
</td>
</tr>
</table>
}
Controller Method
public ActionResult AddToCart(List<VmStoreProducts> product, string returnUrl)
{
ShoppingCart cartObjects = (Session["CartObjects"] as ShoppingCart) ?? new ShoppingCart();
Session["CartObjects"] = cartObjects;
foreach (var item in product)
{
if (item.NoOfUsers > 0)
{
cartObjects.AddItem(item);
}
}
return RedirectToAction("Index", new { returnUrl });
}
Move the definition of the enum outside the VmStoreProducts class
public enum SubscriptionType
{
Monthly,
Annual
}
public class VmStoreProducts
{
public VmStoreProducts()
{
NoOfUsers = 1;
}
public int MojitoProductId { get; set; }
....
}
The for loop will name the selects
[0].TypeOfSubscription
[1].TypeOfSubscription
....
which will correctly bind on postback (assuming your action method is public ActionResult AddToCart(IEnumerable<VmStoreProducts> products) {...
Also, do not use
#Html.TextBox("product[" + #i + "].Name", Model[i].Name, new { #readonly = "readonly" })
Since you already using a DisplayFor for the same property a hidden input seems more appropriate, so
#Html.HiddenFor(m => m[i].Name)
or if you want to display it twice
#Html.TextBoxFor(m => m[i].Name, new { #readonly = "readonly" })
This applies to the other properties as well
Try using a textbox and hide it to persist the value or use another 'data- property
In case of DropDownListFor, when data is posted back to controller, selected value get lost, so we need to have a hidden textbox to keep the selected value