wdarnellg
asked on
MVC-5: Show Full Names
I would like to show a FullName from a computed property at the top of a view. I can see the FullName property when I look at the Autos log. But the lambda expression used in the Html helper only shows the property name, not the data. Is there any way to display the data that the log seems to show to be available?
The View:
The controller:
The debugger's Auto Log:
The browser view:
The View:
<div class="container">
@using (Html.BeginForm("Index", "Attendances", FormMethod.Get))
{
<div class="row">
<div class="col-md-4">
<p>
<h3>Attendances for player: @Html.DisplayNameFor(model => model.FullName) </h3>
</p>
</div>
<div class="col-md-4">
<p>
<h4>Attendances Recorded: @Model.Count() </h4>
</p>
</div>
</div>
}
</div>
The controller:
public ActionResult Index(int? Id )
{
//Get the rosters and their attendance records
IQueryable<Attendances> attendances = db.Attendances
.Where(a => a.Enrollments_Attendance == Id)
.Include(e => e.Enrollments.Individuals)
.OrderByDescending(a => a.AttendanceDate);
ViewBag.EnrollmentId = Id;
var sql = attendances.ToString();
return View(attendances.ToList());
}
The debugger's Auto Log:
The browser view:
ASKER
The Attendances model:
public class Attendances
{
public int Id { get; set; }
[Required]
[StringLength(15)]
public string Type { get; set; }
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:MM-dd-yyyy}", ApplyFormatInEditMode = true)]
public DateTime AttendanceDate { get; set; }
[StringLength(255)]
public string Comments { get; set; }
[Display(Name="Enrollments")]
public int Enrollments_Attendance { get; set; }
public virtual Enrollments Enrollments { get; set; }
[NotMapped]
public string FullName
{
get
{
var player = Enrollments.Individuals.FirstName + " " + Enrollments.Individuals.LastName;
return player;
}
}
}
Actually I need the complete View (especially the model definition).
Notice that the controller is sending a List of Attendances, need to check how the view is set up. Thanks.
Notice that the controller is sending a List of Attendances, need to check how the view is set up. Thanks.
ASKER
The complete View:
@model IEnumerable<SlamJammersData.Model.Attendances>
@{
ViewBag.Title = "Rosters";
}
<div class="container container-fluid">
<div class="panel panel-info">
<div class="panel-body">
<div class="container">
@using (Html.BeginForm("Index", "Attendances", FormMethod.Get))
{
<div class="row">
<div class="col-md-4">
<p>
<h3>Attendances for player: @Html.DisplayNameFor(model => model.FullName) </h3>
</p>
</div>
<div class="col-md-4">
<p>
<h4>Attendances Recorded: @Model.Count() </h4>
</p>
</div>
</div>
}
</div>
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="col-md-2">
<p>
@Html.DisplayNameFor(model => model.Type)
</p>
</div>
<div class="col-md-2">
<p>
@Html.DisplayNameFor(model => model.AttendanceDate)
</p>
</div>
<div class="col-md-2">
<p>
@Html.DisplayNameFor(model => model.Comments)
</p>
</div>
</div>
@foreach (var item in Model)
{
<div class="row table-striped">
<div class="col-md-2">
<p>
@Html.DisplayFor(modelItem => item.Type)
</p>
</div>
<div class="col-md-2">
<p>
@Html.DisplayFor(modelItem => item.AttendanceDate)
</p>
</div>
<div class="col-md-2">
<p>
@Html.DisplayFor(modelItem => item.Comments)
</p>
</div>
<div class="col-md-1">
<p>
<input class="btn btn-xs btn-info" type="button" value="Details" onclick=" location.href = '@Url.Action("Details", "Attendances", new {id = item.Id}, null)' "/>
</p>
</div>
<div class="col-md-1">
<p>
<input class="btn btn-xs btn-info" type="button" value="Edit" onclick=" location.href = '@Url.Action("Edit", "Attendances", new {id = item.Id}, null)' "/>
</p>
</div>
<div class="col-md-2">
<p>
<input class="btn btn-xs btn-success" type="button" value="Add New Attendance" onclick=" location.href = '@Url.Action("Create", "Attendances", new {enrollments_Attendance = item.Enrollments_Attendance}, null)' "/>
</p>
</div>
<div class="col-md-1">
<p>
<input class="btn btn-xs btn-danger" type="button" value="Delete" onclick=" location.href='@Url.Action("Delete", "Attendances", new {id = item.Id}, null)' " />
</p>
</div>
</div>
}
</div>
ASKER
Thanks for looking.
The complete View:
The complete View:
@model IEnumerable<SlamJammersData.Model.Attendances>
@{
ViewBag.Title = "Rosters";
}
<div class="container container-fluid">
<div class="panel panel-info">
<div class="panel-body">
<div class="container">
@using (Html.BeginForm("Index", "Attendances", FormMethod.Get))
{
<div class="row">
<div class="col-md-4">
<p>
<h3>Attendances for player: @Html.DisplayNameFor(model => model.FullName) </h3>
</p>
</div>
<div class="col-md-4">
<p>
<h4>Attendances Recorded: @Model.Count() </h4>
</p>
</div>
</div>
}
</div>
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="col-md-2">
<p>
@Html.DisplayNameFor(model => model.Type)
</p>
</div>
<div class="col-md-2">
<p>
@Html.DisplayNameFor(model => model.AttendanceDate)
</p>
</div>
<div class="col-md-2">
<p>
@Html.DisplayNameFor(model => model.Comments)
</p>
</div>
</div>
@foreach (var item in Model)
{
<div class="row table-striped">
<div class="col-md-2">
<p>
@Html.DisplayFor(modelItem => item.Type)
</p>
</div>
<div class="col-md-2">
<p>
@Html.DisplayFor(modelItem => item.AttendanceDate)
</p>
</div>
<div class="col-md-2">
<p>
@Html.DisplayFor(modelItem => item.Comments)
</p>
</div>
<div class="col-md-1">
<p>
<input class="btn btn-xs btn-info" type="button" value="Details" onclick=" location.href = '@Url.Action("Details", "Attendances", new {id = item.Id}, null)' "/>
</p>
</div>
<div class="col-md-1">
<p>
<input class="btn btn-xs btn-info" type="button" value="Edit" onclick=" location.href = '@Url.Action("Edit", "Attendances", new {id = item.Id}, null)' "/>
</p>
</div>
<div class="col-md-2">
<p>
<input class="btn btn-xs btn-success" type="button" value="Add New Attendance" onclick=" location.href = '@Url.Action("Create", "Attendances", new {enrollments_Attendance = item.Enrollments_Attendance}, null)' "/>
</p>
</div>
<div class="col-md-1">
<p>
<input class="btn btn-xs btn-danger" type="button" value="Delete" onclick=" location.href='@Url.Action("Delete", "Attendances", new {id = item.Id}, null)' " />
</p>
</div>
</div>
}
</div>
The view is referring to a list (@model IEnumerable<SlamJammersDat a.Model.At tendances> ).
Thus, this view needs to display the list of "Attendances" instances first with edit/details button in each entry and then you need to create a another controller actions (Details, Edit) and view to edit/display the selected "Attendances" instances. You can not display an instance in this view because there is no Id to identify which specific instance of the list you are looking for.
My recommendation will be to let ASP.NET MVC 5 generates the controllers and views for you, just delete your current controller and associated views and follow the example in this MVC5 link that shows how to create the Index view and what is scaffolded by VS2013. You will see that it creates the index page as well as your edit, details and delete actions and associated views. You can always change the generated code later on to introduce in the Index method a filtering parameter. ( I assume you have a home page that will specify the filtering parameter)
Note: If you need to display a specific item then please change the return action and the view model to target an specific instance. For example
Controller: //Assumption you need to return the first instance.
return View(attendances[0]);
View:
@model SlamJammersData.Model.Atte ndances
Thus, this view needs to display the list of "Attendances" instances first with edit/details button in each entry and then you need to create a another controller actions (Details, Edit) and view to edit/display the selected "Attendances" instances. You can not display an instance in this view because there is no Id to identify which specific instance of the list you are looking for.
My recommendation will be to let ASP.NET MVC 5 generates the controllers and views for you, just delete your current controller and associated views and follow the example in this MVC5 link that shows how to create the Index view and what is scaffolded by VS2013. You will see that it creates the index page as well as your edit, details and delete actions and associated views. You can always change the generated code later on to introduce in the Index method a filtering parameter. ( I assume you have a home page that will specify the filtering parameter)
Note: If you need to display a specific item then please change the return action and the view model to target an specific instance. For example
Controller: //Assumption you need to return the first instance.
return View(attendances[0]);
View:
@model SlamJammersData.Model.Atte
ASKER
Hi Miguel.
The list you are looking at is for a specific student whose id is passed from a roster (enrollments) list. Here's the story as it stands now:
First step is to get a session of locations to view roster attendances from:
Then a session is selected and the list of locations are presented:
From the locations we select the roster we want in order to get the enrollments:
If we look at the details of the enrollment, we can see the Ids of the enrollment instance and its foreign key (player id):
If we click on the Attendances link we get the list of attendances for this individual on the attendance index page:
When we look at the debugger to see what is being collected we can see the FullName's data.
You can not display an instance in this view because there is no Id to identify which specific instance of the list you are looking for.
The list you are looking at is for a specific student whose id is passed from a roster (enrollments) list. Here's the story as it stands now:
First step is to get a session of locations to view roster attendances from:
Then a session is selected and the list of locations are presented:
From the locations we select the roster we want in order to get the enrollments:
If we look at the details of the enrollment, we can see the Ids of the enrollment instance and its foreign key (player id):
If we click on the Attendances link we get the list of attendances for this individual on the attendance index page:
When we look at the debugger to see what is being collected we can see the FullName's data.
Ok, all attendances are related to just one player.
If that is the case my first post suggestion is correct, just replace:
Basically you need to access the first element of the list([0]). FullName is not property of the current model.
If that is the case my first post suggestion is correct, just replace:
<h3>Attendances for player: @Html.DisplayNameFor(model => model.FullName) </h3>
with:<h3>Attendances for player: @Html.DisplayNameFor(model => model[0].FullName) </h3>
Basically you need to access the first element of the list([0]). FullName is not property of the current model.
My bad (a typo) the code should be:
<h3>Attendances for player: @Html.DisplayFor(model => model.FullName) </h3>
Note: DisplayNameFor display the property name, not the value.
ASKER
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
ASKER
I've requested that this question be closed as follows:
Accepted answer: 0 points for wdarnellg's comment #a40713239
for the following reason:
I also posted this question on ASP.NET forums and it was suggested to use the First() on the Model. That gave me the list of properties to select the FullName from and the it displayed properly.
Accepted answer: 0 points for wdarnellg's comment #a40713239
for the following reason:
I also posted this question on ASP.NET forums and it was suggested to use the First() on the Model. That gave me the list of properties to select the FullName from and the it displayed properly.
Both answers (mine and wdarnellg) are equivalent, first method returns the first element of the enumeration, thus my answer is correct as well.
I am OK if you decide to delete the question.
I am OK if you decide to delete the question.
ASKER
Miguel is correct. His solution works the same. As his was posted first, and before I actually tested it, I think he earned the points.
Thank you.
Thank you.
ASKER
Follow Up...
Not sure if I should ask this as a different question, but I just discovered that if there are no records to get from the database, such as a new player being added to the roster, there is an out of index error thrown for the ElementAt() or a similar error thrown for the First() functions. Is there a way to get the display to just show attendance count as 0? Or do I need to do something like catch the error and show a friendlier message? If the latter, are there any suggestions as to how to show such a message?
Not sure if I should ask this as a different question, but I just discovered that if there are no records to get from the database, such as a new player being added to the roster, there is an out of index error thrown for the ElementAt() or a similar error thrown for the First() functions. Is there a way to get the display to just show attendance count as 0? Or do I need to do something like catch the error and show a friendlier message? If the latter, are there any suggestions as to how to show such a message?
Uhmm, is there any way you can put the full name in the view bag before calling attendance view? (On the details controller page)
I am assuming that if you have the player id you have access to the full name details, then you put full name in the view bag and display the view bag contents in the attendance view.
I know it is going to change to your initial design, but it will deal with this scenario and this question original scenario.
If you need further info then you need to ask a new question, post the action method that calls attendance view as well as how to get full name form player details.
I am assuming that if you have the player id you have access to the full name details, then you put full name in the view bag and display the view bag contents in the attendance view.
I know it is going to change to your initial design, but it will deal with this scenario and this question original scenario.
If you need further info then you need to ask a new question, post the action method that calls attendance view as well as how to get full name form player details.
ASKER
Thanks. I am going to play with it, and ask a new question if I can't make ViewBag make sense.
ASKER
Ok, I used the viewbag to display a friendlier message. I put the fullname line in a try catch and it works as expected now.
Thanks again Miguel!
public ActionResult Index(int? Id)
{
//Get the rosters and their attendance records
IQueryable<Attendances> attendances = db.Attendances
.Where(a => a.Enrollments_Attendance == Id)
.Include(e => e.Enrollments.Individuals)
.OrderByDescending(a => a.AttendanceDate);
ViewBag.EnrollmentId = Id;
try
{
ViewBag.FullName = attendances.First().FullName;
}
catch (InvalidOperationException ex)
{
ViewBag.Exception = ex;
ViewBag.FullName = "No Attendances to display for the selected player";
}
return View(attendances.ToList());
}
Thanks again Miguel!
Your controller is returning a list. The list itself does not seem to contain FullName property, thus this property value can not be displayed,
Note: Assuming that the model is a list then you should access the first element full name by providing an index as shown below:
Open in new window