How to sort a Grid using Viewmodel not ViewBag? - asp.net-mvc

I have my code working and sorting correctly but I am using ViewBag to do so. I would like to clean up my code and use ViewModel instead to sort my grid but I'm stumped in how to do so. Any help would be greatly appreciated. Thank you.
Model
public partial class Asset
{
public int AssetKey { get; set; }
public int ProductKey { get; set; }
public string InventoryOwner { get; set; }
public string SerialNumber { get; set; }
Controller
public class InventoryManagementController : Controller
{
private Orders db = new Orders();
public ActionResult Index(int? AssetNum, string keyword, string sortOrder, string currentFilter, int? page)
{
ViewBag.OwnerSort = sortOrder == "owner_asce" ? "owner_desc" : "owner_asce";
ViewBag.AssetSort = sortOrder == "asset_asce" ? "asset_desc" : "asset_asce";
ViewBag.SerialSort = sortOrder == "serialnum_asce" ? "serialnum_desc" : "serialnum_asce";
ViewBag.ProductSort = sortOrder == "product_asce" ? "product_desc" : "product_asce";
ViewBag.Keyword = keyword;
var records = from s in db.Assets select s;
string AssetNums = AssetNum.ToString();
if (keyword != null)
{
page = 1;
}
else
{
keyword = currentFilter;
}
ViewBag.CurrentFilter = keyword;
switch (sortOrder)
{
case "asset_asce":
records = records.OrderBy(s => s.AssetKey);
break;
case "asset_desc":
records = records.OrderByDescending(s => s.AssetKey);
break;
case "serialnum_asce":
records = records.OrderBy(s => s.SerialNumber);
break;
case "serialnum_desc":
records = records.OrderByDescending(s => s.SerialNumber);
break;
case "product_asce":
records = records.OrderBy(s => s.Product.ProductName);
break;
case "product_desc":
records = records.OrderByDescending(s => s.Product.ProductName);
break;
case "owner_asce":
records = records.OrderBy(s => s.InventoryOwner);
break;
case "owner_desc":
records = records.OrderByDescending(s => s.InventoryOwner);
break;
int pageSize = 25; //Number of Records
int pageNumber = (page ?? 1);
return View(records.ToPagedList(pageNumber, pageSize));
//return View(assets.ToList());
}
View
#model PagedList.IPagedList<OrderDB.Models.Asset>
#using PagedList.Mvc;
<link href="~/Content/PagedList.css" rel="stylesheet" type="text/css" />
#{
ViewBag.Title = "Inventory HomePage";
}
<!DOCTYPE html>
<title>Index</title>
<br />
<h2>Inventory</h2>
<table class="table" border="1">
<tr>
<th>
#Html.ActionLink("Asset Tag", "Index", new { sortOrder = ViewBag.AssetSort, currentFilter = ViewBag.CurrentFilter })
</th>
<th>
#Html.ActionLink("Serial Number", "Index", new { sortOrder = ViewBag.SerialSort, keyword = ViewBag.Keyword, currentFilter = ViewBag.CurrentFilter })
</th>
<th>
#Html.ActionLink("Product", "Index", new { sortOrder = ViewBag.ProductSort, keyword = ViewBag.Keyword, currentFilter = ViewBag.CurrentFilter })
</th>
<th>
#Html.ActionLink("Inventory Owner", "Index", new { sortOrder = ViewBag.OwnerSort, keyword = ViewBag.Keyword, currentFilter = ViewBag.CurrentFilter })
</th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.ActionLink(item.AssetKey.ToString(), "Details", new { id = item.AssetKey })
</td>
<td>
#Html.DisplayFor(modelItem => item.SerialNumber)
</td>
<td>
#Html.DisplayFor(modelItem => item.Product.ProductName)
</td>
<td>
#Html.DisplayFor(modelItem => item.InventoryOwner)
</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 }))

Related

How to filter data using dropdown list in mvc

