How to Present a DataTable in an MVC3 Razor view - asp.net

I have a reliable and tested import method between an .xls spreadsheet[1] that returns a DataTable. I've located this in my service layer, not data as only the workbook gets persisted as an uploaded file, but now I'm wondering where and how to produce an HTML representation of this DataTable. I would prefer to avoid two loops in my view. I have a variable number of columns in the DataTable.
[1] Using an OleDb interface. I know it's archaic but it works.

DataTables are weakly typed. I hate weak typing.
Here's an alternative approach: using view models, strongly typed views and display templates. So start by defining a view model which will represent the information you are willing to display:
public class MyViewModel
{
public IEnumerable<ColumnViewModel> Columns { get; set; }
public IEnumerable<RowViewModel> Rows { get; set; }
}
public class ColumnViewModel
{
public string Name { get; set; }
}
public class RowViewModel
{
public IEnumerable<CellValueViewModel> Values { get; set; }
}
public class CellValueViewModel
{
public string Value { get; set; }
}
then you could have a controller action which will populate this view model. If you already have some service layers that spits DataTables, you could map those tables to the aforementioned view model. For the purpose of this demo let's hardcode:
public class HomeController : Controller
{
public ActionResult Index()
{
var model = new MyViewModel
{
Columns = new[]
{
new ColumnViewModel { Name = "column1" },
new ColumnViewModel { Name = "column2" },
new ColumnViewModel { Name = "column3" },
},
Rows = new[]
{
new RowViewModel
{
Values = new[]
{
new CellValueViewModel { Value = "1x1" },
new CellValueViewModel { Value = "1x2" },
new CellValueViewModel { Value = "1x3" },
}
},
new RowViewModel
{
Values = new[]
{
new CellValueViewModel { Value = "2x1" },
new CellValueViewModel { Value = "2x2" },
new CellValueViewModel { Value = "2x3" },
}
},
new RowViewModel
{
Values = new[]
{
new CellValueViewModel { Value = "3x1" },
new CellValueViewModel { Value = "3x2" },
new CellValueViewModel { Value = "3x3" },
}
}
}
};
return View(model);
}
}
and the last part is the view (~/Views/Home/Index.cshtml):
#model MyViewModel
<table>
<thead>
<tr>
#Html.DisplayFor(x => x.Columns)
</tr>
</thead>
<tbody>
#Html.DisplayFor(x => x.Rows)
</tbody>
</table>
and our display templates:
~/Views/Home/DisplayTemplates/ColumnViewModel.cshtml:
#model ColumnViewModel
<th>
#Html.DisplayFor(x => x.Name)
</th>
~/Views/Home/DisplayTemplates/RowViewModel.cshtml:
#model RowViewModel
<tr>
#Html.DisplayFor(x => x.Values)
</tr>
~/Views/Home/DisplayTemplates/CellValueViewModel.cshtml:
#model CellValueViewModel
<td>
#Html.DisplayFor(x => x.Value)
</td>
And that's pretty much all. As you can see we have written exactly zero loops in our views and we ended up with a nice <table> structure representing an Excel Worksheet.

Related

How to Bind a group by data in view in mvc5? what are the best ways to do

I am using Entityframework context, i dont know how to bind to view.
I am grouping items by gender
public SQLChallengeEntities Sqlcontext = new SQLChallengeEntities();
var bookGrouped = Sqlcontext.Empinfoes.ToList()
.GroupBy(x => x.EmpSex).ToList();
return View(bookGrouped.ToList());
In View How to get the data
#foreach (var s in Model)
{
#group.Sex
foreach (var book in s.Values)
{
#s.Empname
#s.EmpDesignation #s.EmpAge
}
}
I am getting this error:
The model item passed into the dictionary is of type 'System.Collections.Generic.List1[System.Linq.IGrouping2[System.String,Angular‌​CrudS.Empinfo]]', but this dictionary requires a model item of type 'System.Linq.IGrouping2[System.String,AngularCrudS.Empinfo]'
In order to have #group.Sex you need to have a model like
public class EmployeeSexGroupModel
{
public string Sex { get; set; }
public IEnumerable<AngularCrudS.Employee> Employees { get; set; }
}
Then your query would be
var bookGrouped = Sqlcontext.Empinfoes
.GroupBy(x => x.EmpSex).Select(x => new EmployeeSexGroupModel { Sex = x.Key, Employees = x});
return View(bookGrouped.ToList());
Your view would then look like
#model List<EmployeeSexGroupModel>
#foreach (var s in Model)
{
#s.Sex
foreach (var e in s.Employees)
{
#e.Empname
#e.EmpDesignation #e.EmpAge
}
}
public class GroupClass
{
public string Key { get; set; }
public List<Shahriar> shahriarList { get; set; }
}
var list = db.Shahriars.GroupBy(x => x.Name).Select(x => new GroupClass(){
Key = x.Key,
shahriarList = x.ToList()
}).ToList();
ViewBag.Data = list;
#foreach (var x in (List<GroupClass>)ViewBag.Data)
{
<tr><td colspan="4" style="background-color:lightblue;">#x.Key</td></tr>
foreach (var y in x.shahriarList)
{
<tr>
<td>#y.Id</td>
<td>#y.Name</td>
<td>#y.Roll</td>
<td>#y.Mobile</td>
</tr>
}
}

