How to show some results in Index View - c#

I have two model classes: Artist and Album, I want to show in the Index View that belong to Artist the total amount of Albums per Artist, I want to create other column besides "Name" and "LastName" named "AlbumsTotal" with the total amount of albums produced by the artist, inside Index View, here is an example of what I want:
Name LastName TotalAlbums
Frank Sinatra 4
Celine Dion 6
I know how to do that creating a ViewModel and using other view, but I want to use the same view that belongs to Artist and display the information. Can you let me know how I can do this?
Model classes:
public class Artist
{
public int ArtistID { get; set; }
[Display(Name ="Artist name")]
public string Name { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
public virtual List<Album> Albums { get; set; }
}
public class Album
{
public int AlbumID { get; set; }
public string AlbumName { get; set; }
public virtual Artist Artist { get; set; }
public int ArtistID { get; set; }
}
Index View:
#model IEnumerable<AlexMusicStore.Models.Artist>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.Name)
</th>
<th>
#Html.DisplayNameFor(model => model.LastName)
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.LastName)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.ArtistID }) |
#Html.ActionLink("Details", "Details", new { id=item.ArtistID }) |
#Html.ActionLink("Delete", "Delete", new { id=item.ArtistID }) |
</td>
</tr>
}
</table>

One possible way is as follow.
Since you already have the albums in a collection on the Artist, and assuming you load all the albums of the artist into this collection, you can show the total amount of albums for the artist by using the Count() method of the List.
Change your View's code to look as follow:
#model IEnumerable<AlexMusicStore.Models.Artist>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.Name)
</th>
<th>
#Html.DisplayNameFor(model => model.LastName)
</th>
<th>
#Html.DisplayName("TotalAlbums")
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.LastName)
</td>
<td>
#item.Albums.Count()
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.ArtistID }) |
#Html.ActionLink("Details", "Details", new { id=item.ArtistID }) |
#Html.ActionLink("Delete", "Delete", new { id=item.ArtistID }) |
</td>
</tr>
}
</table>

Related

Get the Child Class Propert in Parent class

I had a two controllers in my application with database first approach
SampCutReqMaster.CS
public partial class SampCutReqMaster
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public SampCutReqMaster()
{
this.SamCutAssignmentMasters = new HashSet<SamCutAssignmentMaster>();
}
public decimal SampCutreqID { get; set; }
public Nullable<decimal> BuyerID { get; set; }
public Nullable<decimal> PatternRefID { get; set; }
public Nullable<decimal> PatternStyleID { get; set; }
public Nullable<decimal> SampleTypeID { get; set; }
public virtual BuyerMaster BuyerMaster { get; set; }
public virtual PatternStyle PatternStyle { get; set; }
public virtual PatterRefMaster PatterRefMaster { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<SamCutAssignmentMaster> SamCutAssignmentMasters { get; set; }
public virtual SampleType SampleType { get; set; }
}
and The next is
SamCutAssignmentMaster
public partial class SamCutAssignmentMaster
{
public decimal CutAssignID { get; set; }
public decimal SampCutreqID { get; set; }
public System.DateTime ReceivedDate { get; set; }
public string ReceivedBy { get; set; }
public Nullable<decimal> PatternMasterID { get; set; }
public virtual PatternMaster PatternMaster { get; set; }
public virtual SampCutReqMaster SampCutReqMaster { get; set; }
}
I had created a controller with a index view for SampCutReqMaster
public class SampCutReqMastersController : Controller
{
private ArtEntities db = new ArtEntities();
// GET: SampCutReqMasters
public ActionResult Index()
{
var sampCutReqMasters = db.SampCutReqMasters.Include(s => s.BuyerMaster).Include(s => s.PatternStyle).Include(s => s.PatterRefMaster).Include(s => s.SampleType).Include(s=>s.SamCutAssignmentMasters);
var sampCutReqMasterssort = sampCutReqMasters.ToList().OrderByDescending(a => a.AddedDate);
return View(sampCutReqMasterssort.ToList());
}
}
I want to get the "receivedBy" of SamcutAssignmentMaster(child class) in my view of SamCutReqMaster (Parent).But there may be no data in SamcutAssignmentMaster relavant to SamCutReqMaster (FK is SamCutReqID)
In Index view Below I need to access SamcutAssignmentMaster.receivedBy
#model IEnumerable<WebArtSampler.Models.SampCutReqMaster>
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Index</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.ReqNum)
</th>
<th>
#Html.DisplayNameFor(model => model.Fabric)
</th>
<th>
#Html.DisplayNameFor(model => model.SampleRequiredDate)
</th>
<th>
#Html.DisplayNameFor(model => model.AddedDate)
</th>
<th>
#Html.DisplayNameFor(model => model.AddedBy)
</th>
<th>
#Html.DisplayNameFor(model => model.BuyerMaster.BuyerName)
</th>
<th>
#Html.DisplayNameFor(model => model.PatternStyle.StyleName)
</th>
<th>
#Html.DisplayNameFor(model => model.PatterRefMaster.PatterRefNum)
</th>
<th>
#Html.DisplayNameFor(model => model.SampleType.SampleType1)
</th>
<th>
#Html.DisplayNameFor(model => model.SizeDetail)
</th>
<th>
#Html.DisplayNameFor(model => model.Qty)
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.ReqNum)
</td>
<td>
#Html.DisplayFor(modelItem => item.Fabric)
</td>
<td>
#Html.DisplayFor(modelItem => item.SampleRequiredDate)
</td>
<td>
#Html.DisplayFor(modelItem => item.AddedDate)
</td>
<td>
#Html.DisplayFor(modelItem => item.AddedBy)
</td>
<td>
#Html.DisplayFor(modelItem => item.BuyerMaster.BuyerName)
</td>
<td>
#Html.DisplayFor(modelItem => item.PatternStyle.StyleName)
</td>
<td>
#Html.DisplayFor(modelItem => item.PatterRefMaster.PatterRefNum)
</td>
<td>
#Html.DisplayFor(modelItem => item.SampleType.SampleType1)
</td>
<td>
#Html.DisplayFor(modelItem => item.SizeDetail)
</td>
<td>
#Html.DisplayFor(modelItem => item.Qty)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.SampCutreqID }) |
#Html.ActionLink("Details", "Details", new { id=item.SampCutreqID }) |
#Html.ActionLink("Delete", "Delete", new { id=item.SampCutreqID })
</td>
</tr>
}
</table>
Ok. You can't access the properties whilst your type is still as the interface ICollection. You need to cast it to a concrete type before you can access the properties of the collection via an index.
#for (var adCounter = 0; adCounter <= (Model.SamCutAssignmentMasters.Count - 1); adCounter++)
{
#Html.DisplayFor(x => ((List<SamCutAssignmentMaster>)x.SamCutAssignmentMasters)[adCounter].ReceivedBy)
}
Cast the type to a list as per the above and you should see the properties.
NOTE: You are using DisplayFor in your view. If you intend to post the contents of this view the model will not bind unless you have a hidden control for each item or you switch to TextBoxFor. You will also need the for (Counter) syntax as well to bind to items in collections.
Hope that helps.