My site already have the search,sorting function. I wanted to add a filter function also but am facing a problem which is the dropdown list at the view page will not return a value to the controller that will filter out the data but somehow it won't and I didn't want to hard code the dropdown list if that is possible .
Admin Controller
public ViewResult Index(string sortOrder, string currentFilter, string searchString, string currentValue, string sortType, int? page)
{
ViewBag.CurrentSort = sortOrder;
ViewBag.sortType = new SelectList(db.MembershipTypes, "MembershipTypesId", "Name");
ViewBag.CurrentType = sortType;
//sorting
ViewBag.NameSortParm = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
ViewBag.DateSortParm = sortOrder == "Date" ? "date_desc" : "Date";
if (searchString != null || sortType != null)
{page = 1;}
else
{
searchString = currentFilter;
sortType = currentFilter;
}
ViewBag.CurrentFilter = searchString;
var customer = from a in db.Customers.Include(c => c.MembershipTypes) select a;
var x = from b in db.MembershipTypes select b;
//search
if (!String.IsNullOrEmpty(searchString))
{
customer = customer.Where(c => c.LastName.Contains(searchString)
|| c.FirstName.Contains(searchString));
}
//sorting
switch (sortOrder)
{
case "name_desc":
customer = customer.OrderByDescending(c => c.LastName);
break;
case "Date":
customer = customer.OrderBy(c => c.DateofBirth);
break;
case "date_desc":
customer = customer.OrderByDescending(c => c.DateofBirth);
break;
default:
customer = customer.OrderBy(c => c.LastName);
break;
}
int pageSize = 3;
int pageNumber = (page ?? 1);
return View(customer.ToPagedList(pageNumber, pageSize));
}
Index.cshtml
#model PagedList.IPagedList<LeafLife.Models.Customers>
#using PagedList.Mvc;
<link href="~/Content/PagedList.css" rel="stylesheet" type="text/css" />
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Index</h2>
#using (Html.BeginForm("Index", "Admin", FormMethod.Get))
{
<p>
Find by name: #Html.TextBox("SearchString", ViewBag.CurrentFilter as string)
#Html.DropDownList("MembershipTypesId", ViewBag.CurrentFilter as string)
<input type="submit" value="Search" />
</p>
}
<table class="table">
<tr>
<th>
MembershipTypes
</th>
<th>
Username
</th>
<th>
FirstName
</th>
<th>
#Html.ActionLink("Last Name", "Index", new { sortOrder = ViewBag.NameSortParm, currentFilter = ViewBag.CurrentFilter })
</th>
<th>
Email
</th>
<th>
#Html.ActionLink("Date of Birth", "Index", new { sortOrder = ViewBag.DateSortParm, currentFilter = ViewBag.CurrentFilter })
</th>
<th>
Password
</th>
<th></th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.MembershipTypes.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.Username)
</td>
<td>
#Html.DisplayFor(modelItem => item.FirstName)
</td>
<td>
#Html.DisplayFor(modelItem => item.LastName)
</td>
<td>
#Html.DisplayFor(modelItem => item.Email)
</td>
<td>
#Html.DisplayFor(modelItem => item.DateofBirth)
</td>
<td>
#Html.DisplayFor(modelItem => item.Password)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id = item.IC }) |
#Html.ActionLink("Details", "Details", new { id = item.IC }) |
#Html.ActionLink("Delete", "Delete", new { id = item.IC })
</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 }))
I have solved my own question the solution is in the AdminController simply add another if statement which need to change a new parameter in it
if (!String.IsNullOrEmpty(searchVar))
{
customer = customer.Where(c => c.MembershipTypes.Name.Contains(searchVar));
}
After that you are required to hardcoded in the value of the dropdownlist, In my case i don't have a lot of reference data which is suitable to hardcoded in
#Html.DropDownList("SearchVar", new List<SelectListItem>
{
new SelectListItem{ Text="Assiants", Value = "Assiants" },
new SelectListItem{ Text="Secretary", Value = "Secretary" },
new SelectListItem{ Text="Ambassador", Value = "Ambassador" }
}, "Select", ViewBag.CurrentTypes as string)
<input type="submit" value="Search" />

How could I use limit and offset with pagedlist to paginate in Asp.Net MVC?