Is it possible to Pass set of table records from front end to back end using MVC3

i'm displaying a table in front end where table records are Editable and each record has a check box.
if some records are selected by making the corresponding checkboxes checked and submitted all the selected records have to be stored in a backend table.
Is it possible using Asp.net MVC3?
If yes how to pass that list of records from View to controller and Model?
As I understand you want to pass array of selected checkboxes to ActionResult during post.
See example below
Model:
public class EditableItemModel
{
public bool SelectedItem { get; set; }
public string Name { get; set; }
}
Controller:
public ActionResult Index()
{
var model = new EditableItemModel[]
{
new EditableItemModel { SelectedItem = true },
new EditableItemModel()
};
return View(model);
}
[HttpPost]
public ActionResult Index(EditableItemModel[] tableItems)
{
IEnumerable<EditableItemModel> selectedItems = tableItems.Where(i => i.SelectedItem);
return RedirectToAction("Index");
}
View:
#using CheckboxInTableExample.Models;
#model EditableItemModel[]
#using (Html.BeginForm("Index"))
{
<table>
#for (int i = 0; i < Model.Length; i++)
{
<tr>
<td>
#Html.CheckBoxFor(m => m[i].SelectedItem)
</td>
<td>
#Html.EditorFor(m => m[i].Name)
</td>
</tr>
}
</table>
<input type="submit" title="Submit" />
}
Hope this helps.

.net MVC passing linq data from controller to view

I am trying to pass data from controller to view. I have searched the web but could not find a solution.
if I do this it works:
Controller:
var yyy = (from a in Connection.Db.Authorities select a) ;
ViewBag.data = yyy;
View:
#foreach(var item in ViewBag.data)
{
#item.Value
}
But the following code does not work:
Controller:
var yyy = (from a in Connection.Db.Authorities select new {Value = a.Value, TypeCode = a.TypeCode, Return = Calculate(a.Return)}) ;
ViewBag.data = yyy;
View:
#foreach(var item in ViewBag.data)
{
#item.Value
}
It gives "item does not contain a definition for Value" for the view file.
Any help would be great.
Thank you.
-edited: updated the second controller linq query. and corrected the first controller linq query.
It's because You already select Value and Value has no such property as Value. You should change in controller:
var yyy = (from a in Connection.Db.Authorities select a.Value); to
var yyy = (from a in Connection.Db.Authorities select a);
OR change the view to
#foreach(var item in ViewBag.data)
{
#item
}
//////////////////////////////////////////////// EDITS ////////////////////////////////////////////////
Than You should not use anonymous object. You should create ViewModelClass. For Example:
public class AuthoritiesViewModel
{
public string Value { get; set; }
public string TypeCode { get; set; }
public string Return { get; set; }
}
And change your controller:
var yyy = (from a in Connection.Db.Authorities select new AuthoritiesViewModel{ Value = a.Value, TypeCode = a.TypeCode, Return = Calculate(a.Return)});
ViewBag.data = yyy;
and in your view you will be able to use:
<table>
<tr>
<th>Value</th>
<th>TypeCode</th>
<th>Return</th>
</tr>
#foreach(AuthoritiesViewModel item in ViewBag.data)
{
<tr>
<td>#item.Value<td>
<td>#item.TypeCode<td>
<td>#item.Return<td>
</tr>
}
</table>
Also, I have a question to You. Why do You use ViewBag to pass data from controller to view? Why don't You use Model to pass these data to view according to MVC pattern?
//////////////////////////////////////////////// MORE EDITS ////////////////////////////////////////////////
To send more than one query result You can create more complex model. For example:
public class AuthoritiesViewModel
{
public string Value { get; set; }
public string TypeCode { get; set; }
public string Return { get; set; }
}
public class AnotherQueryViewModel
{
public string AnotherQueryValue { get; set; }
public string AnotherQueryTypeCode { get; set; }
public string AnotherQueryReturn { get; set; }
}
public class ModelClass
{
IEnumerable<AuthoritiesViewModel> Authorities { get; set; }
IEnumerable<AnotherQueryViewModel> AnotherQueryResults { get; set; }
}
And change the controller:
var yyy = (from a in Connection.Db.Authorities select new AuthoritiesViewModel{ Value = a.Value, TypeCode = a.TypeCode, Return = Calculate(a.Return)});
// do your another select
var zzz = (from smthing select new AnotherQueryViewModel ...)
// create model instance
ModelClass model = new ModelClass()
{
Authorities = yyy.AsEnumerable(),
AnotherQueryResults = zzz..AsEnumerable()
}
// return view with model
return View("view", model);
and in view you can use:
#model ModelClass
#*display first query result*#
<table>
<tr>
<th>Value</th>
<th>TypeCode</th>
<th>Return</th>
</tr>
#foreach(AuthoritiesViewModel item in Model.Authorities)
{
<tr>
<td>#item.Value<td>
<td>#item.TypeCode<td>
<td>#item.Return<td>
</tr>
}
</table>
#*display second query result*#
<table>
<tr>
<th>Another Query Value</th>
<th>Another Query TypeCode</th>
<th>Another Query Return</th>
</tr>
#foreach(AnotherQueryViewModel item in Model.AnotherQueryResults)
{
<tr>
<td>#item.AnotherQueryValue<td>
<td>#item.AnotherQueryTypeCode<td>
<td>#item.AnotherQueryReturn<td>
</tr>
}
</table>
use sth like this
ViewBag.qualification = new SelectList(db.Lookups.Where(x => x.lookup_type == "Qualification"), "lookup_content", "lookup_content");

