How to implement pagedlist in mvc when using view models? - c#

I am using viewmodel concept in mvc 4. I am posting data to db and as soon as post displaying in grid below also. So I have used view model concept. This is my viemodel class
public class MyViewModel
{
public document upload_document { get; set; }
public IList<document> Upload_List { get; set; }
}
I have many fields in document so I am not posting fields. I have gone through some articles and they are returning something like this: return View(students.ToList());where student is var. But I am returning model in all action methods. Also in view they have written
#model PagedList.IPagedList<ContosoUniversity.Models.Student>
#using PagedList.Mvc;
but I have this in my view
#model c3card.Dal.EDModel.MyViewModel
So, how can return model that contains pagenum,page size? How can I use this pagedlist concept when using view models?

If you need to map your entities to view models and still be able to page through them, then you need to use StaticPagedList. In order for the standard method of using PagedList to work, it needs to be passed a queryable (unevaluated), so that it can limit the query to only pull the proper number of records. If you're mapping to a view model, though, then that's going to evaluate the query.
What you need is something like:
public ActionResult Students(int? page)
{
var pageNumber = page ?? 1;
var pageSize = 10;
var totalStudents = db.Students.Count();
var students = db.Students.Skip((pageNumber - 1) * pageSize).Take(pageSize);
var model = // map `students` to your view model
var pagedList = new StaticPagedList<MyViewModel>(model, pageNumber, pageSize, totalStudents);
return View(pagedList);
}
Then, the model for your view is:
#model PagedList.IPagedList<Namespace.To.MyViewModel>

Related

ASP.Net Scaffolded MVC Struggling to populate a dropdownlist with Entity Framework

I'm struggling to conceptualise this because every resource I have found on Google has presented a different way to do it.
I have, at the moment generated razor views pertaining to a scaffolded controller using entity Framework. My controller looks like this:
// GET: tbl_computerinfo
public ActionResult Index()
{
var tbl_computerinfo = db.tbl_computerinfo.Include(t => t.tbl_equipment);
tbl_computerinfo = tbl_computerinfo.Where(c => c.Company == "Company Name");
return View(tbl_computerinfo.ToList());
}
My Model is quite large but is just a generated entity framework model built on two tables linked with a foreign key tbl_computerinfo and tbl_equipment.
There is a string field called company in tbl_computerinfo. I need to select all the unique company values in the database and then use that to populate a dropdown which would exist on the index view. The selection of a company on that dropdown list should then filter the results in index view to only pull back entries with that company name. Any pointing in the right direction would be gratefully appreciated.
You need to create a ViewModel:
public class ComputerInfoViewModel
{
public List<string> CompanyList {get; set;}
public ComputerInfo ComputerInfo {get; set;}
}
In your Index method you populate this and pass it to the View:
public ActionResult Index()
{
var model = new ComputerInfoViewModel
{
CompanyList = /* populate this with your list of companies */
ComputerInfo = /* populate this with what? */
};
return View(model);
}
In your View, you declare the model:
#model ComputerInfoViewModel
And you can access the model properties for display using #Model.CompanyList and #Model.ComputerInfo

MVC 4 how pass data correctly from controller to view