I'm using PagedList to paginate but it need to has all records in a list and then make the pagination and it will waste a long time to render the page, so, I want to use LIMIT and OFFSET with PagedLit to make a real pagination and waste a short time.
How could I use PagedList with LIMIT and OFFSET to create a real pagination ?
trying
Model
public class SearchUsuarioModel{
public IPagedList<UpUsuarioAdminModel> listaModel { get; set; } //list model
public IPagedList<Usuario> listaObject { get; set; } //list all objects
//Status
public IEnumerable<SelectListItem> status { get; set; }
public int statusSelected { get; set; }
public String nome { get; set; }
public String role { get; set; }
public int limit { get; set; }
public int offset { get; set; }
public int pageSize { get; set; }
public int pageNumber { get; set; }
public SearchUsuarioModel(){
listaModel = new List<UpUsuarioAdminModel>().ToPagedList(1, 50);
}
}
Controller
public ActionResult viewAllAdmin(int? page, String nome, String role, int? offSet){
//model
SearchUsuarioModel model = new SearchUsuarioModel();
model.nome = nome;
model.role = role;
model.limit = 3;
model.offset = offSet ?? 0;
model.pageNumber = page ?? 1;
model.pageSize = model.limit;
//listas
IList<Usuario> _listaObject = new List<Usuario>();
IList<UpUsuarioAdminModel> _listaModel = new List<UpUsuarioAdminModel>();
UsuarioDAO dao = new UsuarioDAO();
try{
_listaObject = dao.findAllOffset(model.limit, model.offset);
} catch (Exception e){
Debug.WriteLine("viewAllAdmin UsuarioController: " + e.Message);
}
if (_listaObject.Count > 0){
foreach (Usuario u in _listaObject){
UpUsuarioAdminModel m = new UpUsuarioAdminModel();
m.id = u.id;
m.nome = u.nome;
m.email = u.email;
m.roleSelected = u.role.ToString();
m.statusDesc = u.status == 1 ? "Ativo" : "Inativo";
m.contrato = u.imgContrato;
if (u.contato != null){
//Debug.WriteLine("Telefone: " + string.IsNullOrEmpty(u.contato.telefone1));
m.telefone1 = string.IsNullOrEmpty(u.contato.telefone1) ? "" : u.contato.telefone1;
}
_listaModel.Add(m);
}
}
model.listaModel = _listaModel.ToPagedList(model.pageNumber, model.limit);
model.listaObject = dao.findAll().ToPagedList(model.pageNumber, model.limit);
return View(model);
}
HTML
<div class="panel panel-red center-block">
<div class="panel-heading bg-red clearfix">
<strong>Usuários do sistema</strong>
<div class="pull-right">
#Html.ActionLink("Novo", "addUsuarioAdmin", "Usuario", new { Class = "text-white glyphicon glyphicon-plus" })
</div>
</div>
<div class="panel-body">
<table class="table table-bordered table-responsive table-striped table-hover" id="tableView">
<thead class="CabecalhoTabela">
<tr>
<th>#ID</th>
<th>Nome</th>
<th>Email</th>
<th>Telefone</th>
<th>Perfil</th>
<th>Status</th>
<th>Controles</th>
</tr>
</thead>
<tbody class="conteudoTabela">
#foreach (UpUsuarioAdminModel m in Model.listaModel){
<tr>
<td class="text-right">#Html.DisplayFor(i => m.id)</td>
<td>#Html.DisplayFor(i => m.nome)</td>
<td class="text-lowercase">#Html.DisplayFor(i => m.email)</td>
<td class="text-center">#Html.DisplayFor(i => m.telefone1)</td>
<td class="text-center">#Html.DisplayFor(i => m.roleSelected)</td>
<td class="text-center">#Html.DisplayFor(i => m.statusDesc)</td>
<td>
#Html.ActionLink(" ", "editUsuarioAdmin", "Usuario", new { id = EncodingParams.encode(Convert.ToString(#m.id)) }, new { Class = "glyphicon glyphicon-pencil", title = "editar" })
#if (!string.IsNullOrEmpty(m.contrato))
{
#Html.ActionLink(" ", "Download", "Usuario", new { id = EncodingParams.encode(Convert.ToString(#m.id)) }, new { Class = "glyphicon glyphicon-file", title = "Contrato" })
}
</td>
</tr>
}
</tbody>
</table>
</div>
<div class="panel-footer">
Pagina #Model.listaObject.PageNumber de #Model.listaObject.PageCount
#Html.PagedListPager(Model.listaObject, page => Url.Action("viewAllAdmin", new { page = Model.pageNumber, offSet = Model.offset }))
</div>
</div>
DAO
public IList<Usuario> findAll(){
ISession _session = getSession();
IList<Usuario> list = _session.CreateQuery("FROM Usuario u ORDER BY u.id")
.List<Usuario>();
return list;
}
public IList<Usuario> findAllOffset(int limit, int offset){
ISession _session = getSession();
IList<Usuario> list = _session.CreateQuery("FROM Usuario u ORDER BY u.id")
.SetFirstResult(offset)
.SetMaxResults(limit)
.List<Usuario>();
return list;
}

Display List return from a controller to a table in view ASP.NET MVC4