Passing a parameter to Html.ActionLink

I am trying to pass a parameter to the Create #Html.ActionLink in the Index view however I am having some difficulties.
I have an Address controller in which the user sees the addresses of a specific person when they access the Index view. I would like to pass this PersonID to the Create view so that they do not have to select or enter the person when they create a new address. My actionlink looks like this -
#Html.ActionLink("Create New", "Create", new { id = Model.[PersonID is not a choice]})
My problem is that after Model PersonID is not an option. I am not sure how to get PersonID to the Create function in the AddressController.
I tried following along with the post - Passing a parameter to Html.ActionLink when the model is IEnumerable<T> - where they are having the same issue. The first answers seems like a likely solution however I could not duplicate the model they created and when I put the pieces in my Address model I could not duplicate the code they had performed in the controller. Is there another solution?
My Address Model -
public partial class Address
{
public int AddressID { get; set; }
public int PersonID { get; set; }
[Display(Name="Address")]
public string Address1 { get; set; }
[Display(Name = "Address 2")]
public string Address2 { get; set; }
public string City { get; set; }
[Display(Name="State")]
public string StateAbbr { get; set; }
[Display(Name = "Zip Code")]
public string Zip { get; set; }
public virtual Person Person { get; set; }
public List<Address> Address { get; set; }
}
My AddressController Index
public ActionResult Index(int id)
{
var addresses = db.Addresses.Include(a => a.Person)
.Where(a => a.PersonID == id);
Person person = db.People.Find(id);
ViewBag.FullName = person.FirstName + " " + person.LastName;
person.PersonID = id;
return View(addresses.ToList());
}
Address Index view -
#model IEnumerable<OpenBurn.Models.Address>
#{
ViewBag.Title = "Address";
}
<h2>Address</h2>
<p>
#Html.ActionLink("Create New", "Create", new { id = .PerosnID })
</p>
<h3 style="color: #008cba;"> #ViewBag.FullName </h3>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.Address1)
</th>
<th>
#Html.DisplayNameFor(model => model.Address2)
</th>
<th>
#Html.DisplayNameFor(model => model.City)
</th>
<th>
#Html.DisplayNameFor(model => model.StateAbbr)
</th>
<th>
#Html.DisplayNameFor(model => model.Zip)
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Address1)
</td>
<td>
#Html.DisplayFor(modelItem => item.Address2)
</td>
<td>
#Html.DisplayFor(modelItem => item.City)
</td>
<td>
#Html.DisplayFor(modelItem => item.StateAbbr)
</td>
<td>
#Html.DisplayFor(modelItem => item.Zip)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.AddressID }) |
#Html.ActionLink("Details", "Details", new { id=item.AddressID }) |
#Html.ActionLink("Delete", "Delete", new { id=item.AddressID })
</td>
</tr>
}
</table>
Since the #Html.ActionLink syntax isn't inside a foreach loop, you obviously can't use IEnumerable<OpenBurn.Models.Address> as the model. You need a new model class that contains a property that holds those Address records and a property that holds the PersonID value. You should also use the same model class to pass the FullName value instead of using ViewBag. I would suggest the below model class
public class AddressIndexModel
{
public AddressIndexModel()
{
this.Addresses = new List<Address>();
}
public int PersonID { get; set; }
public string FullName { get; set; }
public List<Address> Addresses { get; set; }
}
then change your controller to this
public ActionResult Index(int id)
{
var addresses = db.Addresses.Include(a => a.Person)
.Where(a => a.PersonID == id);
Person person = db.People.Find(id);
AddressIndexModel model = new AddressIndexModel();
model.PersonID = id;
model.FullName = person.FirstName + " " + person.LastName;
model.Addresses = addresses.ToList();
return View(model);
}
and change your view to below
#model AddressIndexModel
#{
ViewBag.Title = "Address";
}
<h2>Address</h2>
<p>
#Html.ActionLink("Create New", "Create", new { id = Model.PersonID })
</p>
<h3 style="color: #008cba;"> #Model.FullName </h3>
<table class="table">
<tr>
<th>
Address
</th>
<th>
Address 2
</th>
<th>
City
</th>
<th>
State
</th>
<th>
Zip Code
</th>
<th></th>
</tr>
#foreach (var item in Model.Addresses) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Address1)
</td>
<td>
#Html.DisplayFor(modelItem => item.Address2)
</td>
<td>
#Html.DisplayFor(modelItem => item.City)
</td>
<td>
#Html.DisplayFor(modelItem => item.StateAbbr)
</td>
<td>
#Html.DisplayFor(modelItem => item.Zip)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.AddressID }) |
#Html.ActionLink("Details", "Details", new { id=item.AddressID }) |
#Html.ActionLink("Delete", "Delete", new { id=item.AddressID })
</td>
</tr>
}
</table>

