How can you build a ul LI tree based on an existing model? On the client side of the application.Nesting can be unlimited
#foreach (var item in Model)
{
<tr>
<th scope="col">#Html.DisplayFor(modelItem => item.Id) </th>
#if (item.ParentId != null)
{
<th scope="col">#Html.DisplayFor(modelItem => item.ParentTitle) </th>
}
else
{
<th scope="col">null </th>
}
<th scope="col">#Html.DisplayFor(modelItem => item.Title) </th>
<th scope="col">#Html.DisplayFor(modelItem => item.Description) </th>
<th scope="col">#Html.DisplayFor(modelItem => item.Created) </th>
</tr>
}
I saw a manual build, just tagging and getting model elements, but is it possible to automate the process somehow?
<ul>
<li>First parent
<ul>
<li>First child
<ul>
Model:
[Table("TestTable", Schema = "dbo")]
public class MyClass
{
public int Id { get; set; }
public int? ParentId { get; set; }
public string Title { get; set; }
public DateTime Created { get; set; }
public string Description { get; set; }
}
public class MySecondClass
{
public int Id { get; set; }
public int? ParentId { get; set; }
public string Title { get; set; }
public DateTime Created { get; set; }
public string Description { get; set; }
public string ParentTitle { get; set; }
}
I would have had a list of children property on your parent rather than 2 very similar classes, then you would be able to make a hierarchical structure:
public class MyClass
{
public int Id { get; set; }
public int? ParentId { get; set; }
public string Title { get; set; }
public DateTime Created { get; set; }
public string Description { get; set; }
public IEnuerable<MyClass> Children { get; set; }
}
Then instead of passing a flat set of classes through as your model, you can build up your hierarchy (in the below, I assumed Model is a list of all your items):
var topLevel = Model.Where(item => !item.HasValue); // or whatever the value is when there is no parent
Then you can loop through this top level to set your children:
foreach (var item in topLevel)
{
item.Children = GetChildren(item.Id, Model);
}
And your Get Children method can be
public static IEnumerable<MyClass> GetChildren(int parentId, IEnumerable<MyClass> allItems)
{
if (parentId.HasValue)
{
var children = allItems.Where(item => item.ParentId.HasValue && item.ParentId.Value.Equals(parentId));
if (children != null && children.Any())
{
foreach (var item in children)
{
item.Children = GetChildren(item.Id, allItems);
}
return children;
}
}
return null;
}
This should help build something then you can have a partial that takes a model of IEnumerable<MyClass> and make it recursive:
#model IEnumerable<MyClass>
#foreach (MyClass item in Model)
{
<ul>
<li>
#item.Title
#if (item.Children != null && item.Children.Any())
{
#Html.Partial("NameOfThisPartial", item.Children)
}
</li>
</ul>
}
And your initial partial call will be:
#Html.Partial("NameOfThisPartial", topLevel)
Related
I have three relational models that I want to display in a view in one table. following, I will list 3 models then the controller and the view.
and an error that come out from the controller.
Model Documents
public class Documents
{
[Key]
public int DocId { get; set; }
public string DocName { get; set; }
[ForeignKey("Employee")]
public int EmpId_From { get; set; }
[ForeignKey("Employee")]
public int EmpId_To { get; set; }
[ForeignKey("Organization")]
public int OrganId_From { get; set; }
[ForeignKey("Organization")]
public int OrganId_To { get; set; }
public Employee _Employee { get; set; }
public Organization _Organization { get; set; }
}
Employee
public class Employee
{
[Key]
public int Emp_ID { get; set; }
public string EmpName { get; set; }
}
Organization
public class Organization
{
[Key]
public int OrgID { get; set; }
public string OrgName { get; set; }
}
The Controller
public IActionResult Index()
{
List<Documents> x = _context.Documents.Include(e => e.Employee).Include(o => o.Organization).ToList();
return View(x);
}
The View
#model IEnumerable<Documents>
#foreach (var item in Model.DocumentsList)
{
<tr>
<td>
#item.DocId
</td>
<td>
#item.DocName
</td>
<td> // I can see item.Employee.EmpName but how to display it for this FK EmpId_From & EmpId_To
#item.EmpId_From // item.Employee.EmpName for EmpId_From
</td>
<td>
#item.EmpId_To // item.Employee.EmpName for EmpId_To
</td>
<td>
#item.OrganId_From // item.Organization.OrgName for OrganId_From
</td>
<td>
#item.OrganId_To // item.Organization.OrgName for OrganId_To
</td>
</tr>
}
I get this error from the controller
Microsoft.Data.SqlClient.SqlException: 'Invalid column name '_EmployeeEmp_ID'.
Invalid column name 'OrganizationOrgID'.
Invalid column name 'EmployeeEmp_ID'.
Invalid column name 'OrganizationOrgID'.'
As far as I know, if want to add relationship between the Documents and Employee, Organization, you could directly add the employee and Organization as the property inside the Documents. Then you could directly get the related employee and Organization's value.
Your model class will like this:
public class Documents
{
[Key]
public int DocId { get; set; }
public string DocName { get; set; }
public Employee Emp_From { get; set; }
public Employee Emp_To { get; set; }
public Organization Organ_From { get; set; }
public Organization Organ_To { get; set; }
}
public class Employee
{
[Key]
public int Emp_ID { get; set; }
public string EmpName { get; set; }
}
public class Organization
{
[Key]
public int OrgID { get; set; }
public string OrgName { get; set; }
}
Home controller:
public IActionResult Index()
{
List<Documents> x = _dbContext.Documents.Include(e => e.Emp_From).Include(o => o.Emp_To).Include(o => o.Organ_From).Include(o => o.Organ_To).ToList();
return View(x);
}
View:
<table>
#foreach (var item in Model)
{
<tr>
<td>
#item.DocId
</td>
<td>
#item.DocName
</td>
<td>
#item.Emp_From.EmpName
</td>
<td>
#item.Emp_To.EmpName
</td>
<td>
#item.Organ_From.OrgName
</td>
<td>
#item.Organ_To.OrgName
</td>
</tr>
}
</table>
Result:
On an ASP Core project I have a model for Customers:
using System;
using System.Collections.Generic;
namespace RiskDotNet.Models
{
public partial class Customers
{
public Customers()
{
Accounts = new HashSet<Accounts>();
}
public string SrcSys { get; set; }
public string CustId { get; set; }
public string CustNm { get; set; }
public virtual ICollection<Accounts> Accounts { get; set; }
}
}
Thereafter, the accounts pertaining to each customer as:
using System;
using System.Collections.Generic;
namespace RiskDotNet.Models
{
public partial class Accounts
{
public Accounts()
{
Balances = new HashSet<Balances>();
}
public string SrcSys { get; set; }
public string CustId { get; set; }
public string AccId { get; set; }
public string ProdId { get; set; }
public virtual ICollection<Balances> Balances { get; set; }
public virtual Customers Customers { get; set; }
}
}
And third model for the balances (transactions) pertaining to each account:
using System;
using System.ComponentModel.DataAnnotations;
namespace RiskDotNet.Models
{
public partial class Balances
{
[DisplayFormat(DataFormatString = "{0:dd-MMM-yyyy}")]
public DateTime RepDt { get; set; }
public string CustId { get; set; }
public string AccId { get; set; }
public string SrcSys { get; set; }
public decimal? PrOs { get; set; }
public virtual Accounts X { get; set; }
}
}
Now, while I want the Balances table, in the details view of the Accounts page, to be reflected in a sorted manner like a Descending Order of the Reporting Date (RepDt), I am unable to do so.
What is wrong with the following details section of the Accounts Controller:
public async Task<IActionResult> Details(string _SrcSys, string _CustId, string _AccId) //All three join up to form the Composite Key
{
if (_SrcSys == null || _CustId == null || _AccId == null)
{
return NotFound();
}
var Accs = await _context.Accounts
.Include(Cust => Cust.Customers) //To reflect the Customer's Name
.Include(Bal => Bal.Balances) //The Main Portion I want sorted
.SingleOrDefaultAsync(m => m.SrcSys == _SrcSys && m.CustId == _CustId && m.AccId == _AccId);
return View(Accs.Balances.OrderByDescending(x => x.RepDt));
}
Error returns stack:
InvalidOperationException: The model item passed into the ViewDataDictionary is of type 'System.Linq.OrderedEnumerable`2[RiskDotNet.Models.Balances,System.DateTime]', but this ViewDataDictionary instance requires a model item of type 'RiskDotNet.Models.Accounts'.
Follows the View Model:
#model RiskDotNet.Models.Accounts
#{ViewData["Title"] = "Details";}
<div>
<dt><strong>Account:</strong></dt>
<dd>#Html.DisplayFor(model => model.AccId)</dd>
<dt><strong>Src. System:</strong></dt>
<dd>#Html.DisplayFor(model => model.SrcSys)</dd>
<dt><strong>Product:</strong></dt>
<dd>#Html.DisplayFor(model => model.ProdId)</dd>
</dl>
</div>
<div>
<dl>
<dd>
<table class="table">
<tr>
<th>Date</th>
<th style="text-align:right">Pr. O/s.</th>
</tr>
#foreach (var item in Model.Balances)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.RepDt)
</td>
<td style="text-align:right">
#Html.DisplayFor(modelItem => item.PrOs)
</td>
</tr>
}
</table>
</dd>
</dl>
</div>
<a asp-action="Index">Accounts' List</a>
pretty new to mvc 5.
I have a model that contains a field and a list.
I wish to display both in my view.
this is my model:
public class AdminChargeHistory
{
public List<StripeChargeHistory> Charges = new List<StripeChargeHistory>();
public string ErrorMessage { get; set;] }
}
public class StripeChargeHistory
{
public int TransactionId { get; set; }
public string Amount { get; set; }
public string AmountRefunded { get; set; }
public string CustomerId { get; set; }
public Nullable<bool> Paid { get; set; }
public string Status { get; set; }
public string ChargeId { get; set; }
public string InvoiceId { get; set; }
public string BalanceTransId { get; set; }
public Nullable<bool> Live { get; set; }
public Nullable<int> Month { get; set; }
public Nullable<int> Year { get; set; }
}
my controller:
public ActionResult MissedPayments()
{
var adminChargeHistory = new AdminChargeHistory();
try
{
var stripeRepository = new StripeRepository();
var results = stripeRepository.GetMissedPayments(-1, -1, false);
foreach (var result in results)
{
var stripeChargeHistory = new StripeChargeHistory();
stripeChargeHistory.Amount = result.Amount;
stripeChargeHistory.AmountRefunded = result.AmountRefunded;
stripeChargeHistory.BalanceTransId = result.BalanceTransId;
stripeChargeHistory.ChargeId = result.ChargeId;
stripeChargeHistory.CustomerId = result.CustomerId;
stripeChargeHistory.InvoiceId = result.InvoiceId;
stripeChargeHistory.Live = result.Live;
stripeChargeHistory.Month = result.Month;
stripeChargeHistory.Paid = result.Paid;
stripeChargeHistory.Status = result.Status;
stripeChargeHistory.TransactionId = result.TransactionId;
stripeChargeHistory.Year = result.Year;
adminChargeHistory.Charges.Add(stripeChargeHistory);
}
}
catch (Exception ex)
{
adminChargeHistory.ErrorMessage = ex.Message;
}
return View(adminChargeHistory);
}
my view:
#model InformedProducts.Models.AdminChargeHistory
#{
ViewBag.Title = "Missed Payments";
}
<h2>Missed Payments</h2>
<table class="grid">
<tr>
<th>Customer Id</th>
<th>Amount</th>
<th>Month</th>
<th>Year</th>
</tr>
#foreach (var item in Model.StripeChargeHistory)
{
<tr>
<td class="left"><#item.CustomerId></td>
<td class="left"><#item.Amount></td>
<td class="left"><#item.Month></td>
<td class="left"><#item.Year></td>
</tr>
#}
#Html.LabelFor(m=>m.ErrorMessage)
</table>
but errors here:
InformedProducts.Models.AdminChargeHistory
and here?
#Html.LabelFor(m=>m.ErrorMessage)
I cannot see what I am doing wrong?
Model - Add getter/setter for Charges and empty constructor.
public class AdminChargeHistory
{
public AdminChargeHistory()
{
Charges = new List<StripeChargeHistory>();
}
public ICollection<StripeChargeHistory> Charges { get; set; }
public string ErrorMessage { get; set; }
}
Controller - take advantage of LINQ
public ActionResult MissedPayments()
{
var adminChargeHistory = new AdminChargeHistory();
try
{
var stripeRepository = new StripeRepository();
var results = stripeRepository.GetMissedPayments(-1, -1, false);
adminChargeHistory.Charges = results.Select(result => new StripeChargeHistory
{
Amount = result.Amount,
CustomerId = result.CustomerId,
Month = result.Month,
Year = result.Year
}).ToList();
}
catch (Exception ex)
{
adminChargeHistory.ErrorMessage = ex.Message;
}
return View(adminChargeHistory);
}
View - Reference the Charges collection property
#model InformedProducts.Models.AdminChargeHistory
#{
ViewBag.Title = "Missed Payments";
}
<h2>Missed Payments</h2>
<table class="grid">
<tr>
<th>Customer Id</th>
<th>Amount</th>
<th>Month</th>
<th>Year</th>
</tr>
#foreach (var item in Model.Charges)
{
<tr>
<td class="left"><#item.CustomerId></td>
<td class="left"><#item.Amount></td>
<td class="left"><#item.Month></td>
<td class="left"><#item.Year></td>
</tr>
#}
#Html.LabelFor(m=>m.ErrorMessage)
</table>
if you have red squiggly under #model InformedProducts.Models.AdminChargeHistory you might have the wrong namespace.. Remove InformedProducts.Models. and put cursor on AdminChargeHistory and hit ctrl + . (period) and it should find the correct namespace.
It should be:
#foreach (var item in Model.Charges)
{
// code removed for brevity...
}
This is because your model AdminChargeHistory has a property named Charges which is enumerable. What you are using right now: Model.StripeChargeHistory won't work because there is no such property in the class AdminChargeHistory.
Also, you have public string ErrorMessage { get; set;] }, that bracket looks like a problem.
I am trying to get total on my view.
I am confused what should i do? Please help me out..
I am not understanding where should i use query and ofc I need it in my view to show but how?
Model class
namespace BOL1
{
public class ADetailsVm
{
public List<BOL1.tbl_Transiction> Payables { get; set; }
public List<BOL1.tbl_Transiction> Reciveables { get; set; }
}
}
DbContext
public partial class bankingEntities : DbContext
{
public bankingEntities()
: base("name=bankingEntities")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
public virtual DbSet<tbl_Accounts> tbl_Accounts { get; set; }
public virtual DbSet<tbl_Transiction> tbl_Transiction { get; set; }
public virtual DbSet<tbl_TransictionType> tbl_TransictionType { get; set; }
public DbSet<ADetailsVm> ADetailsVm { get; set; }
}
}
Controller
public class Details : Controller
{
private TransictionBs objbs;
public Details()
{
objbs = new TransictionBs();
}
// GET: Shinwari/AccountDetails
[HttpGet]
public ActionResult Index(int accountid)
{
ADetailsVm v = new ADetailsVm();
//Load both the collection properties
v.Payables = objbs.GetALL().Where(p => p.AId == accountid && p.tbl_TransictionType.Type.Contains("Payable")).ToList();
v.Reciveables = objbs.GetALL().Where(r => r.AId==accountid && r.tbl_TransictionType.Type.Contains("Reciveable")).ToList();
return View(v);
View
#model BOL1.ADetailsVm
#{
ViewBag.Title = "Index";
}
<h2>AccountDetails</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table id="Payables" class="table">
<tr>
<th>
Date
</th>
<th>
Discription
</th>
<th>
Amount
</th>
</tr>
#foreach (var item in Model.Payables)
{
<tr>
<td>
#item.Date
</td>
<td>
#item.TDiscription
</td>
<td>
#item.Amount
</td>
</tr>
}
</table>
Use the LINQ Sum extension method on the Amount property(assuming it is of numeric type) of your Payables collection property of the view model.
<h2> #Model.Payables.Sum(s=>s.Amount) </h2>
Or if you do not like adding so much C# code in razor views(like me :)), You may add a new property to store the total in your view model.
public class ADetailsVm
{
public decimal TotalPayableAmount { set;get;}
public List<BOL1.tbl_Transiction> Payables { get; set; }
public List<BOL1.tbl_Transiction> Reciveables { get; set; }
}
and in your action method, call the Sum method and set the value to our new TotalPayableAmount property.
public ActionResult Index(int accountid)
{
var v = new ADetailsVm();
v.Payables = objbs.GetALL().Where(p => p.AId == accountid &&
p.tbl_TransictionType.Type.Contains("Payable")).ToList();
v.Reciveables = objbs.GetALL().Where(r => r.AId == accountid &&
r.tbl_TransictionType.Type.Contains("Reciveable")).ToList();
v.TotalPayableAmount= v.Payables.Sum(s=>s.Amount)
return View(v);
}
and in your view
#model ADetailsVm
<h2>#Model.TotalPayableAmount</h2>
Newbie to MVC, using MVC 5 and VS 2013.
Code first from existing database, EF6
Goal:
Want to show a listing of all models from the tblModel for an MVP listed in tblMVP
Below is the current state of the project and the runtime error:
Error:
System.Collections.Generic.IEnumerable<WebApplication2.Models.tblAccount>' does not contain a definition for 'tblModels' and no extension method 'tblModels' accepting a first argument of type System.Collections.Generic.IEnumerable<WebApplication2.Models.tblAccount> could be found (are you missing a using directive or an assembly reference?)
Models:
[Table("tblMVP")]
public partial class tblMVP
{
[Key]
public int ID { get; set; }
public int AccountID { get; set; }
public virtual tblAccount tblAccount { get; set; }
}
[Table("tblModel")]
public partial class tblModel
{
[Key]
public int ID { get; set; }
public int AccountID { get; set; }
public virtual tblAccount tblAccount { get; set; }
}
[Table("tblAccount")]
public partial class tblAccount
{
public tblAccount()
{
tblModels = new HashSet();
tblMVPs = new HashSet();
}
public int ID { get; set; }
public virtual ICollection tblModels { get; set; }
public virtual ICollection tblMVPs { get; set; }
}
Controller:
// GET: MVP
public ActionResult Index()
{
var tblAccounts = db.tblAccounts.Include(t => t.tblModels).Include(t => t.tblMVPs);
return View(db.tblAccounts.ToList());
}
View
#model IEnumerable<WebApplication2.Models.tblAccount>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.tblModels.partNumber)
</th>
<th>
#Html.DisplayNameFor(model => model.AccountName)
</th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.tblModels.partNumber)
</td>
<td>
#Html.DisplayFor(modelItem => item.AccountName)
</td>
</tr>
}
</table>
You're trying to do two different things. You have an IEnumerable<tblAccount>, which doesn't have properties, it just has a list of tblAccount.
So in the top, you're trying to get properties of the IEnumerable, but there aren't any.
In the bottom, you're iterating the IEnumerable, and getting properties of the tblAccount, which you are doing correctly.
So in the top section, you need to get a tblAccount from the IEnumerable so that you can get properties of it. Below is an example of how you can do it.
#model IEnumerable<WebApplication2.Models.tblAccount>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.First().tblModels.partNumber)
</th>
<th>
#Html.DisplayNameFor(model => model.First().AccountName)
</th>
</tr>
Ultimately this is is the bare essentials version of what worked. For better or worse a direct relationship between the tblModel and tblMVP was created and the model loading in the controller was rearranged.
Models:
[Table("tblMVP")]
public partial class tblMVP
{
public tblMVP()
{
tblModels = new HashSet();
}
public int ID { get; set; }
public int AccountID { get; set; }
public string Description { get; set; }
public virtual tblAccount tblAccount { get; set; }
public virtual ICollection tblModels { get; set; }
}
[Table("tblModel")]
public partial class tblModel
{
[Key]
public int ModelID { get; set; }
public int AccountID { get; set; }
[Required]
[StringLength(50)]
public string partNumber { get; set; }
[StringLength(5000)]
public string description { get; set; }
public int? MVPID { get; set; }
public virtual tblMVP tblMVP { get; set; }
}
[Table("tblAccount")]
public partial class tblAccount
{
public tblAccount()
{
tblModels = new HashSet();
tblMVPs = new HashSet();
}
public int ID { get; set; }
[StringLength(150)]
public string AccountName { get; set; }
public int? AccountNumber { get; set; }
public virtual ICollection tblModels { get; set; }
public virtual ICollection tblMVPs { get; set; }
}
**Controller:**
// GET: MVP
public ActionResult Index()
{
var tblModels = db.tblModels.Include(t => t.tblAccount).Include(t => t.tblMVP).ToList();
return View(tblModels.ToList());
}
View
#model IEnumerable<MDLX_Bootstrap_V5.Models.tblModel>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.tblAccount.AccountName)
</th>
<th>
#Html.DisplayNameFor(model => model.partNumber)
</th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.tblAccount.AccountName)
</td>
<td>
#Html.DisplayFor(modelItem => item.partNumber)
</td>
</tr>
}
</table>