Reputation: 160
I'm working on the design for a web application. The application was not originally coded by me, and I'm trying my best not to modify any controllers or models while I work on the design.
At the moment, the application is a header that is supposed to display the name of the project you are currently looking at, and the project's completion date. This header is a partial view that is called by the layout, also a partial view. Because the header is a separate view then the Project Details View, I am having a really hard time pulling this information out.
I have tried adding an @model reference to the controller to Header, but got an error that I was passing in the wrong type (see error below).
I have also tried to pass the model into the @Html.Partial call within the Layout view that calls to the header (also this). Generally everything I have tried gets me this error:
The model item passed into the dictionary is of type 'System.Collections.Generic.List`1[OST.Pride.Business.Models.Project]', but this dictionary requires a model item of type 'OST.Pride.Web.Models.AdminProjectUserEdit'.
I can't just move the header to the Project Details view because the header is a part of the entire application's layout. I would appreciate anyone's help in this, I've been stuck on it for a while.
Header being called in layout
<header id="main-header">
@Html.Partial("LayoutTemplates/Header")
</header>
Header:
<div class="navbar" style="padding-top:15px;">
<div class="navbar-inner">
<div class="container" style="width:auto;">
<div class="project-navbar">
<h3><ul class="nav pull-left">Customer: TEST </ul></h3>
<h3><ul class="nav" style="padding-left:40%;">Project: //This is where the project name needs to be//</ul></h3>
<h3><ul class="nav pull-right" align="center">Project Completion Date: //Again, I need to pull the completion date here// </ul></h3>
</div>
</div>
</div>
</div>
Controller's Method
public ActionResult Details(int? projectid, int? ProjectID, int? projectuserid) // based on the project id, populates the view with the roles, project users, and the roles for the screen.
{
var model = new Models.AdminProjectUserEdit();
model.Project = storeDB.Projects.Find(ProjectID);
model.Users = storeDB.Users.ToList();
model.Surveys = storeDB.Surveys.Include("SurveyType").ToList();
model.ProjectUsers = storeDB.ProjectUsers.Include("Project").Include("User").Where(x => x.ProjectID == projectid).ToList();
return View(model);
}
Upvotes: 2
Views: 165
Reputation: 160
While Darin's answer was a really good one and may very well work better in a different situation, I decided to go with a suggestion from my supervisor and use ViewBag. Using this method means I don't need to pass a model into the header, which is a shared view.
Here is how I implemented this method into my code:
Header being called in Layout
<header id="main-header">
@Html.Partial("LayoutTemplates/Header")
</header>
Header
<div class="navbar" style="padding-top:15px;">
<div class="navbar-inner">
<div class="container" style="width:auto;" >
@if (@ViewBag.projectName == null)
{ /**do nothing**/ }
else
{
<div class="project-navbar">
<h3><ul class="nav pull-left">Customer: TEST </ul></h3>
<h3><ul class="nav" style="padding-left:40%;">Project: @ViewBag.projectName</ul></h3>
<h3><ul class="nav pull-right" align="center">Project Completion Date: @ViewBag.projectCompletion </ul></h3>
</div>
}
</div>
</div>
Controller's Method
public ActionResult Details(int? projectid, int? ProjectID, int? projectuserid) // based on the project id, populates the view with the roles, project users, and the roles for the screen.
{
var model = new Models.AdminProjectUserEdit();
model.Project = storeDB.Projects.Find(ProjectID);
model.Users = storeDB.Users.ToList();
model.Surveys = storeDB.Surveys.Include("SurveyType").ToList();
model.ProjectUsers = storeDB.ProjectUsers.Include("Project").Include("User").Where(x => x.ProjectID == projectid).ToList();
ViewBag.projectName = storeDB.Projects.Find(ProjectID).ProjectName;
ViewBag.projectCompletion = storeDB.Projects.Find(ProjectID).ProjectCompletion;
return View(model);
}
Upvotes: 1
Reputation: 1038820
There are few considerations here. Since you are putting this inside the Layout, this means that absolutely every view in your application will display the project details. But to display a project detail you must have a project first. And to have a project you must have a project id. Following this logic, this in turns means that you must have the project id everywhere for each request. This project id could be part of the request query string or the route. For the purpose of this demonstration I assume that it is part of the route data.
So you could use a child action to display the project details inside your Layout instead of a partial view:
<header id="main-header">
@Html.Action("Header", "SomeController", new { projectid = ViewContext.RouteData["projectid"] })
</header>
Notice how we are passing the projectId
parameter from the route data. You will obviously have to adapt this code if the project id is in the query string, or a cookie or wherever you have decided to persist it. The route seems like a good place.
So we invoke the Header
child action action of Some
controller which will fetch the project and pass it to the corresponding partial view:
[ChildAction]
public ActionResult Header(int? projectId)
{
if (projectId == null)
{
return PartialView();
}
var project = storeDB.Projects.Find(projectID);
return PartialView(project);
}
and then inside the corresponding Header.cshtml
partial view we render the project details:
@model Project
@if (Model == null)
{
// there wasn't any project selected => display some default stuff
<div>No project to display</div>
}
else
{
<div class="navbar" style="padding-top:15px;">
<div class="navbar-inner">
<div class="container" style="width:auto;">
<div class="project-navbar">
<h3>
<ul class="nav pull-left">
Customer: TEST
</ul>
</h3>
<h3>
<ul class="nav" style="padding-left:40%;">
Project:
@Html.DisplayFor(x => x.Name)
</ul>
</h3>
<h3>
<ul class="nav pull-right" align="center">
Project Completion Date:
@Html.DisplayFor(x => x.CompletionDate)
</ul>
</h3>
</div>
</div>
</div>
</div>
}
Upvotes: 3