The popular model item passed into the dictis of type System.Collections.Generic.List`1[X] but this dictionary requires a model item of type X

So yeah I have investigated and read a lot of responses here but they all have mismatch with data types.. I cannot figure out why this is happening.
public class RestaurantBranchModel
{
public int id { get; set; }
public string name { get; set; }
public string telephone { get; set; }
public int master_restaurant_id { get; set; }
//public RestaurantModel master_restaurant { get; set; }
public int address_id { get; set; }
//public AddressModel address { get; set; }
}
Controller
RestaurantBranchRepository RestaurantBranchRepository = new RestaurantBranchRepository();
IEnumerable<RestaurantBranchModel> Branches;
// GET: RestaurantBranch
public ActionResult Index()
{
Branches = RestaurantBranchRepository.GetBranches();
return View(Branches); //I've also tried adding .ToList()
}
View
#model IEnumerable<OrdenarBackEnd.Models.RestaurantBranchModel>
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_XenonLayoutPage.cshtml";}
<h2>Index</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.name)
</th>
<th>
#Html.DisplayNameFor(model => model.telephone)
</th>
<th>
#Html.DisplayNameFor(model => model.master_restaurant_id)
</th>
<th>
#Html.DisplayNameFor(model => model.address_id)
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.name)
</td>
<td>
#Html.DisplayFor(modelItem => item.telephone)
</td>
<td>
#Html.DisplayFor(modelItem => item.master_restaurant_id)
</td>
<td>
#Html.DisplayFor(modelItem => item.address_id)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.id }) |
#Html.ActionLink("Details", "Details", new { id=item.id }) |
#Html.ActionLink("Delete", "Delete", new { id=item.id })
</td>
</tr>
}
</table>
#section BottomScripts{}
//END OF CODE
So.. I have a the model. I pass a collection of items in the View, the View is under the LIST template for mvc, and it says i am passing a generic list but it needs a single object ? what gives??..
This is the error
The model item passed into the dictionary is of type 'System.Collections.Generic.List`1[OrdenarBackEnd.Models.RestaurantBranchModel]', but this dictionary requires a model item of type 'OrdenarBackEnd.Models.UserModel'.
Change
#Html.DisplayNameFor(model => model.name)
To
#Html.DisplayNameFor(model => model.First().name)
Basically it needs a single object and you are passing in a list.

