I have a table in a razor view that is displaying data like so
There are fields that I'd like to group like so
I dont think I'm going to achieve this by grouping because I'm going to loose data. Not sure what approach to take?
This is my markup
<div class="row">
<table class="arrowes-table table-striped">
<thead>
<tr>
<th>Driver Name</th>
<th>Alarm Type : Count</th>
<th>Total Distance For Period</th>
<th>Avg Per Km Driven</th>
<th>Relative Driver Score</th>
</tr>
</thead>
<tbody>
#foreach (var item in Model.DriverBehaviour.OrderByDescending(x => x.DriverName))
{
<tr>
<td>#Html.HiddenFor(m => item.DriverId) #Html.ActionLink(item.DriverName, "Operator", "Operators", new { area = "VehicleManagement", operatorId = item.DriverId })</td>
<td>#item.AlarmType : <span class="brand-red">#item.TypeCount</span></td>
<td>#item.TotalDistanceForPeriod</td>
<td>
#{
var avg = #Math.Truncate(1000 * item.AverageAlarmPerKmDriven) / 1000;
}
#avg
</td>
<td>
#{
var relScore = #Math.Truncate(1000 * #item.RelativeDriverScore) / 1000;
if (relScore.ToString().StartsWith("-") == true)
{
<span class="brand-red">#relScore</span>
}
if (relScore.ToString().StartsWith("-") == false)
{
<span class="brand-green">+#relScore</span>
}
}
</td>
</tr>
}
</tbody>
</table>
</div>
Thanks for any ideas :)
It's ok, I got it
<div class="row">
<table class="arrowes-table table-striped">
<thead>
<tr>
<th>Driver Name</th>
<th>Alarm Type : Count</th>
<th>Total Distance For Period</th>
<th>Avg Per Km Driven</th>
<th>Relative Driver Score</th>
</tr>
</thead>
<tbody>
#foreach (var group in Model.DriverBehaviour.GroupBy(item => item.DriverName))
{
<tr>
<td>#Html.ActionLink(#group.Key, "Operator", "Operators", new { area = "VehicleManagement", operatorId = group.FirstOrDefault().DriverId })</td>
<td>
<ul class="list-unstyled">
#foreach (var item in group)
{
<li> #item.AlarmType : <span class="brand-red">#item.TypeCount</span></li>
}
</ul>
</td>
<td>
<ul class="list-unstyled">
#foreach (var item in group.GroupBy(x => x.TotalDistanceForPeriod))
{
<li>#item.Key</li>
}
</ul>
</td>
<td>
<ul class="list-unstyled">
#foreach (var item in group)
{
var avg = #Math.Truncate(1000 * item.AverageAlarmPerKmDriven) / 1000;
<li>
#avg
</li>
}
</ul>
</td>
<td>
<ul class="list-unstyled">
#foreach (var item in group)
{
var relScore = #Math.Truncate(1000 * #item.RelativeDriverScore) / 1000;
if (relScore.ToString().StartsWith("-") == true)
{
<li class="brand-red">#relScore</li>
}
if (relScore.ToString().StartsWith("-") == false)
{
<li class="brand-green">+#relScore</li>
}
}
</ul>
</td>
</tr>
}
</tbody>
</table>
</div>
Produces this
Related
I am having this problem when i press a link to view data in pdf:
System.NullReferenceException: 'Object reference not set as an instance of an object.'
This problem arises when I try to display the SQL values in PDF.
As you can see in the image, there is a link to see the values in PDF, when you click there the error already mentioned will appear.
I share the code:
Controller:
public ActionResult Index(string buscarTitulo)
{
PDFPrinter db = new PDFPrinter();
ViewBag.CurrentFilter = buscarTitulo;
var datos = from s in db.SQLs
select s;
if (!String.IsNullOrEmpty(buscarTitulo))
{
datos = datos.Where(s => s.Titulo.ToString().Contains(buscarTitulo.ToUpper()));
}
return View(datos.ToList());
}
public ActionResult Pdf()
{
var reporte = new ActionAsPdf("Index");
return reporte;
}
public ActionResult Impresion(double? tit) {
using (PDFPrinter db = new PDFPrinter()) {
V_CuetaWeb v = db.SQLs.FirstOrDefault(c => c.Titulo == tit);
List<V_CuetaWeb> lista = new List<V_CuetaWeb>();
lista.Add(v);
var reporte = new PartialViewAsPdf("Pdf", v);
return reporte;
}
}
Index:
#model IEnumerable<ProvidusCuotas.V_CuetaWeb>
#{
ViewBag.Title = "Inicio";
}
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Inicio</title>
</head>
<body>
<form id="form">
<div>
#using (Html.BeginForm())
{
<p>
Título: #Html.TextBox("buscar", ViewBag.CurrentFilter as string)
<input type="submit" value="Filtrar" /><br />
<input type="button" value="Imprimir" onclick="window.print()" />
</p>
}
</div>
<div>
<table border="1">
#foreach (var item in Model)
{
<tr>
<th scope="row" abbr="Suscriptor">Suscriptor: </th>
<td>
<b>#Html.DisplayFor(modelItem => item.Apellido), #Html.DisplayFor(modelItem => item.Nombre)</b>
</td>
<td>Título: #Html.DisplayFor(modelItem => item.Titulo)</td>
</tr>
PDF:
#model IEnumerable<ProvidusCuotas.V_CuetaWeb>
#{
ViewBag.Title = "PDF";
}
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Inicio</title>
</head>
<body>
<form id="form">
<div>
<table border="1">
#foreach (var item in Model)
{
<tr>
<th scope="row" abbr="Domicilio">Domicilio: </th>
<td>
#Html.DisplayFor(modelItem => item.Domicilio)
</td>
<td></td>
<td></td>
<td></td>
<td>Valor Nominal: #Html.DisplayFor(modelItem => item.ValNom)</td>
</tr>
<tr>
<th scope="row" abbr="Barrio">Barrio: </th>
<td>
#Html.DisplayFor(modelItem => item.Barrio)
</td>
</tr>
<tr>
<th scope="row" abbr="Localidad">Localidad: </th>
<td>
#Html.DisplayFor(modelItem => item.Localidad)
</td>
</tr>
<tr>
<th scope="row" abbr="Telefono">Teléfono: </th>
<td>
#Html.DisplayFor(modelItem => item.Telefono)
</td>
</tr>
<tr>
<th scope="row" abbr="Celular">Celular: </th>
<td>
#Html.DisplayFor(modelItem => item.Celular)
</td>
</tr>
<tr>
<th scope="row" abbr="Descripcion">D. Plan Actual: </th>
<td>
#Html.DisplayFor(modelItem => item.DescPlanActual)
</td>
</tr>
<tr>
<th scope="row" abbr="Fecha">Fecha Sorteo: </th>
<td>
#Html.DisplayFor(modelItem => item.FechaSorteo)
</td>
</tr>
<tr>
<th>Zona: #Html.DisplayFor(modelItem => item.acidzona)</th>
<th>Cobrador: #Html.DisplayFor(modelItem => item.Cobrador)</th>
<th>Código: #Html.DisplayFor(modelItem => item.Codigo)</th>
<th>Título: #Html.DisplayFor(modelItem => item.Titulo)/#Html.DisplayFor(modelItem => item.Endoso)</th>
<th>Sorteo: #Html.DisplayFor(modelItem => item.Sorteo)</th>
<th>Cuota: #Html.DisplayFor(modelItem => item.Cuota)</th>
<th>Vencimiento: #Html.DisplayFor(modelItem => item.Vencimiento)</th>
<th>Monto: #Html.DisplayFor(modelItem => item.Monto)</th>
</tr>
}
</table>
</div>
</form>
</body>
</html>
PDFPrinter class:
public partial class PDFPrinter : DbContext
{
public PDFPrinter()
: base("name=VisorPDF")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
//public virtual DbSet<V_CuetaWeb> V_CuetaWeb { get; set; }
public virtual DbSet<V_CuetaWeb> SQLs { get; set; }
}
Any sugerence? how to solve this?
I don't understan the mistake
I think your flow needs to change, so index will pass list of pdf objects. and it iterate from view and display a table. This part correct.
Then you click from one link, then it should pass that click object to second view. Then it will display you object values.
So pdf view model should be
#model ProvidusCuotas.V_CuetaWeb
Then no need to have foreach loop. Just access the properties and display those.
and you c# method should be like this
public ActionResult Impresion(double? tit) {
using (PDFPrinter db = new PDFPrinter())
{
V_CuetaWeb v = db.SQLs.FirstOrDefault(c => c.Titulo == tit);
return View("Pdf", v);
}
}
Here is the Model:
public class TestModel
{
public string Data { get; set; }
public List<string> Datas { get; set; }
}
Here is the view:
#model InventoryWeb.Models.TestModel
#using (Html.BeginForm())
{
#Html.DisplayFor(modelItem => Model.Data)
#Html.HiddenFor(m => m.Data)
<table class="table">
<tr>
<th>
Data
</th>
<th></th>
</tr>
#for (int i = 0; i < Model.Datas.Count; i++)
{
#Html.Hidden("Datas["+ i + "]", Model.Datas[i])
<tr>
<td>
#Html.DisplayFor(modelItem => Model.Datas[i])
</td>
<td>
<input type="submit" value="Submit" formaction="SubmitTest" formmethod="post"/>
</td>
</tr>
}
</table>
}
How to pass the selected row number (the number of row on which user pressed the "Submit" button) to controller? TempData/Viewbag/whatever it is possible to use to pass this info to Controller site when Submitting.
The way you wrote it, it will send all the data back to server for any row.
You can insert a form in each row:
#model InventoryWeb.Models.TestModel
#Html.DisplayFor(modelItem => Model.Data)
<table class="table">
<tr>
<th>
Data
</th>
<th></th>
</tr>
#for (int i = 0; i < Model.Datas.Count; i++)
{
<tr>
<td>
#Html.DisplayFor(modelItem => Model.Datas[i])
</td>
<td>
#using (Html.BeginForm())
{
#Html.Hidden("rowNumber", i)
<input type="submit" value="Submit" formaction="SubmitTest" formmethod="post"/>
}
</td>
</tr>
}
</table>
But I prefer using javascript in this situations.
Edit
With JavaScript:
#using (Html.BeginForm("SubmitTest"))
{
#Html.DisplayFor(modelItem => Model.Data)
#Html.HiddenFor(m => m.Data)
<input type="hidden" id="rowNumber" name="rowNumber" />
<table class="table">
<tr>
<th>
Data
</th>
<th></th>
</tr>
#for (int i = 0; i < Model.Datas.Count; i++)
{
#Html.Hidden("Datas["+ i + "]", Model.Datas[i])
<tr>
<td>
#Html.DisplayFor(modelItem => Model.Datas[i])
</td>
<td>
<input type="button" value="Submit" onclick="SubmitForm(#i, this);"/>
</td>
</tr>
}
</table>
}
<script>
function SubmitForm(i, btn){
$("#rowNumber").val(i);
var form = $(btn).closest("form");
form.submit();
}
</script>
use <button> to replace the <input type="submit" ..>, and set the row number in the value of the <button>
#for (int i = 0; i < Model.Datas.Count; i++)
{
<tr>
<td>
#Html.DisplayFor(modelItem => Model.Datas[i])
</td>
<td>
<button name="rowNumber" value="#i">Submit</button>
</td>
</tr>
}
And if the target post Controller/Action is different the current one, instead of setting formaction and formmethod in every submit button, set it in the Html.BeginForm() like
#using(Html.BeginForm("ActionName", "ControllerName"))
{
...
}
I am using Asp.Net , EF6 ( MVC ) and have some data stored in my view. What I need is some indexing for each row. Here is the view.
For every row I have 0 Index. I wanna know, if there is some Built in feature in EF, that will help to add indexes for each row, (1,2,3....) and which will be automatically be updated, when new rows are created or deleted.
This is the Code for creating the table and doing Paging in my View.
<div class="bs-example">
<div class="table-responsive">
<div class="panel panel-default">
<table class="table table-striped table-hover table-bordered" cellspacing="0" data-toggle="table" data-click-to-select="true">
<tr>
<th style="vertical-align:middle;" class="text-center">
Index
</th>
<th style="vertical-align:middle;" class="text-center">
#Html.ActionLink("English", "Index", new { sortOrder = ViewBag.EnglishSortParm, currentFilter = ViewBag.CurrentFilter })
</th>
<th style="vertical-align:middle;" class="text-center">
#Html.ActionLink("Russian", "Index", new { sortOrder = ViewBag.RussianSortParm, currentFilter = ViewBag.CurrentFilter })
</th>
<th style="vertical-align:middle;" class="text-center">
#Html.ActionLink("Armenian", "Index", new { sortOrder = ViewBag.ArmenianSortParm, currentFilter = ViewBag.CurrentFilter })
</th>
<th style="vertical-align:middle;" class="text-center">
#Html.ActionLink("French", "Index", new { sortOrder = ViewBag.FrenchSortParm, currentFilter = ViewBag.CurrentFilter })
</th>
<th style="vertical-align:middle;" class="text-center">
#Html.ActionLink("Spanish", "Index", new { sortOrder = ViewBag.SpanishSortParm, currentFilter = ViewBag.CurrentFilter })
</th>
<th style="vertical-align:middle;" class="text-center">
#Html.ActionLink("Arabic", "Index", new { sortOrder = ViewBag.ArabicSortParm, currentFilter = ViewBag.CurrentFilter })
</th>
<th></th>
</tr>
#{
foreach (var item in Model.Item1)
{
<tr class="clickableRow">
<td style="vertical-align:middle; font-size:medium;font-style:italic;" class="text-center">
#ViewBag.IndexOfRow.ToInt32
</td>
<td style="vertical-align:middle;" class="text-center">
#Html.DisplayFor(modelItem => item.English)
</td>
<td style="vertical-align:middle;" class="text-center">
#Html.DisplayFor(modelItem => item.Russian)
</td>
<td style="vertical-align:middle;" class="text-center">
#Html.DisplayFor(modelItem => item.Armenian)
</td>
<td style="vertical-align:middle;" class="text-center">
#Html.DisplayFor(modelItem => item.French)
</td>
<td style="vertical-align:middle;" class="text-center">
#Html.DisplayFor(modelItem => item.Spanish)
</td>
<td style="vertical-align:middle;" class="text-center">
#Html.DisplayFor(modelItem => item.Arabic)
</td>
<td style="vertical-align:middle;" class="text-center">
<span style="color:white;">
#Html.ActionLink("Edit", "Edit", new { id = item.Text, #style = "color:red;" })
#*#Html.ActionLink("Details", "Details", new { id = item.Text })*#
#Html.ActionLink("Delete", "Delete", new { id = item.Text })
</span>
</td>
</tr>
}
}
</table>
</div>
<br />
Page #(Model.Item1.PageCount < Model.Item1.PageNumber ? 0 : Model.Item1.PageNumber) of #Model.Item1.PageCount
#Html.PagedListPager(Model.Item1, page => Url.Action("Index",
new { page, sortOrder = ViewBag.CurrentSort, currentFilter = ViewBag.CurrentFilter }))
</div>
</div>
And this is the code from my Controller
public ViewResult Index(int? page)
{
int pageSize = 15;
int pageNumber = (page ?? 1);
var allModels = new Tuple<IPagedList<Translation>, List<Translation>>
(translations.ToPagedList(pageNumber, pageSize), translations.ToList()) { };
return View(allModels);
}
I have removed the unnecessary code, only is left the code for paging.
I have not done anything so far, because I have not find any indexing question or article in Google or SO so far.
Thanks for help.
And if you want to put Index while creating table, you can loop like this in your table body:
<tbody>
#{
int counter = 1;// Index start value
foreach (var Item in Model.SomeList)
{
<tr>
<td> #counter </td>
</tr>
counter++;
}
}
</tbody>
Just set the start row index in the action method to ViewBag.
int pageSize = 15;
int pageNumber = (page ?? 1);
ViewBag.StartRowIndex = ((pageNumber - 1) * pageSize) + 1;
Then use it in the view.
#{
var rowIndex = (int)ViewBag.StartRowIndex;
}
foreach (var item in Model.Item1)
{
<tr class="clickableRow">
<td style="vertical-align:middle; font-size:medium;font-style:italic;" class="text-center">
#(rowIndex++) //#ViewBag.IndexOfRow.ToInt32
</td>
When you dont know what to do, create a new class :))
Im kidding, but the idea remains valid.
Why dont you craete a new class that will represent your "ViewModel" that will have the exact EF model inside and an extra Index property that you will use to bind to an index in the view?
What you will pass from your controller to the view will be the new ViewModel class.
Note:
If you want to go fancy, you could go somewhere on the line of : ObservableCollection http://msdn.microsoft.com/en-us/library/ms668604(v=vs.110).aspx which derrives from INotifyPropertyChanged
Basically it means that you have an event at your disposal that you can fire when the list has changed (add, delete) that will be used to update the index.
<div>
<table >
<tr>
<th>Customer ID</th>
<th>Name</th>
<th>Type</th>
</tr>
#foreach (var a in Model.Attachments)
{
<tr>
<td>
#a.CId
</td>
<td>
#a.CName
</td>
<td>
#a.CType
</td>
</tr>
}
</table>
#Html.PagedListPager((IPagedList)Model.Attachments, page => Url.Action("Index", new { page }))
</div>
Currently I am displaying 25 items per page. If the final page does not have 25 items, I want to append rows to the end of the table, to keep the Page selector at the same level from page to page.
This seems like it would work, I just don't know where to put it:
#for (int i = 25; i > Model.Attachments.Count() % 25; i--)
{
<tr>
<td></td>
</tr>
}
You have for sure a loop thrown the attachments list.
Put this loop right after the loop where you write your TRs.
Just take into account that if your data makes your TRs higher, this will break your solution. Other thing you may try is adding a HTML space in your dummy rows:
<div>
<table >
<tr>
<th>Customer ID</th>
<th>Name</th>
<th>Type</th>
</tr>
#foreach (var a in Model.Attachments)
{
<tr>
<td>
#a.CId
</td>
<td>
#a.CName
</td>
<td>
#a.CType
</td>
</tr>
}
#for (int i = 25; i > Model.Attachments.Count() % 25; i--)
{
<tr>
<td></td>
</tr>
}
</table>
#Html.PagedListPager((IPagedList)Model.Attachments, page => Url.Action("Index", new { page }))
</div>
<h2>Documenten</h2>
<table border="1"">
<tr>
<th">
title
</th>
<th>
description
</th>
<th>
Download
</th>
</tr>*
#foreach (var item in Model.Trajects.Components)
{
if (item.getType() == "document")
{
<tr>
<td>
#item.Title
</td>
<td>
#item.Description
</td>
<td><a href='#Url.Action("Download","Component", new {componentid=item.componentID,l=Request["trajectcode"],g = Model})'>
<img src='#Url.Content("../../Images/play.png")' alt="Home Page">
</a> </td>
</tr>
}
}
</table>
Now, whats the best way to sort this table on title, when I initialize the view?
I prefer to sort it in the controller, but you can do the following:
#foreach (var item in Model.Trajects.Components.OrderBy(c => c.Title))
{
if (item.getType() == "document")
{
<tr>
<td>#item.Title</td>
<td>#item.Description</td>
<td>
<a href='#Url.Action("Download","Component", new { componentid = item.componentID, l = Request["trajectcode"], g = Model })'>
<img src='#Url.Content("../../Images/play.png")' alt="Home Page">
</a>
</td>
</tr>
}
}
See OrderBy in the foreach statment.