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

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:

Related

How to redirect to a different url using tr onlick

I have this Razor page Userview which includes a list of students in a table
I want on clicking a row to open a URL passing the ID of selected student row. Here's what I got so far
#foreach (var student in Model._User.Students)
{
<tr onclick="location.href = '#(Url.Action("Info", new { id = student.Id }))'">
<td>Some basic info of student</td>
</tr>
}
I expect to get redirected to /Info/{id} but instead got /Useview/{id}?action=Info
You can use Url.Page :
<tr onclick="location.href = '#(Url.Page("Info", new { id = 1 }))'">
Then if you have another page named Info , you can get the parameter :
#page "{id}"
#model RAZOR.Pages.InfoModel
#{
ViewData["Title"] = "Info";
}
<p>The Id is #Model.Id</p>
Info.cshtml.cs:
public class InfoModel : PageModel
{
public int Id { get; set; }
public void OnGet(int id)
{
Id = id;
}
}

.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");

Pass a model to an MVCMailer view

I have a controller, which passes a model (ovw.ToList()) to a view:
//
// GET: /Clinic/Overview/
public ActionResult Overview()
{
IEnumerable<Clinic> ovw = from c in db.Clinics
select c;
return View(ovw.ToList());
}
View:
#model IEnumerable<ttp.Models.Clinic>
#foreach (var item in Model)
{
<div>#item.ClinicName</div>
#foreach (var item2 in item.Properties)
{
<div>#item2.Address</div>
This works absolutely fine on screen.
When using MVCMailer, however , if I want to display the same layout in the email, how do I pass the ovw.ToList() to the mailer view, so that I can reference the same model in this way:
(I'm stuck on what to put in as the first line in the view):
#model IEnumerable<ttp.Models.Clinic>
#foreach (var item in Model)
Thanks for any help,
Mark
You should find your answer in the 'Pass Data to Mailer Views' part of this guide: https://github.com/smsohan/MvcMailer/wiki/MvcMailer-Step-by-Step-Guide
To pass your model along with the view to MVCMailer, you need to use ViewData:
var comment = new Comment {From = me, To = you, Message = "Great Work!"};
ViewData = new ViewDataDictionary(comment);
In my project i doing like this it's below
i am showing all my category list in my index view
in my model class
public List<CategoryDetails> CategoryData { get; set; }
and i am also create CategoryDetails class and create a property to all my field
like this
public int CatID { get; set; }
[Required(ErrorMessage = "Enter Category Name")]
public string CatName { get; set; }
public string CatImage { get; set; }
and create a function in my main model class like this
public void LoadCategory()
{
CategoryData = (from con in dbData.Categorys
select new CategoryDetails()
{
CatID = con.CatID,
CatName = con.CatName,
CatImage = con.CatImage,
}).ToList();
}
In my controller i create a action like this
create my model class object and pass my model function to action
public ActionResult Index()
{
CategoryModel categorymodel = new CategoryModel();
categorymodel.LoadCategory();
return View(categorymodel);
}
and in my view
#model PMS.Models.CategoryModel
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>
Index</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table>
<tr>
<th>
Category Name
</th>
<th>
</th>
</tr>
#foreach (var item in Model.CategoryData)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.CatName)
</td>
</tr>
}
</table>
i think this will help you

Paged list isn't working

I did the Getting Started with ASP.NET MVC 3 (C#) tutorial by Rick Anderson, is a catalog of products, is already working, but, since i added a long list of products, now i need a pagedList to get just a number of products per page, looking around i found an example but isn't working, to my project i added on the Models file this class named IPagedList.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Presupuestos.Models
{
public interface IPagedList
{
int ItemCount
{
get;
set;
}
int PageCount
{
get;
set;
}
int PageIndex
{
get;
set;
}
int PageSize
{
get;
set;
}
bool IsPreviousPage
{
get;
}
bool IsNextPage
{
get;
}
}
public interface IPagedList<T> : IList<T>, IPagedList
{
}
public class PagedList<T> : List<T>, IPagedList<T>
{
private List<Productos> list;
private int p;
private int p_2;
public PagedList(IQueryable<T> source, int index, int pageSize)
{
this.ItemCount = source.Count();
this.PageSize = pageSize;
this.PageIndex = index;
this.AddRange(source.Skip(index * pageSize).Take(pageSize).ToList());
this.PageCount = (int)Math.Ceiling((double)this.ItemCount / this.PageSize);
}
public PagedList(List<T> source, int index, int pageSize)
{
this.ItemCount = source.Count();
this.PageSize = pageSize;
this.PageIndex = index;
this.AddRange(source.Skip(index * pageSize).Take(pageSize).ToList());
}
public PagedList(List<Productos> list, int p, int p_2)
{
// TODO: Complete member initialization
this.list = list;
this.p = p;
this.p_2 = p_2;
}
public int ItemCount
{
get;
set;
}
public int PageCount
{
get;
set;
}
public int PageIndex
{
get;
set;
}
public int PageSize
{
get;
set;
}
public bool IsPreviousPage
{
get
{
return (PageIndex > 0);
}
}
public bool IsNextPage
{
get
{
return (PageIndex + 1) * PageSize <= ItemCount;
}
}
}
public static class Pagination
{
public static PagedList<T> ToPagedList<T>(this IQueryable<T> source, int index, int pageSize)
{
return new PagedList<T>(source, index, pageSize);
}
public static PagedList<T> ToPagedList<T>(this IQueryable<T> source, int index)
{
return new PagedList<T>(source, index, 10);
}
}
}
Also, i added another class named HTMLHelpers.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Text;
using Presupuestos.Models;
namespace Presupuestos.Models
{
public static class ListPaging
{
public static MvcHtmlString Paging(this HtmlHelper html, IPagedList pagedList, string url, string pagePlaceHolder)
{
StringBuilder sb = new StringBuilder();
// only show paging if we have more items than the page size
if (pagedList.ItemCount > pagedList.PageSize)
{
sb.Append("<ul class=\"paging\">");
if (pagedList.IsPreviousPage && pagedList.PageIndex != 1)
{
// previous link
sb.Append("<li class=\"prev\"><a href=\"");
sb.Append(url.Replace(pagePlaceHolder, (pagedList.PageIndex - 1).ToString()));
sb.Append("\" title=\"Go to Previous Page\">prev</a></li>");
}
for (int i = 0; i < pagedList.PageCount; i++)
{
sb.Append("<li>");
if (i == pagedList.PageIndex)
{
sb.Append("<span>").Append((i + 1).ToString()).Append("</span>");
}
else
{
sb.Append("<a href=\"");
sb.Append(url.Replace(pagePlaceHolder, (i + 1).ToString()));
sb.Append("\" title=\"Go to Page ").Append((i + 1).ToString());
sb.Append("\">").Append((i + 1).ToString()).Append("</a>");
}
sb.Append("</li>");
}
if (pagedList.IsNextPage)
{
// next link
sb.Append("<li class=\"next\"><a href=\"");
sb.Append(url.Replace(pagePlaceHolder, (pagedList.PageIndex + 1).ToString()));
sb.Append("\" title=\"Go to Next Page\">next</a></li>");
}
sb.Append("</ul>");
}
return MvcHtmlString.Create(sb.ToString());
}
}
}
Finally this is the view file, i just added the #using presupuestos.models and the last html.paging at the end:
#model IEnumerable<Presupuestos.Models.Productos>
#using Presupuestos.Models
#{
ViewBag.Title = "Productos";
}
<h2>Catalogo de Productos</h2>
<p>
#Html.ActionLink("Agregar Producto", "Create")
</p>
<table>
<tr>
<th>
Marca
</th>
<th>
Codigo
</th>
<th>
Nombre
</th>
<th>
Envase
</th>
<th>
PresentaciĆ³n
</th>
<th>
Linea
</th>
<th>
Categoria
</th>
<th></th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.marca)
</td>
<td>
#Html.DisplayFor(modelItem => item.codigo)
</td>
<td>
#Html.DisplayFor(modelItem => item.nombre)
</td>
<td>
#Html.DisplayFor(modelItem => item.envase)
</td>
<td>
#Html.DisplayFor(modelItem => item.presentaciĆ³n)
</td>
<td>
#Html.DisplayFor(modelItem => item.linea)
</td>
<td>
#Html.DisplayFor(modelItem => item.categoria)
</td>
<td>
#Html.ActionLink("Editar", "Edit", new { id = item.ID }) |
#Html.ActionLink("Detalles", "Details", new { id = item.ID }) |
#Html.ActionLink("Borrar", "Delete", new { id = item.ID })
</td>
</tr>
}
</table>
<div>
#Html.Paging(new PagedList<Productos>(ViewData.Model.ToList(),1,10), Url.Action("Index","Index", new { page = "PAGENUM" }), "PAGENUM")
</div>
Hope you can help me, i have been stuck with this for one day, just last friday i started using mvc3, the good thing was what my boss needs is what is on the tutorial, but, now that i wanted to do this extra thing (pagedlist) i'm really lost!!
It looks as if in this line
#Html.Paging(new PagedList<Productos>(ViewData.Model.ToList(),1,10), Url.Action("Index","Index", new { page = "PAGENUM" }), "PAGENUM")
you are hardcoding the current page index to be 1.
I'd guess that in your Index action method you need might want to have something representing your current page that you can pass through to your view, and replace the hardcoded 1 with that.
e.g.
public void Index(int page = 1)
{
// ... set up your view model
// ...
// ...
// page is added to the url by your paging helper.
ViewBag.CurrentPage = page;
return View(viewModel);
}
And in the view...
#Html.Paging(new PagedList<Productos>(ViewData.Model.ToList(),#ViewBag.CurrentPage,10), Url.Action("Index","Index", new { page = "PAGENUM" }), "PAGENUM")
Based on what you said in your comment, that the paged list doesn't appear at the bottom of the page, I'd really recommend doing some debugging and seeing which code paths are actually executing. But anyway we can maybe guess the following...
First step is to put a breakpoint in the ListPaging.Paging and check it's actually getting called. If it is, and nothing at all is getting appended to your StringBuilder, then perhaps
if (pagedList.ItemCount > pagedList.PageSize)
{
// ...
is not evaluating to true. I'm assuming there's more items in your list than 10, so it should be true. So maybe the reason this isn't evaluating to true is because neither value is being set.
The constructor that you added looks dubious:
public PagedList(List<Productos> list, int p, int p_2)
{
// TODO: Complete member initialization
this.list = list;
this.p = p;
this.p_2 = p_2;
}
None of the properties that PagedList uses actually get set in here. what's the point of this constructor? What are p and p_2? If this constructor is being called, then ItemCount and PageSize will have no value. I'd suggest getting rid of it and letting the other constructors be called.

How to Present a DataTable in an MVC3 Razor view

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.

Resources