Getting the UserName of an ApplicationUser into a view

I am trying to display the name of an author of a question but unlike the other properties of the model, the ApplicationUser.UserName property does not show in the view (it's just blank). I am using Entity Framework, MVC 5 and Razor.
My Question model:
public class Question
{
public int QuestionID { get; set; }
public string Title { get; set; }
public ApplicationUser Author { get; set; }
public string Description { get; set; }
[DisplayName("Created")]
public DateTime CreationDateTime { get; set; }
public int Rating { get; set; }
}
My QuestionController Index action:
// GET: Questions
public ActionResult Index()
{
return View(db.Questions.ToList());
}
And the view:
#model IEnumerable<Waegogi.Models.Question>
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.Title)
</th>
<th>
#Html.DisplayNameFor(model => model.Author.UserName)
</th>
<th>
#Html.DisplayNameFor(model => model.Description)
</th>
<th>
#Html.DisplayNameFor(model => model.CreationDateTime)
</th>
<th>
#Html.DisplayNameFor(model => model.Rating)
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Title)
</td>
<td>
#Html.DisplayFor(modelItem => item.Author.UserName)
</td>
<td>
#Html.DisplayFor(modelItem => item.Description)
</td>
<td>
#Html.DisplayFor(modelItem => item.CreationDateTime)
</td>
<td>
#Html.DisplayFor(modelItem => item.Rating)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.QuestionID }) |
#Html.ActionLink("Details", "Details", new { id=item.QuestionID }) |
#Html.ActionLink("Delete", "Delete", new { id=item.QuestionID })
</td>
</tr>
}
</table>
Where am I going wrong?
You should be able to solve this by explicitly loading your relationships in your controller call:
public ActionResult Index()
{
return View(db.Questions.Include(q => q.ApplicationUser).ToList());
}

MVC Model binding on multiple edit

I have the following view model
public class ResourceProjectedCapacitiesModel
{
public int ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Location { get; set; }
public string Manager { get; set; }
public string Role { get; set; }
public string Project { get; set; }
public decimal Capacity { get; set; }
public System.DateTime Date { get; set; }
}
In my GET action i display all these in the view.
[HttpPost]
public ActionResult Index(List ResourceProjectedCapacitiesModel> list)
{
foreach (ResourceProjectedCapacitiesModel item in list)
{
....
}
....
}
In the view there is the following editor but when the form is submitted the binding doesnt work, list is null
#Html.EditorFor(modelItem => item.Capacity)
#Html.HiddenFor(modelItem => item.ID)
#model List<CapacityPlanner.ViewModels.ResourceProjectedCapacitiesModel>
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
#using(Html.BeginForm())
{
<table class="table">
<tr>
<th>
First Name
</th>
<th>
Last Name
</th>
<th>
Location
</th>
<th>
Manager
</th>
<th>
Role
</th>
<th>
Project
</th>
<th>Apr</th>
<th>May</th>
<th>Jun</th>
<th>Jul</th>
<th>Aug</th>
<th>Sep</th>
<th>Oct</th>
<th>Nov</th>
<th>Dec</th>
<th>Jan</th>
<th>Feb</th>
<th>Mar</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.FirstName)
</td>
<td>
#Html.DisplayFor(modelItem => item.LastName)
</td>
<td>
#Html.DisplayFor(modelItem => item.Location)
</td>
<td>
#Html.DisplayFor(modelItem => item.Manager)
</td>
<td>
#Html.DisplayFor(modelItem => item.Role)
</td>
<td>
#Html.DisplayFor(modelItem => item.Project)
</td>
#for(var i = 1; i <= 12; i++)
{
<td>
#if(item.Date.Month == i)
{
#Html.EditorFor(modelItem => item.Capacity)
}
</td>
}
<td>
#Html.HiddenFor(modelItem => item.ID)
</td>
</tr>
}
</table>
<input type="submit" value="Save" class="btn btn-default" />
}
I have inserted the code of my view
You should use for instead of foreach.
#for (int i = 0; i < Model.Items.Count; i++)
{
#Html.EditorFor(model => Model.Items[i].Amount)
#Html.HiddenFor(model => Model.Items[i].Amount)
}
Then all filled will get different id.

Categories