I am new to MVC and would like to display data from two models in a view in table form.
this is my Customer model:
public class Customer
{
public int CustomerID { get; set; }
[Display(Name = "First Name")]
public string CustomerFirstName { get; set; }
[Display(Name = "Last Name")]
public string CustomerLastName { get; set; }
[Column(TypeName = "VARCHAR")]
[StringLength(50)]
[Display(Name = "Email")]
public string CustomerEmail { get; set; }
[Column(TypeName = "VARCHAR")]
[StringLength(50)]
[Display(Name = "Street")]
public string CustomerAddress1 { get; set; }
[Column(TypeName = "VARCHAR")]
[StringLength(50)]
[Display(Name = "Suburb")]
public string CustomerAddress2 { get; set; }
[Column(TypeName = "VARCHAR")]
[StringLength(50)]
[Display(Name = "City")]
public string CustomerAddress3 { get; set; }
[Column(TypeName = "VARCHAR")]
[StringLength(50)]
[Display(Name = "Postal code")]
public string PostalCode { get; set; }
[Column(TypeName = "VARCHAR")]
[StringLength(10)]
[Display(Name = "Cellphone Number")]
public string CustomerCell { get; set; }
[Display(Name = "Customer Name")]
public string FullName
{
get { return CustomerFirstName + " " + CustomerLastName; }
}
public virtual ICollection<Purchase> Purchases { get; set; }
}
}
this is my Hire model:
public class Hire
{
public int HireID { get; set; }
[Display(Name = "Equipment type")]
public int EquipmentID { get; set; }
public int PurchaseID { get; set; }
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
[Display(Name = "Returned date")]
public DateTime? ReturnedDate { get; set; }
public virtual Purchase Purchases { get; set; }
public virtual Equipment Equipments { get; set; }
}
This is my ViewModel:
public class Custhire
{
public string CustomerFirstName { get; set; }
public string CustomerLastName { get; set; }
public string CustomerEmail { get; set; }
public string CustomerCell { get; set; }
public int HireID { get; set; }
public DateTime? ReturnedDate { get; set; }
}
This is my controller I use to pass the view model to the view:
public ActionResult Table()
{
Custhire model = new Custhire();
return View(model);
}
This is my view:
#model IEnumerable<FCproject.ViewModel.Custhire>
#{
ViewBag.Title = "Table";
}
<h2>Table</h2>
<table class="table table-condensed"
<thead>
<tr>
<th>CustomerID</th>
<th>Equipment</th>
<th>Retrned date</th>
<th></th>
<th></th>
</tr>
</thead>
<body>
#foreach (var item in ViewModel.Custhire)
{
<tr>
<td>
#Html.DisplayFor(m => item.CustomerFirstName)
</td>
<td>
#Html.DisplayFor(m => item.CustomerLastName)
</td>
<td>
#Html.DisplayFor(m => item.CustomerEmail)
</td>
<td>
#Html.DisplayFor(m => item.CustomerCell)
</td>
<td>
#Html.DisplayFor(m => item.HireID)
</td>
<td>
#Html.DisplayFor(m => item.ReturnedDate)
</td>
</tr>
}
</body>
<tr>
</table>
in my view, my #foreach says ViewModel does not exist in current context
There are couple of things to check for -
You have bind your view with -
IEnumerable<FCproject.ViewModel.Custhire>
And the Controller snippet that you have provided returns, single Custhire object. Which actually should return IEnumerable of Custhire Something for example like -
public ActionResult Table()
{
List<Custhire> model = new List<Custhire>();
//keep adding the "Custhire" to the collection
//as per your requirement
model.Add(new Custhire());
return View(model);
}
Second, you need to replace,
#foreach (var item in ViewModel.Custhire)
with this
#foreach (var item in Model)
as the Model itself contains collection of Custhire.
When you create view, ensure that is strongly typed
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:
There is a textbox and a dropdown list box. If textbox is selected then shows a validation for dropdown which means dropdown should also be selected and If dropdown is selected then shows a validation for textbox which means textbox should also be selected If none is selected then do not show any validation.
And I want the condition on Model class in mvc.
<table class="simple">
<thead>
<tr>
<th colspan="2">Heading </th>
</tr>
</thead>
<tbody>
<tr>
<td>
#Html.TextBoxFor(model.prop2,new
{#class = "form- control font-9 p-1" })
</td>
<td>
#(Html.Kendo().DropDownListFor(m =>
m.prop1))
.DataTextField("Type")
.DataValueField("Id")
.OptionLabel(PleaseSelect)
.HtmlAttributes(new { #class = "form-control" }))
</td>
</tr>
<tr>
<td>
#Html.TextBoxFor(model.prop4,new
{#class = "form- control font-9 p-1" })
</td>
<td>
#(Html.Kendo().DropDownListFor(m =>
m.prop3))
.DataTextField("Type")
.DataValueField("Id")
.OptionLabel(PleaseSelect)
.HtmlAttributes(new { #class = "form-control" }))
</td>
</tr>
</tbody>
</table>
Model Class is -
public class ViewModel
{
public int? prop1 { get; set; }
public decimal? prop2 { get; set; }
public int? prop3 { get; set; }
public decimal? prop4 { get; set; }
}
Create a new class
public class Custom : ValidationAttribute
{
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
//Get your model and do magic!
var model = (yourmodel)validationContext.ObjectInstance;
//Your condtions
if ((model.prop1== null && model.prop2 == null) || (model.prop1!= null && model.prop2 != null))
{
return ValidationResult.Success;
}
else
{
return new ValidationResult("You must select both of them");
}
}
}
now add your custom Annotation
public class RefractionFinalViewModel
{
[custom]
[Display(Name = "Select type")]
public int? prop1 { get; set; }
public decimal? prop2 { get; set; }
public int? prop3 { get; set; }
public decimal? prop4 { get; set; }
}
View
#Html.LabelFor(m => m.prop3 )
#Html.DropDownListFor(m => m.prop3 , new SelectList(your items, "Id", "type"), "", new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.prop3 )
Or you can use Foolproof package
[RequiredIf("prop2!= null", ErrorMessage = "prop1")]
public int? prop1{ get; set; }
[RequiredIf("prop1> 0", ErrorMessage = "prop2")]
public decimal? prop2{ get; set; }
[RequiredIf("prop4!= null", ErrorMessage = "prop3")]
public int? prop3{ get; set; }
[RequiredIf("prop3> 0", ErrorMessage = "prop4")]
public decimal? prop4{ get; set; }
Simply I applied the validation on Model Class.
[RequiredIf("prop2!= null", ErrorMessage = "prop1 required")]
public int? prop1{ get; set; }
[RequiredIf("prop1> 0", ErrorMessage = "prop2 required")]
public decimal? prop2{ get; set; }
[RequiredIf("prop4!= null", ErrorMessage = "prop3 required")]
public int? prop3{ get; set; }
[RequiredIf("prop3> 0", ErrorMessage = "prop4 required")]
public decimal? prop4{ get; set; }
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>
1st model:
public class VehicleMake
{
[Key]
public int MakeId { get; set; }
public string Make { get; set; }
}
2nd Model:
public class VehicleModel
{
[Key]
public int ModelId { get; set; }
public string Model { get; set; }
public DateTime Year { get; set; }
public int MakeId { get; set; }
public VehicleMake VehcileMake { get; set; }
}
How to pass two models as strongly typed view.
my view has 1) one dropdownlist which bind make and makeid from VehicleMake class
2) one textbox as Model which binds from vehicleModle class
Please suggest how to create a view using multiple models?
#model MvcApplication1.Data.ViewVMModel
....
<h2>CreateModel</h2>
<table>
<tr>
<td>#Html.Label("Select Make")</td>
<td>#Html.DropDownListFor(model=>model.VehicleMake,new SelectList(Model. "MakeId","Make")))</td>
</tr>
<tr>
<td>Enter Model </td>
<td>#Html.TextBoxFor(model=>model.VehcileModel)</td>
</tr>
</table>
You're editing data so first step is to create a view model (add other validation attributes as required).
public class VehicleVM
{
[Required(ErrorMessage = "...")]
public string Model { get; set; }
[Required(ErrorMessage = "...")]
public DateTime? Year { get; set; } // make nullable to protect against under-posting attacks
[Required(ErrorMessage = "...")]
[Display(Name = "Make")]
public int? SelectedMake { get; set; }
public IEnumerable<SelectListItem? MakesList { get; set; }
}
and in the GET method, initialize an instance of your view model, populate it and pass it to the view
var makes = db.VehicleMakes; // get the Makes from the database
VehicleVM vehicle = new VehicleVM()
{
MakesList = new SelectList(makes, "MakeId", "Make")
};
return View(vehicle);
and in the view
#model VehicleVM
....
#using (Html.BeginForm())
{
#Html.LabelFor(m => m.SelectedMake)
#Html.DropDownListFor(m => m.SelectedMake, Model.MakesList)
#Html.ValidationMessageFor(m => m.SelectedMake)
#Html.LabelFor(m => m.Model)
#Html.TextBoxFor(m => m.Model)
#Html.ValidationMessageFor(m => m.Model)
....
Which will post back to
public ActionResult Create(VehicleVM vehicle)
your Viewmodel should be something like this
public VehicleModel VehicleModel { get; set; }
public List<VehicleMake> VehcileMakeList { get; set; }
and in your view
#model MvcApplication1.Data.ViewVMModel
....
<h2>CreateModel</h2>
<table>
<tr>
<td>#Html.Label("Select Make")</td>
<td>#Html.DropDownListFor(model=>model.VehicleModel.MakeId ,new SelectList(Model.VehcileMakeList, "MakeId","Make")))</td>
</tr>
<tr>
<td>Enter Model </td>
<td>#Html.TextBoxFor(model=>model.VehcileModel.Model)</td>
<td>#Html.TextBoxFor(model=>model.VehcileModel.Year )</td>
</tr>
</table>
and in your action
ViewVMModel vm = new ViewVMModel();
vm.VehcileMakeList = //get list of make
vm.VehicleModel = new VehicleModel();
return view(vm);
I'm working in ASP.NET MVC 4 and I have the problem that my model validation isn't working correctly. For some reason not all my required fields have to be filled in.
Here's my model:
public class MovieModel
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
public DateTime ReleaseDate { get; set; }
[Required]
public string Genre { get; set; }
[Required]
public decimal Price { get; set; }
public virtual ICollection<RoleInMovie> RoleInMovie { get; set; }
}
Here's the View:
#using (Html.BeginForm())
{
<table>
<tr>
<td>
<label>Name:</label></td>
<td>#Html.EditorFor(m => m.Name)</td>
<td>#Html.ValidationMessageFor(m => m.Name)</td>
</tr>
<tr>
<td>
<label>Genre:</label></td>
<td>#Html.EditorFor(m => m.Genre)</td>
<td>#Html.ValidationMessageFor(m => m.Genre)</td>
</tr>
<tr>
<td>
<label>Price:</label></td>
<td>#Html.EditorFor(m => m.Price)</td>
<td>#Html.ValidationMessageFor(m => m.Price)</td>
</tr>
</table>
<button type="submit">Submit</button>
}
And here's my action:
[HttpPost]
public ActionResult Add(MovieModel model)
{
if(ModelState.IsValid)
{
return RedirectToAction("Index");
}
return View();
}
Now here's the thing: as soon as I enter only a price, modelstate.isvalid becomes true. When hovering over my model, it sais both name and genre are null. Ofcourse they are required, but the validation doesn't work.
Also, the validationmessagefor only works on price.
I hope I'm not overlooking something too ridiculous. Thanks for the help!
Return the invalid model back to the view:
[HttpPost]
public ActionResult Add(MovieModel model)
{
if(ModelState.IsValid)
{
return RedirectToAction("Index");
}
return View(model); // <----
}
Oh, and make sure that the required attribute is disallowing empty strings
http://msdn.microsoft.com/en-us/library/system.componentmodel.dataannotations.requiredattribute.allowemptystrings.aspx
public class MovieModel
{
public int Id { get; set; }
[Required(AllowEmptyStrings = false)]
public string Name { get; set; }
public DateTime ReleaseDate { get; set; }
[Required(AllowEmptyStrings = false)]
public string Genre { get; set; }
[Required]
public decimal Price { get; set; }
public virtual ICollection<RoleInMovie> RoleInMovie { get; set; }
}