I need to set a banner image in my layout page dynamically based on a selected value. I have been researching but it seems that i cannot have a controller for the layout page, so i have been looking at using a partial view but i am missing something apparently. How can i accomplish this?
Layout Page
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>@ViewBag.Title - My ASP.NET Application</title>
@Styles.Render("~/Content/css")
@Scripts.Render("~/bundles/modernizr")
</head>
<body>
<div class="header">
<div>
@Html.Partial("_Header")
</div>
</div>
<div class="container body-content">
@RenderBody()
<hr />
<footer>
<p>© @DateTime.Now.Year - My ASP.NET Application</p>
</footer>
</div>
@Scripts.Render("~/bundles/jquery")
@Scripts.Render("~/bundles/bootstrap")
@RenderSection("scripts", required: false)
</body>
</html>
Partial view
@model TicketPaymentsAzureMVC.Models.Client
<h1>Header</h1>
<img src="@Url.Content(Model.BannerUrl)" alt="Image" />
Using @Html.Partial()
does not call a controller method and just renders the html defined in the partial. By default it passes the model from the main view to the partial (unless you specify it in the 2nd parameter), so unless the model in the main view is typeof TicketPaymentsAzureMVC.Models.Client
your code will throw an exception.
If you use a view model that contains a property Client Client
(and you populate that property in the GET method), then you could use
@Html.Partial("_Header", Model.Client)
to pass an instance of Client
to the partial. That would mean that every view using that layout would need that property.
A better option is to use @Html.Action()
or @{ Html.RenderAction(); }
to call a server method that returns the partial
[ChildActionOnly]
public ActionResult Header()
{
Client model = ... // initialize your model and set the `BannerUrl` property
return PartialView(_"Header", model);
}
and in the layout
@{ Html.RenderAction("Header", yourControllerName); }
All the options I can think of:
1) Share a model across all the actions that use that layout.
2) Use ViewBag. Link: https://msdn.microsoft.com/en-us/library/system.web.mvc.controllerbase.viewbag(v=vs.118).aspx
3) Use RenderAction (the layout doesn't depend on the actions that are executed). Link: https://msdn.microsoft.com/en-us/library/ee839451(v=vs.98).aspx
4) Making an AJAX call from a JS file that is referenced in the layout (the layout doesn't depend on the actions that are executed). Link: http://www.aspsnippets.com/Articles/ASPNet-MVC-jQuery-AJAX-and-JSON-Example.aspx
The way you are doing it you need to define a base class for the model with property BannerUrl. You could use ViewBag to avoid that but I don't like that solution either.
I would do this:
1) Create a JS file called layout.js. That file would make an AJAX call to the get the banner URL and set it.
2) In the layout, reference the JS file created in (1).
3) Any page that uses the layout doesn't need to do anything. The layout is handling it by itself so no dependency.