I currently have a controller with a LINQ statement that i am passing data from to my view. I am trying to find a more efficient and better coding method to do this.
My home controller statement is as follows.
Var Melt
Furnace1 =
(from item in db.tbl_dppITHr
where item.ProductionHour >= StartShift && item.ProductionHour <= EndDate
select item).Sum(x => x.Furnace1Total),
ViewData["Furnace1Total"] = Melt.Furnace1;
In my view i then reference the ViewData To show this. Using
#model dynamic
Now i have quite alot of linq statements inside the Index method. And for each one i am doing the ViewData[]
I am hoping that someone can show how i pass more than one var from a controller across to a view without the ViewData or ViewBag methods. And how i would get access to this within my view.
You should create a ViewModel with all of your data needed and then pass that down to the view.
public class ViewModel
{
public List<int> Melt1 { get; set; }
public void LoadMeltProperties()
{
if (Melt1 == null)
{
Melt1 = new List<int>();
}
Melt1 = (from item in db.tbl_dppITHr
where item.ProductionHour >= StartShift && item.ProductionHour <= EndDate
select item).Sum(x => x.Furnace1Total).ToList();
}
public ViewModel Load()
{
LoadMeltProperties();
return this;
}
}
public ActionResult YourControllerAction()
{
var vm = new ViewModel().Load();
return View("ViewName", vm);
}
Then in your View you can use a strongly typed model rather than dynamic
#model ViewModel
You can then iterate over your ViewModel properties via:
foreach(var melt in Model.Melt1) {
// do what you require
}
IMHO, you should create a ViewModel an pass data using it.
Create a class
public class MyViewModel
{
public <MeltFurnace1Type> MeltFurnace1{get;set;}
}
In Action Method
public ActionResult Action()
{
MyViewModel vm = new MyViewModel();
vm.MeltFurnace1 = something;
return View("YourViewName", vm);
}
In View
#model MyViewModel
//You can access your property using
Model.MeltFurnace1
If you need to pass data actually from the controller and its data is depend on internal state or input controller parameters or has other properties of "business data" you should use Model part from MVC pattern:
Model objects are the parts of the application that implement the
logic for the application's data domain. Often, model objects retrieve
and store model state in a database. For example, a Product object
might retrieve information from a database, operate on it, and then
write updated information back to a Products table in a SQL Server
database.
You can see details here or look to the Models and Validation in ASP.NET MVC part of Microsoft tutorial.
Add model class:
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public string City { get; set; }
}
Pass model object to the view:
public ActionResult Index()
{
var model = GetModel();
return View(model);
}
Add strongly typed View via define model type:
#model Person
Use Model variable in your view:
#Model.City
Use models instead
var Melt
Furnace1 =
(from item in db.tbl_dppITHr
where item.ProductionHour >= StartShift && item.ProductionHour <= EndDate
select item).Sum(x => x.Furnace1Total),
return View("SomeVIew",MeltFurnace1)
In view#model "TypeOfMeltFurnace1"
You can reference model in view by property Model
If someone is still looking for options…
You also can pass object from Controller to View, if you don’t use any particular Model for the View. To pass just a single (or maybe few) parameter from the Controller to the View, you can do it inside View() Method.
In the Controller:
public async Task<IActionResult> Update(int id)
{
return View(new { Id = id });
}
Then in the View you can access your parameter like this (assuming you don’t use any other Model inside your View):
<div>
#Html.ActionLink("Link name", "ControllerMethod", "ControllerName", new { id = (int)Model.Id })
</div>
Otherwise, like already mentioned, pass your model inside View() Method.

MVC page that displays multiple, related, ViewModels updating with ajax

I have some simple list management pages, each is strongly typed against the following ViewModel
public class ListManagementIndexViewModel
{
public Guid Id { get; set; }
public string Name { get; set; }
}
I have Views for Category, Priority, Status and a few other drop downs, there's some AutoMapper configuration that ensures the Name property is bound to whatever the Domain model might have for the entity. The idea is that the systems administrators are able to manage what's in these lists (Create new, Edit existing and Delete). This gives me an Index view for each like this:
I would like to put all of these on a single page, rather than have separate views for each. I think partials are probably the way to do this, but I'm not clear whether that's a recommended approach or not?
Also I'm not clear on how to handle the Controller(s). As things stand; with the PriorityController I have the following Index ActionResult
public ActionResult Index(string searchString, string currentFilter, int? page)
{
if (Request.HttpMethod == "GET")
searchString = currentFilter;
ViewBag.CurrentFilter = searchString;
int pageNumber = page ?? 1;
var query = Session.QueryOver<Priority>();
if (!string.IsNullOrWhiteSpace(searchString))
query.WhereRestrictionOn(p => p.PriorityName)
.IsInsensitiveLike(String.Format("%{0}%", searchString));
var result = query.OrderBy(p => p.PriorityName).Asc.List();
var viewModel = AutoMapper.Mapper.Map<IEnumerable<Priority>,
IEnumerable<ListManagementIndexViewModel>>(result)
.ToPagedList(pageNumber, PageSize);
return View(viewModel);
}
While I could move that to a 'Master' single list management page I would also need to do the same for the other list types, but then what would my ViewModel need to look like, there are currently 5 lists to manage, so I have 5 controllers doing exactly the same thing, only the types vary. If I were to put all that on 1 'Master' single view page I would somehow need to stuff all 5 PagedList collections into 1 ViewModel and then in the 'Master' single version pass the data off to the relevant Partials razor code?
Also how would I handle the other Controller actions (Edit, Create and Delete)?
Update
Thinking on my feet - if the unified / single view page ViewModel were:
public class ListManagementIndexViewModel
{
public Dictionary<string, IPagedList<T>> ManagementLists { get; set; }
}
and the SinglePageController were
public ActionResult Index(string searchString, string currentFilter, int? page)
{
var priorities = GetPriorities(searchString, currentFilter, page);
var categories = GetCategories(searchString, currentFilter, page);
Dictionary<string, IPagedList> viewModel
= new Dictionary<string, IPagedList<T>>();
viewModel.Add("Priorities", priorities);
viewModel.Add("Categories", categories);
return View(viewModel);
}
I could move the existing logic out to a private method
private IPagedList<Priority> GetPriorities(string searchString,
string currentFilter, int? page)
{
if (Request.HttpMethod == "GET")
searchString = currentFilter;
ViewBag.CurrentFilter = searchString;
int pageNumber = page ?? 1;
var query = Session.QueryOver<Priority>();
if (!string.IsNullOrWhiteSpace(searchString))
query.WhereRestrictionOn(p => p.PriorityName)
.IsInsensitiveLike(String.Format("%{0}%", searchString));
var result = query.OrderBy(p => p.PriorityName).Asc.List();
var priorities = AutoMapper.Mapper.Map<IEnumerable<Priority>,
IEnumerable<ListManagementIndexViewModel>>(result)
.ToPagedList(pageNumber, PageSize);
return priorities;
}
Then in my View the model would contain the ManagementLists collections and I could foreach the results into html tables as I'm currently doing but on separate pages.
However a paging through the results would then result in all lists tables paging rather than just the Priorities table. How would I make each update with Ajax, so paging in one table would only update the list in that one table? If I were to re-include searching, which is currently in the ActionResult method, but not implemented in the UI that would also need to update just the Priorities table. For example if I entered "High" in the search for Priority I would only want to query the Priority table and update it and not run 5 queries to the database to search for "High" in Category or any of the other lists.
I think you should only use a partial if you intend to use it again. I see too often people creating them to help break down the code, but they're never used again.
It would be more organised to have the 5 lists under the one page, that way they're all in the one model and are centrally managed by one controller/model.