I have a function in my controller class, it return a list of data, I want to display it in table structure in my view page.
i have tried the following code but it shows some error
"Class does not contain definition of GetEnumerator"
Controller
public ActionResult data(Message msg,IEnumerable<sample> dept)
{
dbconnection db = new dbconnection();
sample s = new sample();
SqlConnection con = new SqlConnection(db.GetconString());
DataTable dt;
List<examplemvc1.Models.sample> datatable = new List<sample>();
dt = db.BuildDT("select * from MVCsample");
foreach (DataRow row in dt.Rows)
{
s.FirstName = Convert.ToString(row["First Name"]);
s.LastName = Convert.ToString(row["Last Name"]);
s.Address = Convert.ToString(row["Address"]);
s.PhoneNumber = Convert.ToString(row["PhoneNumber"]);
s.Location = Convert.ToString(row["Location"]);
datatable.Add(s);
dept = datatable;
}
ViewBag.tabledata = dept;
return View(dept) ;
}
Model
public class sample
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Address { get; set; }
public string PhoneNumber { get; set; }
public string Location { get; set; }
public string tabledata { get; set; }
}
public class Message
{
public IEnumerable<sample> sampleList { get; set; }
public string MessageText { get; set; }
public string MessageFrom { get; set; }
}
View
#model examplemvc1.Models.sample
#foreach (var data in Model)
{
<table><tr><td>#data.FirstName</td></tr></table>
}
UPDATE
this is how my entire view looks like
#model List<examplemvc1.Models.sample>
#{
ViewBag.Title = "Registration Form";
}
<head>
<script type="text/javascript" src="../../Scripts/jquery-1.7.1.min.js"></script>
<link href="../../Style/sample.css" rel="stylesheet" type="text/css" />
<script src="../../Scripts/samplescript.js" type="text/javascript"></script>
</head>
<h2>
Registration Form </h2>
<body>
<table>
<tr>
<th>
First Name
</th>
</tr>
#foreach (var data in Model)
{
<tr><td>#data.FirstName</td></tr>
}
</table>
#using (Html.BeginForm())
{
<table id="table1">
<tr>
<td>
#Html.Label("Enter FirstName", new { #class = "standard_label_style" })
</td>
<td>
#Html.TextBoxFor(a => a.FirstName, new { #class = "class1", title = "Enter FirstName", id = "NameBox", placeholder = "Enter name", onkeydown = "return TextField(event)" })
<span class="errorMessage"></span>
#if (!ViewData.ModelState.IsValid)
{
<span class="field-validation-error">
#ViewData.ModelState["FirstName"].Errors[0].ErrorMessage</span>
}
</td>
</tr>
<tr>
<td>
#Html.Label("Enter LastName", new { #class = "standard_label_style" })
</td>
<td>
#Html.TextBoxFor(a => a.LastName, new { #class = "class1", placeholder = "Enter name", id = "LastNameBox", title = "Enter Lastname", onkeydown = "return TextField(event); " })
<span class="errorMessage"></span>
</td>
</tr>
<tr>
<td>
#Html.Label("Enter Address", new { #class = "standard_label_style" })
</td>
<td>
#Html.TextBoxFor(a => a.Address, new { #class = "class1", id = "AddressBox", placeholder = "Enter name", title = "Enter Address" })
<span class="errorMessage"></span>
</td>
</tr>
<tr>
<td>
#Html.Label("Enter PhoneNumber", new { #class = "standard_label_style" })
</td>
<td>
#Html.TextBoxFor(a => a.PhoneNumber, new { #class = "class1", id = "PhoneBox", placeholder = "Enter name", title = "Enter Phonenumber", onkeydown = "return ValidateNumber(event);" })
<span class="errorMessage"></span>
</td>
</tr>
<tr>
<td>
#Html.Label("Enter Location", new { #class = "standard_label_style" })
</td><td>
#Html.TextBoxFor(a => a.Location, new { #class = "class1", id = "LocationBox", placeholder = "Enter name", title = "Enter Location" })
<span class="errorMessage"></span>
</td>
</tr>
</table>
<input type="button" id="btnSave" value="Register"/>
<input type="button" value="Clear"/>
<input type="button" id="Tabledata" value="Tabledata"/>
<div id="div1"></div>
#*#Html.ValidationSummary()*#
<script type="text/javascript">
function ValidateNumber(e) {
var evt = (e) ? e : window.event;
var charCode = (evt.keyCode) ? evt.keyCode : evt.which;
if (charCode > 31 && (charCode < 48 || charCode > 57)) {
return false;
}
return true;
};
function TextField(e) {
var evt = (e) ? e : window.event;
var charCode = (evt.keyCode) ? evt.keyCode : evt.which;
if (charCode > 31 && (charCode < 48 || charCode > 56)) {
return true;
}
else if (charCode == 8 || charCode == 9) {
return true;
}
return false
};
</script>
}
</body>
Error is shown in my view code, actually I don't know how to get that values in view page. I am newbie in mvc. Please help me to solve this. Any help will be greatly appreciated.
"Update"
I have solved My problem with the help of Stackoverflow Below is my correctcode
Controller
public ActionResult data()
{
SomeViewModel model = new SomeViewModel();
dbconnection db = new dbconnection();
SqlConnection con = new SqlConnection(db.GetconString());
DataTable dt = db.BuildDT("select * from MVCsample");
foreach (DataRow row in dt.Rows)
{
sample s = new sample();
s.FirstName = Convert.ToString(row["First Name"]);
s.LastName = Convert.ToString(row["Last Name"]);
s.Address = Convert.ToString(row["Address"]);
s.PhoneNumber = Convert.ToString(row["PhoneNumber"]);
s.Location = Convert.ToString(row["Location"]);
model.samples.Add(s);
}
return View(model);
}
Model
namespace examplemvc1.Models
{
public class sample
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Address { get; set; }
public string PhoneNumber { get; set; }
public string Location { get; set; }
public string tabledata { get; set; }
}
public class Message
{
public IEnumerable<sample> sampleList { get; set; }
public string MessageText { get; set; }
public string MessageFrom { get; set; }
}
public class SomeViewModel
{
public SomeViewModel()
{
samples = new List<sample>();
sample = new sample();
}
public List<sample> samples { get; set; }
public sample sample { get; set; }
}
}
view
#model examplemvc1.Models.SomeViewModel
//................
#foreach (var data in Model.samples)
{
<tr><td>#data.FirstName</td>
<td>#data.LastName</td>
<td>#data.Address</td>
<td>#data.PhoneNumber</td>
<td>#data.Location</td></tr>
}
</table>
Just look at Stephen Muecke's Answer below he has explained the context very clearly
You view is displaying both a list of sample and what appears t be a form for a new sample. Start by creating a view model to represent what you want to display/edit
public class SampleVM
{
public SampleVM
{
SampleCollection = new List<sample>
}
public List<sample> SampleCollection { get; set; }
public sample NewSample { get; set; }
}
In your controller modify the code to
public ActionResult data()
{
SampleVM model = new SampleVM();
dbconnection db = new dbconnection();
SqlConnection con = new SqlConnection(db.GetconString());
DataTable dt = db.BuildDT("select * from MVCsample");
foreach (DataRow row in dt.Rows)
{
sample s = new sample();
s.FirstName = Convert.ToString(row["First Name"]);
s.LastName = Convert.ToString(row["Last Name"]);
s.Address = Convert.ToString(row["Address"]);
s.PhoneNumber = Convert.ToString(row["PhoneNumber"]);
s.Location = Convert.ToString(row["Location"]);
model.SampleCollection.Add(s);
}
return View(model);
}
Notes:
Remove the parameters from the GET method. Apart from the fact you
don't use them so they are pointless, even if you were to try and
pass those objects to the method, binding would fail and the
collections would be null (and if you were to construct the correct
query string to make it work, it would be so long it would almost
certainly throw an exception)
You need to initialize a new sample inside the foreach loop
(your code only initialized one object, and each loop updated its
properties to the current row, so you would end up with multiple
reference of the same object, all matching the values of the last
row in your table)
There is no need to pass the model as a ViewBag property (its
already passed to the view using return View(model);
And modify your view to
#model SampleVM
....
<table>
#foreach(var sample in Model.SampleCollection)
<tr>
<td>#sample .FirstName</td>
</tr>
}
</table>
#Html.BeginForm())
{
#Html.LabelFor(m => m.NewSample.FirstName, "Enter FirstName", new { #class = "standard_label_style" })
#Html.TextBoxFor(m => m.NewSample.FirstName, #class = "class1", placeholder = "Enter name", title = "Enter Lastname")
#Html.ValidationMessageFor(m => m.NewSample.FirstName)
}
....
<input type="submit" id="btnSave" value="Register"/>
Notes:
A label element if for associating the element with a control. Your
usage generates <label for="Enter_FirstName"> but you dont have a
control with id="Enter_FirstName". Preferable you should have
[Display(Name = "Enter FirstName")] on the property, but otherwise
use the strongly types helper
Use #Html.ValidationMessageFor() to render ModelState errors,
although in your case all you properties are strings and you don't
have any validation attributes so there will never be any errors, so
its a bit pointless
The html helpers generate an id attribute. There is rarely a need
to overwrite it. Stop polluting your markup with behavior and learn
to use Unobtrusive Javascript
Your form did not contain a submit button
Problem is your model is of Type examplemvc1.Models.sample while you have to pass object of List<examplemvc1.Models.sample> to view:
return View(datatable) ;
Your action:
List <examplemvc1.Models.sample> datatable = new List<sample>();
dt = db.BuildDT("select * from MVCsample");
foreach (DataRow row in dt.Rows)
{
s.FirstName = Convert.ToString(row["First Name"]);
s.LastName = Convert.ToString(row["Last Name"]);
s.Address = Convert.ToString(row["Address"]);
s.PhoneNumber = Convert.ToString(row["PhoneNumber"]);
s.Location = Convert.ToString(row["Location"]);
datatable.Add(s);
}
return View(datatable); // passing list to view
and in View set model to List<examplemvc1.Models.sample>:
#model List<examplemvc1.Models.sample>
and now iterate the way you are doing:
<table>
<thead>
<tr><th>First Name</th></tr>
</thead>
<tbody>
#foreach (var data in Model)
{
<tr><td>#data.FirstName</td></tr>
}
</tbody>
</table>
Here problem is with your model directive.
It should be
#model IEnumerable<examplemvc1.Models.sample>
instead of
#model examplemvc1.Models.sample
Note: You are making assignment few times like dept = datatable; instead you can update the code like this.
public ActionResult data(Message msg,IEnumerable<sample> dept)
{
dbconnection db = new dbconnection();
sample s = new sample();
SqlConnection con = new SqlConnection(db.GetconString());
DataTable dt;
List <examplemvc1.Models.sample> datatable = new List<sample>();
dt = db.BuildDT("select * from MVCsample");
foreach (DataRow row in dt.Rows)
{
s.FirstName = Convert.ToString(row["First Name"]);
s.LastName = Convert.ToString(row["Last Name"]);
s.Address = Convert.ToString(row["Address"]);
s.PhoneNumber = Convert.ToString(row["PhoneNumber"]);
s.Location = Convert.ToString(row["Location"]);
datatable.Add(s);
//dept = datatable;
}
ViewBag.tabledata = datatable;
return View(datatable) ;
}
Update
In such a case you need to create viewmodel first and pass his instance there as model.
public class SomeViewModel
{
public SomeViewModel()
{
samples = new List<sample>();
sample = new sample();
}
public List<sample> samples {get; set;}
public sample sample {get; set;}
}
and in model declaration
#model namespace.SomeViewModel
and then in controller like following.
public ActionResult data(Message msg,IEnumerable<sample> dept)
{
dbconnection db = new dbconnection();
sample s = new sample();
SqlConnection con = new SqlConnection(db.GetconString());
DataTable dt;
List<examplemvc1.Models.sample> datatable = new List<sample>();
dt = db.BuildDT("select * from MVCsample");
foreach (DataRow row in dt.Rows)
{
s.FirstName = Convert.ToString(row["First Name"]);
s.LastName = Convert.ToString(row["Last Name"]);
s.Address = Convert.ToString(row["Address"]);
s.PhoneNumber = Convert.ToString(row["PhoneNumber"]);
s.Location = Convert.ToString(row["Location"]);
datatable.Add(s);
dept = datatable;
}
ViewBag.tabledata = dept;
SomeViewModel vm = new SomeViewModel();
vm.samples = datatable;
vm.sample = //somesample instance here you want to edit.
return View(vm) ;
}
and in view you will get the instance of vm iterate through vm.samples
#foreach (var data in Model.samples)
{
<tr><td>#data.FirstName</td></tr>
}
and in the rest of view do something like this:
#Html.TextBoxFor(a => a.sample.FirstName, new { #class = "class1", title =
"Enter FirstName", id = "NameBox", placeholder = "Enter name", onkeydown =
"return TextField(event)" })

