I'm trying to render different partial views from the _Layout file depending on what function I'm in, controller-wise.
The partial view is in the right column of the website which is located in the _Layout like so:
<aside id="right">
#Html.Partial("RightPartial")
</aside>
What I want to do is render a different partial view depending on where I am.
If I'm in the Index view I might want to view news and in the About view I might want to view phone numbers or something.
Appreciate any help :)
#{
string currentAction = ViewContext.RouteData.GetRequiredString("action");
string currentController = ViewContext.RouteData.GetRequiredString("controller");
}
Now based on the values of those variables decide which partial to render. To avoid polluting the Layout I would write a custom HTML helper:
<aside id="right">
#Html.RightPartial()
</aside>
which might look like this:
public static class HtmlExtensions
{
public static IHtmlString RightPartial(this HtmlHelper html)
{
var routeData = html.ViewContext.RouteData;
string currentAction = routeData.GetRequiredString("action");
if (currentAction == "Index")
{
return html.Partial("IndexPartialView");
}
else if (currentAction == "About")
{
return html.Partial("AboutPartialView");
}
return html.Partial("SomeDefaultPartialView");
}
}
Related
I have a main Index view from which I call view called Create, into which I pass type of the widget I want to create as a string.
Index view:
<i class="fa fa-image"></i> Create Image Widget -
<i class="fa fa-file-text"></i> Create Text Widget
Create Action:
public ActionResult Create(string wType)
{
ViewBag.wType = wType;
return View();
}
the type is then passed into view via ViewBag.wType and this is evaluated in the Create View
Create view:
#using (Html.BeginForm())
{
<section class="row">
#{
if (ViewBag.wType == "image")
{
Html.RenderPartial("~/Views/WidgetEditor/_CreateImageWidget.cshtml");
}
else if (ViewBag.wType == "text")
{
Html.RenderPartial("~/Views/WidgetEditor/_CreateTextWidget.cshtml");
}
}
</section>
}
and depending on this, appropriate partial view is loaded.
Partial views have different models so when the form is submitted, I do not know how which model is passed back. The one from _CreateImageWidget or _CreateTextWidget.
If the HttpPost controller look like this
[HttpPost]
public ActionResult Create(DisplayWidgetImageViewModel imageModel, DisplayWidgetTextViewModel textModel)
{
return new ViewResult();
}
I will get populated imageModel if _CreateImageWidget partial is chosen and textMode if _CreateTextWidget partial is chosen.
This is acceptable it the number of widgets types does not change, but this is not the case.
Is there a way to get somehow specific model from a partial view and know/find out which one it is or am I doing this completely wrong way?
You can create multiple forms in single page. You can also use different action methods per partial:
#using (Html.BeginForm("Action", "Controller")) {
Html.RenderPartial("~/Views/WidgetEditor/_CreateImageWidget.cshtml")
}
You all this without having to use Ajax.
I have used this answer to solve my problem: determine-the-model-of-a-partial-view-from-the-controller-within-mvc
there are also several other link with more resources.
I have one controller which will pass data to view Index.cshtml
public ActionResult Index()
{
var empId = #User.Identity.Name;
var empDetails = empRepository.GetEmployeeDetails(empId);
var emp = new UserViewModel {EmployeeDetail = empDetails};
return View(emp);
}
Layout of view Index.cshtml is Partialview _Layout.cshtml
#model HRM.Areas.EmployeeDetails.Models.UserViewModel
#{
ViewBag.Title = "Index";
Layout = "~/Areas/EmployeeDetails/Views/Shared/_Layout.cshtml";
}
<div>Hello</div>
I want to access the data which I passed from controller action to Index.cshtml in _Layout.cshtml.
Is there any way to do this ?
Your question is not clear on how you want to access the values so i'm making an assumption here:
If you want to include data from a view in a rendering from your layout page you can use the RenderSection method.
Layout Page:
#RenderSection("ViewSection", false)
View Page:
#section ViewSection {
<div>
<label>Emp Name:</label>
#model.EmpDetails.Name
</div>
}
When your Layout is rendered it'll look for a section in your view that matches and render it. Passing a false as the 2nd param tell the Layout that the section is not required.
For more info on this: http://weblogs.asp.net/scottgu/archive/2010/12/30/asp-net-mvc-3-layouts-and-sections-with-razor.aspx
Your question is not quite clear to me:/
My assumption ->
If you change your code to look like this:
public ActionResult Index()
{
var empId = #User.Identity.Name;
var empDetails = empRepository.GetEmployeeDetails(empId);
var emp = new UserViewModel { EmployeeDetail = empDetails };
ViewBag.UserViewModel = emp;
return View(emp);
}
on the Layout page you can access your data:
#if (ViewBag.UserViewModel != null)
{
//do sth with ViewBag.UserViewModel here
//for example:
#Html.Partial("_UserView",ViewBag.UserViewModel)
}
If you explain in details what you want to achive it will be easier for us to give you the right answer.
You can access the data in the model like this:
#Model.EmployeeDetail ...
I want to create a layout like the User page on Stack Overflow where there is a view (the parent view) at the top of the page and then content in tabs, each with it's own view (child views).
When I hover over each of the tabs on the User page in SO it looks like they are pointed at the user controller and are being sent the tab name in the query string to render the appropriate tab content.
I believe I can achieve this using a layout with a section defined in the parent view. The section would be the child view, but I don't know how I would tell the section which view or partial view to show.
I have not been able to find anything useful on the web. Can someone tell me how to do this or at least point me in the right direction?
Thanks in advance!
Edit: Thanks to #Mystere's help I was able to come up with the solution below in case anyone else is trying to do the same thing.
HTH
Final Solution:
Controller Actions
public ActionResult Details(int id, string tab = null)
{
ViewBag.Jobid = id;
ViewBag.Tab = tab ?? "Services";
var viewModel = getJobRecordDetails(id);
return View(viewModel);
}
public ActionResult JobInfo(int id, string tab)
{
ViewBag.Jobid = id;
ViewBag.Tab = tab;
if (tab == "Services")
{
var viewModel = getServices(id);
return View("Services", viewModel);
}
if (tab == "Equipment")
{
var viewModel = getEquipment(id);
return View("Equipment", viewModel);
}
if (tab == "Personnel")
{
var viewModel = getPersonnel(id);
return View("Personnel", viewModel);
}
return View("Error");
}
Parent View
#model MyApplication.Models.JobViewModel
#{
ViewBag.Title = "Details";
}
<h2>Job Details</h2>
...
#* Child View Action *#
#Html.Action("JobInfo", new { id = ViewBag.Jobid, tab = ViewBag.Tab })
Child View
#model MyApplication.Models.ServicesViewModel[]
#{
ViewBag.Title = "Services";
Layout = null;
}
#* Submenu Navigation *#
#{
Html.RenderPartial("SubMenu");
}
<h2>Services</h2>
Services here...
Subnavigation Partial View
<div id="submenucontainer">
<ul id="submenu">
<li class="#Html.ActiveTab("Job","JobInfo","Services")">Services </li>
<li class="#Html.ActiveTab("Job","JobInfo","Equipment")">Equipment</li>
<li class="#Html.ActiveTab("Job","JobInfo","Personnel")">Personnel</li>
</ul>
ActiveTab Helper
public static string ActiveTab(this HtmlHelper helper, string controller, string action, string tab)
{
var classValue = "";
var currentController =
helper.ViewContext.Controller.ValueProvider.GetValue("controller").RawValue.ToString();
var currentAction =
helper.ViewContext.Controller.ValueProvider.GetValue("action").RawValue.ToString();
var currentTab = helper.ViewContext.Controller.ValueProvider.GetValue("tab").RawValue.ToString();
if (currentController == controller && currentAction == action && currentTab == tab)
classValue = "selected";
return classValue;
}
It is unlikely they are using a section for that. sections are used primarily in layout pages (the equivelent of master pages).
More than likely, they just have multiple views, and they pass whichever view is appropriate to the View() method. They might use partial views, or MVC templates to render the tab areas, so that common code is factored out.
Edit:
As requested, code sample:
In action method:
public ActionResult Dashboard(string tab) {
if (tab == "summary")
ViewBag.Tab = "~/Views/Dashboard/Summary.cshtml";
if (tab == "activity")
ViewBag.Tab = "~/Views/Dashboard/Activity.cshtml";
return View()
}
in Dashboard.cshmtl
... your parent view
#Html.Partial(ViewBag.Tab)
... your footer
It's not rocket science. There are so many ways to do this it doesn't take much thought to come up with one of them.
I have an MVC3 application that I am implementing pjax into . Everything is working well except what to do on the server side when an address gets loaded that doesn't already have the main view on the client side. My Controller code looks like
public virtual ActionResult Details(Guid id)
{
var partDetail = new PartDetail(id);
var partialView = PartialView("Details", partDetail);
if(Request.Headers["X-PJAX"]!= null)
{
return partialView;
}
var mainView = View("Index");
// Stick Partial View into main view at #update_panel?
return mainView;
}
How can I stick the partial View into the main view so it inserts the partial view in the #update_panel?
Ok, without a major refactor, you could do the following.
(this assumes that you are able to set the #model on index.cshtml to PartDetail()).
in your controller action above, change:
var mainView = View("Index");
to:
var mainView = View("Index", partDetail);
then, inside your index.cshtml, add the following:
<div id="update_panel">#RenderPartial("Details", Model)</div>
As i said, this will ONLY work if the index #model is set to PartDetail(), otherwise, a little refactoring on the model in the index view will be required to include this PartDetail() model. this viewmodel might well look like the following:
public class IndexViewModel
{
ModelForIndex Index{get; set;}
PartDetail Details{get; set;}
}
this refactored viewmodel would be added to the index.cshtml as #model IndexViewModel and consumed by the partial as:
<div id="update_panel">#RenderPartial("Details", Model.Details)</div>
hope this makes sense.
I've got a view that displays a list of items. Rather than display items in a grid, I'd like to display 4 items per page, each with an image and multiple properties, displayed in a unique layout.
So, I'd like a foreach to iterate through the items, and each item to get displayed in a div. I could put all the code in the loop, but I'd like to have a custom html helper extension to do this.
I came up with this,
public static MvcHtmlString DisplayViewerFor(this HtmlHelper helper, TestModel model, bool rightAligned = true) {
if (model == null) {
model = new TestModel();
}
var outterDiv = new TagBuilder("div");
outterDiv.AddCssClass(rightAligned ? "item-display-right" : "item-display");
var image = new TagBuilder("image");
image.Attributes.Add("src", "Item/GetImage/" + model.ItemName);
image.Attributes.Add("height", "150");
var editorLabel = new TagBuilder("div");
editorLabel.AddCssClass("editor-label");
//LOOKING TO ADD CODE LIKE THIS HERE
var labelContent= html.LabelFor({my model property here})
editorLabel.InnerHtml += labelContent;
//END OF ADD
return new MvcHtmlString(outterDiv.ToString(TagRenderMode.EndTag));
}
In my method above, I need to display a few more values, and I would like to use the Html.LabelFor and Html.DisplayFor helpers, but the methods aren't available and I'm not sure what to pass to them if they were.
I'm not sure if this is possible or not, but I thought I would ask.
EDIT
I'm trying to use the html.LabelFor. See my code where I have updated it above, adding to it these two lines.
var labelContent= html.LabelFor({my model property here})
editorLabel.InnerHtml += labelContent;
You can see the code above.
EDIT 2
Here is the planned use for this Helper with dummied down view.
#model TestItemDisplayList
#{
ViewBag.Title = "Items";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#foreach(var item in #model.Items){
#Html.DisplayViewerFor(item)
}
You can use the Html.DisplayFor method to render a DisplayTemplate. One of the over loads for the method is to specify a template to use. You can modify your page code to read:
Page:
#model TestItemDisplayList
#{ ViewBag.Title = "Items"; Layout = "~/Views/Shared/_Layout.cshtml"; }
#Html.DisplayFor(model => Model,"TestItemDisplayList")
Display Template for TestItemDisplayList
#model TestItemDisplayList
#* You could limit this loop to the first 4 items *#
#foreach(var item in model.Items){ #Html.DisplayFor(item => item) }
Display Template for TestModel
#model TestModel
<div class="item-display">
<img src="#Url.Action("GetImage", "Image", new { id = Model.ItemName})" height="150"/>
<div class="editor-label">#Html.LabelFor(model => model.PropertyHere)</div>
</div>
I assume that your URL for the image used the default route of {controller}/{action}/{id} so I used the Url.Action and specified your ID.
You could also get away witout using a DisplayTemplate for "TestItemDisplayList" and moving that code in to your page but I wasn't clear if you wanted to add logic in that to limit the number of pages.