Issue with a single razor view accessing two models (ASP.NET MVC3)

View(Index.chtml) is returning 0 rows while accessing two models in the view. Please see the code below. I am new to ASP.NET and I am still learning. I tried to debug and I see the table data is not being passed to correctly. Please help
================================================================================
Controller: (OrganizationCodesController.cs)
================================================================================
namespace MvcProject.Controllers
{
public class OrganizationCodesController : Controller
{
//
// GET: /OrganizationCodes/
public ActionResult Index()
{
List<TABLE_CODES> temp_codes = new List<TABLE_CODES>();
List<TABLE_ORGANIZATIONS> temp_organizations = new List<TABLE_ORGANIZATIONS>();
var viewModel = new OrganizationCodesModel(temp_codes, temp_organizations);
return View(viewModel);
}
}
============================================================================
Model: (OrganizationCodesModel.cs)
============================================================================
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Collections;
namespace MvcProject.Models
{
public class OrganizationCodesModel
{
public List<TABLE_CODES> TABLE_CODES { get; set; }
public List<TABLE_ORGANIZATIONS> TABLE_CODES { get; set; }
public OrganizationCodesModel(List<TABLE_CODES> _codes, List<TABLE_ORGANIZATIONS> _organizations)
{
TABLE_CODES = _codes;
TABLE_ORGANIZATIONS = _organizations;
}
}
}
========================================================================
View: (Index.chtml)
========================================================================
#model MvcProject.Models.OrganizationCodesModel
<table>
<thead>
<tr>
<th>
ORGANIZATION_NAME
</th>
<th>
RANK
</th>
<th>
LEVEL
</th>
</thead>
<tbody>
#foreach (var item in Model.TABLE_CODES) {
<tr>
<td>
#foreach (var item_1 in Model.TABLE_ORGANIZATIONS)
{
if (item.LOCATION == item_1.ID)
{
#item1.NAME
break;
}
}
</td>
<td>
#item.RANK
</td>
<td>
#item.LEVEL
</td>
</tr>
}
</tbody>
</table>
List<TABLE_CODES> temp_codes = new List<TABLE_CODES>();
List<TABLE_ORGANIZATIONS> temp_organizations = new List<TABLE_ORGANIZATIONS>();
var viewModel = new OrganizationCodesModel(temp_codes, temp_organizations);
your instanciating two empty lists...
you should put something in your lists !
something like
List<TABLE_CODES> temp_codes = GetTempCodesFromSomewhere();
or
List<TABLE_CODES> temp_codes = new List<TABLE_CODES> {
new TABLE_CODES {LOCATION = 1, RANK = 1, LEVEL =1},
new TABLE_CODES{LOCATION = 2, RANK = 3, LEVEL = 12345}
};
Modiy your Model Class like this:
public class OrganizationCodesModel
{
public List<TABLE_CODES> listTABLE_CODES { get; set; }
public List<TABLE_ORGANIZATIONS> listTABLE_ORGANIZATIONS { get; set; }
}
I have also added text "list" as prefix to the name of the list to distinguish it from the class name otherwise both list name and class name are same.
Ok Now you have to also modify your Index action method like this:
public ActionResult Index()
{
OrganizationCodesModel model = new OrganizationCodesModel();
List<TABLE_CODES>listCodes = new List<TABLE_CODES> {
new TABLE_CODES {LOCATION = 1, RANK = 1, LEVEL =1},
new TABLE_CODES{LOCATION = 2, RANK = 3, LEVEL = 12345}
};
List<TABLE_ORGANIZATIONS> listOrganisation = new List<TABLE_ORGANIZATIONS> {
new TABLE_ORGANIZATIONS {ID = 1,NAME="ABC"},
new TABLE_ORGANIZATIONS{ID = 2,NAME="XYZ"}
};
model.ListTABLE_CODES = listCodes;
model.ListTABLE_ORGANIZATIONS = listOrganisation;
return View(model);
}
and in your View just replace your List name like this:
#foreach (var item in Model.listTABLE_CODES )
#foreach (var item_1 in Model.listTABLE_ORGANIZATIONS )
That is all. Now you will be able to see your output like this:

The model item is of type CookMeIndexViewModel, but requires a model item of type IEnumerable<CookMeIndexViewModel>

I am following along with the music store example to try learn ASP.NET MVC. I'm creating a cookbook application.
I have created my viewmodel that looks like this:
namespace CookMe_MVC.ViewModels
{
public class CookMeIndexViewModel
{
public int NumberOfReceipes { get; set; }
public List<string> ReceipeName { get; set; }
}
}
my controller looks like this
public ActionResult Index()
{
var meals= new List<string> { "Dinner 1", "Dinner 2", "3rd not sure" };
//create the view model
var viewModel = new CookMeIndexViewModel
{
NumberOfReceipes = meals.Count(),
ReceipeName = meals
};
return View(viewModel);
}
Finally my view looks like this
#model IEnumerable<CookMe_MVC.ViewModels.CookMeIndexViewModel>
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table>
<tr>
<th></th>
<th>
Meals
</th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.ActionLink("Edit", "Edit", new { /* id=item.PrimaryKey */ }) |
#Html.ActionLink("Details", "Details", new { /* id=item.PrimaryKey */ }) |
#Html.ActionLink("Delete", "Delete", new { /* id=item.PrimaryKey */ })
</td>
<td>
#item.ReceipeName
</td>
</tr>
}
</table>
I get this error.
The model item passed into the dictionary is of type CookMeIndexViewModel, but this dictionary requires a model item of type IEnumerable<CookMeIndexViewModel>.
I have followed the example. I can't see what I am doing wrong. Should I be returning my viewmodel as a generic list?
In your view you are using #model IEnumerable<CookMe_MVC.ViewModels.CookMeIndexViewModel> which indicates that the model expected by the View is of type IEnumerable of CookMeIndexViewModel.
However in the controller you are passing an object of type CookMeIndexViewModel as a model return View(viewModel); hence the error.
Either change the view to have #model CookMe_MVC.ViewModels.CookMeIndexViewModel
or pass a IEnumerable of CookMeIndexViewModel as model to the view in controller as given below:
public ActionResult Index()
{
var meals= new List<string> { "Dinner 1", "Dinner 2", "3rd not sure" };
//create the view model
var viewModel = new CookMeIndexViewModel
{
NumberOfReceipes = meals.Count(),
ReceipeName = meals
};
List<CookMeIndexViewModel> viewModelList = new List<CookMeIndexViewModel>();
viewModelList.Add(viewModel);
return View(viewModelList);
}
I got this message when I had a conflict between what the #model directive in the _Layout.cshtml layout view and an "inner page" view.
The _Layout.cshtml had directive..
#model MyProject.Models.MyObject
My inner page had...
#model IEnumerable<MyProject.Models.MyObject>
I was working on some test / experiment code and hit this issue when I created new controller etc. It was only when I renamed Model Object and compiled afterwards that I found the source of the problem.
Hope this helps.
Q.
in kendo ui Grid do :
public class BookBean
{
[ScaffoldColumn(false)]
public Int32 Id { set; get; }
public String Title { set; get; }
public String Author { set; get; }
public String Publisher { set; get; }
[UIHint("Integer")]
public Int32 Price { set; get; }
[UIHint("Integer")]
public Int32 Instore { set; get; }
[UIHint("Integer")]
public Int32 GroupId { get; set; }
}
in Integer.ascx in Shared/EditorTemplate folder do :
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<int?>" %>
<%: Html.Kendo().IntegerTextBoxFor(m => m)
.HtmlAttributes(new { style = "width:100%" })
.Min(int.MinValue)
.Max(int.MaxValue)
%>

Resources