Saving an IEnumerable Model

I have a view that has 2 date pickers, one of which is a start date and the other of which is end date. I am able to get the user to select the start and end dates, redirect to a view that will have a list of Time worked where the user could change the date, enter time, and once they are done they should be able to click the save button and it should create a new instance of each time worked to the database. I got the view displaying with no problem, but when the form posts my enumerable model is null, the form collection only has one accessible item, and I am not sure why. Please take a look at the view I am creating below to get an idea of what I am doing and let me know if you are able to help me in any way.
#model IEnumerable<TimeCollection.Models.TimeWorked>
#{
ViewBag.Title = "Create TimeWorked Range";
}
<h2>Create TimeWorked Range</h2>
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<table>
<tr>
<th>
#Html.DisplayNameFor(model => model.WorkDate)
</th>
<th>
#Html.DisplayNameFor(model => model.HoursWorked)
</th>
</tr>
#foreach (var item in Model) {
<tr>
#Html.HiddenFor(modelItem => item.EmployeeId)
<td>
#Html.EditorFor(modelItem => item.WorkDate)
</td>
<td>
#Html.EditorFor(modelItem => item.HoursWorked)
</td>
<td>
#Html.HiddenFor(modelItem => item.BeenSubmitted)
</td>
</tr>
}
</table>
<p>
<input type="submit" value="Save" />
</p>
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace TimeCollection.Models
{
public class TimeWorked
{
public int TimeWorkedId { get; set; }
public int EmployeeId { get; set; }
public DateTime WorkDate { get; set; }
public int HoursWorked { get; set; }
public bool BeenSubmitted { get; set; }
public static void CreateTimeWorked(TimeWorked timeWorkedToCreate)
{
string insertQuery = string.Format("insert into time_worked (employee_id, work_date, work_hours, been_submitted) values ('{0}', '{1}', '{2}', '{3}')", timeWorkedToCreate.EmployeeId, timeWorkedToCreate.WorkDate.ToString("yyyy/MM/dd"), timeWorkedToCreate.HoursWorked, (timeWorkedToCreate.BeenSubmitted == true ? "1" : "0"));
SpectrumData.Utility.ExecuteMySqlCommand(SpectrumData.Properties.Resources.SpectrumTSDatabaseConnectionString, insertQuery);
}
public static TimeWorked ReadTimeWorked(int timeWorkedId)
{
string selectQuery = string.Format("select * from time_worked where time_worked_id = '{0}'", timeWorkedId);
return ConvertDataRowIntoTimeWorked(SpectrumData.Utility.FillDataSet(SpectrumData.Properties.Resources.SpectrumTSDatabaseConnectionString, selectQuery).Tables[0].Rows[0]);
}
public static void UpdateTimeWorked(TimeWorked timeWorkedToUpdate)
{
string updateQuery = string.Format("update time_worked set work_date = '{0}', work_hours = '{1}', been_submitted = '{2}' where time_worked_id = '{2}'", timeWorkedToUpdate.WorkDate, timeWorkedToUpdate.HoursWorked, timeWorkedToUpdate.BeenSubmitted, timeWorkedToUpdate.TimeWorkedId);
SpectrumData.Utility.ExecuteMySqlCommand(SpectrumData.Properties.Resources.SpectrumTSDatabaseConnectionString, updateQuery);
}
public static void DeleteTimeWorked(int timeWorkedId)
{
string deleteQuery = string.Format("delete from time_worked where time_worked_id = '{0}'", timeWorkedId);
SpectrumData.Utility.ExecuteMySqlCommand(SpectrumData.Properties.Resources.SpectrumTSDatabaseConnectionString, deleteQuery);
}
private static TimeWorked ConvertDataRowIntoTimeWorked(System.Data.DataRow timeWorkedDataRow)
{
TimeWorked timeWorked = new TimeWorked();
timeWorked.BeenSubmitted = (timeWorkedDataRow["been_submitted"].ToString() == "1" ? true : false);
timeWorked.EmployeeId = int.Parse(timeWorkedDataRow["employee_id"].ToString());
timeWorked.HoursWorked = int.Parse(timeWorkedDataRow["work_hours"].ToString());
timeWorked.TimeWorkedId = int.Parse(timeWorkedDataRow["time_worked_id"].ToString());
timeWorked.WorkDate = DateTime.Parse(timeWorkedDataRow["work_date"].ToString());
return timeWorked;
}
}
}
public ActionResult CreateTimeWorkedRange(DateTime startDate, DateTime endDate)
{
List<Models.TimeWorked> listOfTimeWorked = new List<Models.TimeWorked>();
DateTime beginning = startDate;
DateTime ending = endDate;
while (beginning <= ending)
{
Models.TimeWorked dayWorked = new Models.TimeWorked()
{
EmployeeId = (Session["InventoryReviewUser"] as SpectrumData.SpectrumTS.InventoryReviewUser).EmployeeId,
WorkDate = beginning
};
if (listOfTimeWorked.Contains(dayWorked) == false)
{
listOfTimeWorked.Add(dayWorked);
}
beginning = beginning.AddDays(1);
}
return View(listOfTimeWorked);
}
[HttpPost]
public ActionResult CreateTimeWorkedRange(List<Models.TimeWorked> modelList)
{
foreach (Models.TimeWorked timeWorked in modelList)
{
Models.TimeWorked.CreateTimeWorked(timeWorked);
}
}
I don't know if there's a better way, but one way to do this is to bind your items using the index of the array as follows:
#for (int i = 0; i < Model.Count; ++i) {
<tr>
#Html.HiddenFor(modelItem => Model[i].EmployeeId)
<td>
#Html.TextBoxFor(modelItem => Model[i].WorkDate)
</td>
<td>
#Html.TextBoxFor(modelItem => Model[i].HoursWorked)
</td>
<td>
#Html.HiddenFor(modelItem => Model[i].BeenSubmitted)
</td>
</tr>
}
You'd need a different collection type for your model (IList<TimeWorked> should be fine) to be able to use indexers, but that shouldn't be a problem I'd imagine. When you post, the collection should fill properly.