Sending IEnumerable to a view that already contains a model

This is the view:
#model tgpwebged.Models.sistema_DocType
...
this model is an entity used with textBoxFor and others html helpers
This is the controller.
public ActionResult AdminSettingAddTipo()
{
IEnumerable<string> indices;
using (tgpwebgedEntities context = new tgpwebgedEntities())
{
var obj = from u in context.sistema_Indexes select u.idName;
indices = obj.ToList();
}
return PartialView(indices);
}
I have all I need here, I am using a model to create with the view so I am not allowed to send ´indices´ as a model because it´s not allowed to have 2 models in one view.
I don´t want to use ´Tupe´ now a parent view. I just want to know how is the best way to send my IEnumerable to the view.
I was thinking of ViewBag for the last option but I am avoiding ViewBag.
thanks
ViewBag is not a good choice. Create ViewModel using your list and your current Model:
public class YourViewModel
{
public sistema_DocType Type { get; set; }
public IEnumerable<string> Indices {get;set;}
}
Hope,it will help.
If you don't want to use ViewBag for whatever reason, you could create a Model specifically for the view that contains the info from the old model and the new indices you want. This is a common pattern in MVC development. You can even have the ViewModel be a Decorator for your current Model.
http://geekswithblogs.net/michelotti/archive/2009/10/25/asp.net-mvc-view-model-patterns.aspx
Use strongly defined where you can, apply this to a model and send that model:
Model
public class MyModel{
public List<sistema_Indexes> indecies {get;set;}
}
Controller
MyModel model = new MyModel();
model.indecies = context.sistema_Indexes.Select(u=> u.idName).ToList();

Passing object to view error

I am getting this error when trying to pass my object to the view. I am new to MVC so please forgive me.
The model item passed into the dictionary is of type 'System.Collections.Generic.List1[<>f__AnonymousType13[System.Int32,System.String,System.Nullable1[System.DateTime]]]', but this dictionary requires a model item of type 'System.Collections.Generic.IEnumerable1[MvcApplication1.Models.storageProperty]'
I am trying to pass a list for a table that will show objects from the storageProperty table with the last date (if there is one) from the expenses table. Most properties have had at least one expense audit, some have had many, and others have had none.
Here is the code from the controller:
var viewModel = db.storageProperties.Select(s => new
{
s.storagePropertyId,
s.BuildName,
latestExpenseSurvey = (DateTime?)s.expenses.Max(e => e.expenseDate)
}).ToList();
return View(viewModel);
}
and the #model statement in the view calls for a storageproperty object. I am using mvc3 with the entity framework. It appears obvious that I cannot pass this list object in place of the storageproperty object, but I can't figure out what to do instead, how should I do this?
Thanks in advance.
Never pass anonymous objects to views. You should always pass view models.
So as always in an ASP.NET MVC application you start by defining a view model which will reflect the requirements of your view:
public class MyViewModel
{
public int StoragePropertyId { get; set; }
public string BuildName { get; set; }
public DateTime? latestExpenseSurvey { get; set; }
}
Then in your controller return an IEnumerable<MyViewModel>:
public ActionResult Index()
{
var viewModel = db.storageProperties.Select(s => new MyViewModel
{
StoragePropertyId = s.storagePropertyId,
BuildName = s.BuildName,
LatestExpenseSurvey = (DateTime?)s.expenses.Max(e => e.expenseDate)
}).ToList();
return View(viewModel);
}
and finally strongly type your view to a collection of this view model:
#model IEnumerable<MyViewModel>
<div>
#Html.EditorForModel()
</div>
Your Linq query projects to an anonymous type. You need to create a named type for this projection in order to refer to it from the view.

Categories