I have a model course, component, subcomponent and evaluation:
public class Course
{
public virtual int CourseId { get; set; }
(...)
public virtual List<Component> Components { get; set; }
public virtual List<UserCourse> Users { get; set; }
}
public class Component
{
public virtual int ComponentId { get; set; }
public virtual string Type { get; set; }
public virtual string Name { get; set; }
public virtual Course Course { get; set; }
public virtual List<Subcomponent> Subcomponents { get; set; }
}
public class Subcomponent
{
public virtual int SubcomponentId { get; set; }
public virtual int ComponentId { get; set; }
public virtual string TypeSub { get; set; }
public virtual string NameSub { get; set; }
(...)
public virtual int ParentId { get; set; }
public virtual Subcomponent Parent { get; set; }
public virtual List<Subcomponent> Childs { get; set; }
public virtual Component Component { get; set; }
}
public class Evaluation
{
public virtual int EvaluationId { get; set; }
public virtual int ComponentId { get; set; }
public virtual Component Component { get; set; }
public virtual int UserCourseId { get; set; }
public virtual UserCourse User { get; set; }
public virtual int Grade { get; set; }
}
I need to give a grade to each subcomponent (or component if the component doesn't have subcomponents) to each user.
First i have a view that shows the users and the grades already given, like an index:
#model SGP.Models.Course
<table>
<tr>
<th>
Users
</th>
<th>
Grades
</th>
</tr>
#foreach (var x in Model.Users)
{
<tr>
<td>
#Html.DisplayFor(modelItem => x.User.UserName)
</td>
#foreach (var y in x.Evaluation)
{
<td>
<table>
<tr>
<td>
<b>#Html.DisplayFor(modelItem => y.Component.NameComp)</b>
</td>
</tr>
<tr>
<td>
#Html.DisplayFor(modelItem => y.Grade)
</td>
</tr>
</table>
</td>
}
<td>
#Html.ActionLink("Give grade", "Comps", "Evaluation", new { id = x.UserCourseId }, null)
</td>
</tr>
}
</table>
Then when press "Give grade", i have a search box to select the component wich the grade will be given.
The search will give a list of subcomponents of that component. Each component can have one or more subcomponents so the final grade to the component is the average of the subcomponents grades.
The view of the subcomponents:
#model SGP.Models.Component
<table>
<tr>
<th>
#Html.DisplayFor(model => model.NameComp)
</th>
<th>
Grade
</th>
</tr>
#foreach (var item in Model.Subcomponents) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.NameSub)
</td>
<td>
???????
</td>
</tr>
}
</table>
But in this view i need to get the UserCourseId previously selected and give a grade to the user in the selected subcomponent. How can i do that?
Thanks
EDIT:
Give grade:
#using (Html.BeginForm("ListaSubs", "Evaluation", FormMethod.Post))
{
<table>
<tr>
<th>
#Html.TextBox("text")
</th>
<td>
<input type="submit" id="ButtonSearch" value="Search" />
</td>
</tr>
</table>
}
And controller:
[HttpPost, ActionName("ListaSubs")]
public ActionResult ListaSubs(string text)
{
var util = (db.Subcomponents.Where(m =>
m.ComponentId.Equals(text)));
return View("view", util);
}
What I do in this case, is to define a wrapper class and use it for view's model. Something like this:
public class MyWrapperClass
{
public Course _Course { get; set; }
public Component _Component { get; set; }
...
}
Then in your view, you define your model as:
#model MyWrapperClass
For some controls you can simply use the following format for the properties:
#Html.HiddenFor(model => model._Course.CourseId)
But in some cases, you probably have to create EditorTemplate or DisplayTemplate for each subclass and use the templates in the view.
To use Editor template, you need to use a UIHint attribute in the class definition.
Here is some links on how to use editor template in razor:
How to add and use a razor editor template
https://www.simple-talk.com/dotnet/asp-net/extending-editor-templates-for-asp-net-mvc/
Related
Controller:
List<EmployeeSkill> emp = new List<EmployeeSkill>();
public ActionResult viewskills(EmployeeSkill objskillset)
{
emp .Add(objskillset);
return PartialView("_SkillListPartial", objskillset);
}
Model:
public int EmployeeID { get; set; }
[Required(ErrorMessage = "Please Enter Skill")]
public string SkillName { get; set; }
[Display(Name = "Experience (In Months)")]
[Required(ErrorMessage = "Please Enter Experience(In Months)")]
public Nullable<byte> ExperienceInMonths { get; set; }
public string CreatedBy { get; set; }
public Nullable<System.DateTime> CreatedDate { get; set; }
public string ModifiedBy { get; set; }
public Nullable<System.DateTime> ModifiedDate { get; set; }
public Nullable<bool> IsActive { get; set; }
public virtual EmployeeDetail EmployeeDetail { get; set; }
View:
model IEnumerable<CISSEC.Models.EmployeeSkill>
<table class="table">
<tr>
<th> #Html.DisplayNameFor(model => model.SkillName) </th>
<th> #Html.DisplayNameFor(model => model.ExperienceInMonths)</th>
</tr>
#foreach (var item in Model) {
<tr>
<td> #Html.DisplayFor(modelItem => item.SkillName) </td>
<td> #Html.DisplayFor(modelItem => item.ExperienceInMonths) </td>
</tr>
}
</table>
Your list is not posted back because you do not render <input> elements for the properties of the list items. Use HiddenFor to render the inputs. Use a for loop so the modelbinder receives the correct index of the list items.
#for (var i = 0; i < Model.Count(); i++) {
<tr>
<td> #Html.HiddenFor(m => m[i].SkillName) </td>
<td> #Html.HiddenFor(m=> m[i].ExperienceInMonths) </td>
</tr>
}
I have a model Course, a model Component and a model Evaluation:
public class Course
{
public virtual int CourseId { get; set; }
public virtual string Name { get; set; }
public virtual List<Component> Components { get; set; }
public virtual List<UserProfile> Users { get; set; }
public virtual List<Evaluation> Evaluation { get; set; }
}
public class Component
{
public virtual int ComponentId { get; set; }
public virtual int CourseId { get; set; }
public virtual Course Course { get; set; }
public virtual string NameComp { get; set; }
}
public class Evaluation
{
public virtual int EvaluationId { get; set; }
public virtual int CourseId { get; set; }
public virtual Course Course { get; set; }
public virtual int UserId { get; set; }
public virtual UserProfile User { get; set; }
public virtual int Grade { get; set; }
}
I need to show in a view a table with all the users, all the components created and the grade for each one.
I tried this way:
#model SGP.Models.Course
<table>
<tr>
<th>
Username
</th>
#foreach (var x in Model.Components)
{
<th>
#Html.DisplayFor(modelItem => x.NameComp)
</th>
}
<th></th>
</tr>
#foreach (var item in Model.Evaluation)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.User.UserName)
</td>
#foreach (var x in Model.Components)
{
<td>
#Html.DisplayFor(modelItem => item.Grade)
</td>
}
<td>
</td>
</tr>
}
But this gives me all the components in one column, and i need one column for each component, and a grade for each one:
The code i have gives this:
Username - Component1Component2Component3
Test - 12
Test - 13
Test - 10
(example of result with username and grades)
And i need:
Username - Component1 - Component2 - Component3
Test - 12 - 13 - 10
(example of result with username and grades)
How can i do this? Thanks
The definition of Evaluations in Course should be:
public virtual IGrouping<string, Evaluation> Evaluations { get; set; }
The code should be:
#model SGP.Models.Course
<table>
<tr>
<th>
Username
</th>
<th>
#foreach (var x in Model.Components)
{
#Html.DisplayFor(modelItem => x.NameComp)
}
</th>
<th></th>
</tr>
#foreach (var group in Model.Evaluations)
{
<tr>
<td>
#Html.DisplayFor(modelItem => group.Key)
</td>
#foreach (var item in group)
{
<td>
#Html.DisplayFor(modelItem => item.Grade)
</td>
}
<td>
</td>
}
</tr>
You need to make sure the evaluation is in reference to a course component:
public class Evaluation
{
public virtual int EvaluationId { get; set; }
public virtual int CourseId { get; set; }
public virtual Course Course { get; set; }
public virtual int ComponentId { get; set; }
public virtual Component Component { get; set; }
public virtual int UserId { get; set; }
public virtual UserProfile User { get; set; }
public virtual int Grade { get; set; }
}
Here are some test values:
var users = new List<UserProfile>
{
new UserProfile { UserId = 1, UserName = "Jim" },
new UserProfile { UserId = 2, UserName = "Sam" },
};
var components = new List<Component>
{
new Component { ComponentId = 1, NameComp = "Unit 1" },
new Component { ComponentId = 2, NameComp = "Unit 2" }
};
var course = new Course
{
Users = users,
Components = components.OrderBy(c => c.ComponentId).ToList(),
Evaluation = new List<Evaluation>
{
new Evaluation { User = users[0], ComponentId = components[0].ComponentId, Grade = 87 },
new Evaluation { User = users[0], ComponentId = components[1].ComponentId, Grade = 99 },
new Evaluation { User = users[1], ComponentId = components[0].ComponentId, Grade = 75 },
new Evaluation { User = users[1], ComponentId = components[1].ComponentId, Grade = 65 }
}
};
And following Razor view should do what you need:
#model SGP.Models.Course
<table>
<tr>
<th>
Username
</th>
#foreach (var x in Model.Components)
{
<th>
#Html.DisplayFor(modelItem => x.NameComp)
</th>
}
<th></th>
</tr>
#foreach (var userEvaluation in Model.Evaluation.GroupBy(e => e.User))
{
<tr>
<td>
#Html.DisplayFor(modelItem => userEvaluation.Key.UserName)
</td>
#foreach (var x in Model.Components)
{
<td>
#(userEvaluation.FirstOrDefault(e => e.ComponentId == x.ComponentId)?.Grade)
</td>
}
<td></td>
</tr>
}
Watch out for this model, it has a lot of circular references, which can be problematic if you're using something like Entity Framework.
I have created a view which contains 2 tables.
What I want is to filter each table data according to their transaction type for example table1 should show only Payables List and table2 should show only Reciveable List.
here is the code
Note When I navigate to the view server shows me The resource cannot be found.other views are fine. here is my code.
My project has BOL(EF Model) BLL(Business object) DAL(Data Access layer) and my main Mvc project
View
#model shinwari_traders.Areas.Shinwari.Models.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.Discription
</td>
<td>
#item.Amount
</td>
</tr>
}
</table>
<table id="Reciveables" class="table">
<tr>
<th>
Date
</th>
<th>
Discription
</th>
<th>
Amount
</th>
</tr>
#foreach (var item in Model.Reciveables)
{
<tr>
<td>
#item.Date
</td>
<td>
#item.Discription
</td>
<td>
#item.Amount
</td>
</tr>
}
</table>
Controller
public class AccountDetailsController : Controller
{
private TransictionBs objbs;
public AccountDetailsController()
{
objbs = new TransictionBs(int accountid);
}
// GET: Shinwari/AccountDetails
public ActionResult Index(int accountid)
{ var v= new ADetails();
v.Payable = objbs.GetALL().Where(p => p.AId==accountid&& p.tbl_TransictionType.Type.Contains("Payable"));
v.Reciveable = objbs.GetALL().Where(r => r.AId==accountid && r.tbl_TransictionType.Type.Contains("Reciveable"));
return View(v);
}
}
}
Model Class
public class ADetailsVm
{
public List<BOL.tbl_Transiction> Payables { get; set; }
public List<BOL.tbl_Transiction> Reciveables { get; set; }
}
DatabaseTable
public partial class tbl_Transiction
{
public int TId { get; set; }
public Nullable<System.DateTime> Date { get; set; }
public Nullable<int> AId { get; set; }
public string Discription { get; set; }
public Nullable<double> PKR { get; set; }
public Nullable<double> Rate { get; set; }
public Nullable<double> Amount { get; set; }
public Nullable<int> TTId { get; set; }
public virtual tbl_Accounts tbl_Accounts { get; set; }
public virtual tbl_TransictionType tbl_TransictionType { get; set; }
}
You need a new view model with 2 collection properties one for each collection.
public class AccountDetailsVm
{
public List<BOL.tbl_Transiction> Reciveable {set;get;}
public List<BOL.tbl_Transiction> Payable {set;get;}
}
And in your GET action, create an object of this view model, fill these 2 properties.
public ActionResult Index(int accountid)
{
var v=new AccountDetailsVm();
//Load both the collection properties
v.Payables = objbs.GetALL()
.Where(p => p.AId==accountid && p.tbl_TransictionType.Type.Contains("Payable"));
v.Reciveable = objbs.GetByID(accountid).tbl_TransictionType.Type.Contains("Reciveable");
return View(v);
}
And your view is bound to the new view model. I just added the minimal code here. You can convert the rendering to a table.
#model AccountDetailsVm
<h1>Reciveable</h1>
#foreach(var item in Model.Reciveable)
{
<p>#item.Amount</p>
}
<h1>Payable</h1>
#foreach(var item in Model.Payable)
{
<p>#item.Amount</p>
}
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>
I have an entity called Fixture, and basically I want to display some fixtures on the page.
My Model is as follows :-
public class Fixture
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int FixtureId { get; set; }
[Display(Name = "Fixture Date")]
[DisplayFormat(DataFormatString = "{0:dd/MM/yyyy}", ApplyFormatInEditMode = true)]
public DateTime? FixtureDate { get; set; }
public DateTime? FixtureTime { get; set; }
public int? CityId { get; set; }
public City City { get; set; }
public int CountryIdA { get; set; }
public int CountryIdB { get; set; }
public int? ScoreA { get; set; }
public int? ScoreB { get; set; }
public Round Round { get; set; }
public int? RoundId { get; set; }
public List<Scorer> Scorers { get; set; }
}
and my ViewModel is as follows :-
public class FixtureViewModel
{
public Fixture Fixture { get; set; }
public IEnumerable<Fixture> FixtureList { get; set; }
public IEnumerable<GroupCountry> GroupCountryList { get; set; }
public IEnumerable<Group> GroupList { get; set; }
public string CountryNameA { get; set; }
public string CountryNameB { get; set; }
}
and I am displaying them in this index page :-
<table>
<tr>
<th>
#Html.DisplayName("Date")
</th>
<th>
#Html.DisplayName("Country A")
</th>
<th>
#Html.DisplayName("Country A")
</th>
<th>
#Html.DisplayName("Score A")
</th>
<th>
#Html.DisplayName("Score B")
</th>
<th>
#Html.DisplayName("Round")
</th>
<th></th>
</tr>
#foreach (Fixture item in Model.FixtureList)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.FixtureDate)
</td>
<td>
#Html.DisplayFor(modelItem => item.CountryIdA)
</td>
<td>
#Html.DisplayFor(modelItem => item.CountryIdB)
</td>
<td>
#Html.DisplayFor(modelItem => item.ScoreA)
</td>
<td>
#Html.DisplayFor(modelItem => item.ScoreB)
</td>
<td>
#Html.DisplayFor(modelItem => item.Round.RoundName)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new {id = item.FixtureId}) |
#Html.ActionLink("Details", "Details", new {id = item.FixtureId}) |
#Html.ActionLink("Delete", "Delete", new {id = item.FixtureId})
</td>
</tr>
}
</table>
Now in the index page, I wish to display something like this :-
<td>
#Html.DisplayFor(modelItem => item.CountryIdA.Country.CountryName)
</td>
<td>
#Html.DisplayFor(modelItem => item.CountryIdB.Country.CountryName)
</td>
How can I achieve that?
I added a navigation item Country in the Model, however I still cannot display the correct CountryName.
Thanks for your help and time
Well CountryIdA and CountryIdB are just Integers. If you are trying to say...
Find a fixture with CountryIdA/B, then get it's Country, and then CountryName
then this is not appropriate to put in a view. Your view should not handle any data access, that is the job of your controller/model. I would suggest adding two Country properties to your view model, one for IdA and one for IdB. Then you can populate these in your controller action and have access to them in your view.
Your controller might look something like...
ViewModel.CountryA = Countries.Where(x => x.CountryID = ViewModel.CountryIdA)
You can extend Fixture in your model by creating a partial class Fixture in the same namespace, create two custom properties CountryIdA/B that does a lookup for the currect IDs.