How do I sort a list of entities using ViewModel instead of ViewBag?

I am using ViewBag to help me sort a list of students found within a list of classes. I have read that ViewBag is something that should be avoided at all costs attempting to build a proper MVC project.
When viewing the page that the below code generates, one is able to sort through a list of students in a variety of ways (First Name by alpha, Last name by alpha, date enrolled, etc), and view only a limited number of students per page.
I do not know exactly how to translate my code to use a ViewModel in place of my current design.
I am using the following code:
Model (Student):
public class Student
{
public int StudentID { get; set; }
public string LastName { get; set; }
public string FirstMidName { get; set; }
public string Email { get; set; }
public DateTime EnrollmentDate { get; set; }
public virtual ICollection<Enrollment> Enrollments { get; set; }
}
Model (Enrollment):
public class Enrollment
{
public int EnrollmentID { get; set; }
public int CourseID { get; set; }
public int StudentID { get; set; }
public string Grade { get; set; } // pass, fail, incomplete
public virtual Course Course { get; set; }
public virtual Student Student { get; set; }
}
(I also have a Course model, but it is not referenced directly by the controller below, so I will omit it here - if it is necessary to show its details, please let me know.)
Controller:
public class StudentController : Controller
{
private SchoolContext db = new SchoolContext();
//
// GET: /Student/
public ViewResult Index(string sortOrder, string currentFilter, string searchString, int? page)
{
ViewBag.CurrentSort = sortOrder;
ViewBag.NameSortParm = String.IsNullOrEmpty(sortOrder) ? "Name desc" : "";
ViewBag.DateSortParm = sortOrder == "Date" ? "Date desc" : "Date";
ViewBag.FNameSortParm = sortOrder == "FName" ? "FName desc" : "FName";
ViewBag.EmailSortParm = sortOrder == "Email" ? "Email desc" : "Email";
if (Request.HttpMethod == "GET")
{
searchString = currentFilter;
}
else
{
page = 1;
}
ViewBag.CurrentFilter = searchString;
var students = from s in db.Students
select s;
if (!String.IsNullOrEmpty(searchString))
{
students = students.Where(s => s.LastName.ToUpper().Contains(searchString.ToUpper())
|| s.FirstMidName.ToUpper().Contains(searchString.ToUpper()));
}
switch (sortOrder)
{
case "Name desc":
students = students.OrderByDescending(s => s.LastName);
break;
case "Date":
students = students.OrderBy(s => s.EnrollmentDate);
break;
case "Date desc":
students = students.OrderByDescending(s => s.EnrollmentDate);
break;
case "FName":
students = students.OrderBy(s => s.FirstMidName);
break;
case "FName desc":
students = students.OrderByDescending(s => s.FirstMidName);
break;
case "Email":
students = students.OrderBy(s => s.Email);
break;
case "Email desc":
students = students.OrderByDescending(s => s.Email);
break;
default:
students = students.OrderBy(s => s.LastName);
break;
}
int pageSize = 4;
int pageNumber = (page ?? 1);
return View(students.ToPagedList(pageNumber, pageSize));
}
And my view:
#model PagedList.IPagedList<MVCAppName.Models.Student>
#{
ViewBag.Title = "Students";
}
<h2>Students</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
#using (Html.BeginForm())
{
<p>
Find by name: #Html.TextBox("SearchString", ViewBag.CurrentFilter as string)
<input type="submit" value="Search" /></p>
}
<table>
<tr>
<th></th>
<th>
#Html.ActionLink("Last Name", "Index", new { sortOrder = ViewBag.NameSortParm, currentFilter = ViewBag.CurrentFilter })
</th>
<th>
#Html.ActionLink("First Name", "Index", new { sortOrder = ViewBag.FNameSortParm, currentFilter = ViewBag.CurrentFilter })
</th>
<th>
#Html.ActionLink("Email", "Index", new { sortOrder = ViewBag.EmailSortParm, currentFilter = ViewBag.CurrentFilter })
</th>
<th>
#Html.ActionLink("Enrollment Date", "Index", new { sortOrder = ViewBag.DateSortParm, currentFilter = ViewBag.CurrentFilter })
</th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.StudentID }) |
#Html.ActionLink("Details", "Details", new { id=item.StudentID }) |
#Html.ActionLink("Delete", "Delete", new { id=item.StudentID })
</td>
<td>
#Html.DisplayFor(modelItem => item.LastName)
</td>
<td>
#Html.DisplayFor(modelItem => item.FirstMidName)
</td>
<td>
#Html.DisplayFor(modelItem => item.Email)
</td>
<td>
#Html.DisplayFor(modelItem => item.EnrollmentDate)
</td>
</tr>
}
</table>
<div>
Page #(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber)
of #Model.PageCount
#if (Model.HasPreviousPage)
{
#Html.ActionLink("<<", "Index", new { page = 1, sortOrder = ViewBag.CurrentSort, currentFilter=ViewBag.CurrentFilter })
#Html.Raw(" ");
#Html.ActionLink("< Prev", "Index", new { page = Model.PageNumber - 1, sortOrder = ViewBag.CurrentSort, currentFilter=ViewBag.CurrentFilter })
}
else
{
#:<<
#Html.Raw(" ");
#:< Prev
}
#if (Model.HasNextPage)
{
#Html.ActionLink("Next >", "Index", new { page = Model.PageNumber + 1, sortOrder = ViewBag.CurrentSort, currentFilter=ViewBag.CurrentFilter })
#Html.Raw(" ");
#Html.ActionLink(">>", "Index", new { page = Model.PageCount, sortOrder = ViewBag.CurrentSort, currentFilter=ViewBag.CurrentFilter })
}
else
{
#:Next >
#Html.Raw(" ")
#:>>
}
</div>
The controller should handle the sorting, the view just displays the data. You already do that, so you need only to define the view model, which preivosuly you'd put in the ViewBag
public class ShowStudentsModel
{
public string CurrentSort {get;set;}
public string NameSortParm {get;set;}
//and so on... you create a property for each property set in the ViewBag
public IEnumerable<Student> Students {get;set;}
}
Then in the view
#model ShowStudentsModel
#foreach(var item in Model.Students)
{
//html code
}
I think the nicest would be to subclass the PagedList.IPagedList<T> which you are using and add sort order there. So at the end of your controller you'd have this:
return View(students.ToPagedList(pageNumber, pageSize, sortOrder));
But if you're not willing to do that, then you could simply create a new ViewModel class to hold the PagedList (your current model) as well as the supplemental data you need (i.e. your sort order).
return View(new SortedStudents
{
Students = students.ToPagedList(pageNumber, pageSize);
SortOrder = sortOrder
});
With the SortedStudents defined like this:
public class SortedStudents
{
public PagedList.IPagedList<MVCAppName.Models.Student> Students { get; set; }
public string SortOrder { get; set; }
}
You could make a wrapper around your Students class
public class StudentWrapper
{
List<Students> studentList { get; set; }
String currentSort { get; set; }
public StudentWrapper() {
studentlist = new List<Students>();
}
In your controller, you would create a new StudentWrapper
StudentWrapper sw = new StudentWrapper();
and set the list of students:
sw.studentList = db.Students.ToList();
and the sortOrder
sw.currentSort = SortOder;
You pass this model to your View
return View(sw);
in your View, you would use the StudentWrapper
#model List<MVCAppName.Models.StudentWrapper>
I dont know how your paging works, so you would have to figure this out.
But i dont see any problems in using the ViewBag either.

Resources