MVC define #section for all views in area - asp.net-mvc

I have a container in my layout where I'd like to display a list of menu items, and I'd like for additional menu items to be displayed based on which area of the site we are viewing.
I know that I could do this with a #section, but that means I would have to copypaste the section contents in every single view within the area, which would be a maintenance mess and a nasty violation of DRY. Multiple per-area layouts would also be undesirable code duplication.
It would be good to do it in the _ViewStart partial, but apparently MVC doesn't allow #sections to be defined in partials. What else can I do?

I would consider making an action method in some generic controller that returns the correct partial view with the proper menu items.
[ChildActionOnly]
public PartialViewResult GetSubMenu(){
var areaName = ViewContext.RouteData.DataTokens["area"];
switch(areaName){
case "Admin":
return PartialView("_adminSubMenu");
....
case default:
//not sure on how to return nothing exactly
return null;
}
}
In your layout
#{Html.RenderAction("GetSubMenu","GenericControllerName");}

Create a Controller and Action to cater for this, I generally use something like NavigationController with a MainMenu action or similar.
In your action:
public ActionResult MainMenu()
{
return PartialView();
}
The from any where on your site layouts or views you can use:
#{ Html.RenderAction("MainMenu", "Navigation"); }
This also means that you can include any business logic in your action and pass a model to your MainMenu, maybe for checking roles etc.
Very handy.

Related

mvc3 razor view from different controller

so in my profile controller page.
I have a method call create
inside the create method
if (Convert.ToInt32(calBMI) >= 25)
{
return View("Index", Survey);
}
I want to render the page to index of survey(survey is another controller take care of surveys), how do i do it to get it works,thanks!!
return View("~/Views/Survey/Index.cshtml", objSurvey);
Assuming objSurvey is your model/ViewModel object and Survey/index view is strongly typed to the type of objSurvey Model/ViewModel
EDIT : As per the comment, If your view is not strongly typed, you can ignore the second parameter
public ActionResult GetSomeThing()
{
return View("~/Views/Survey/Index.cshtml");
}
If your intention is to share this view among multiple controllers, it should be in the /Views/Shared/ folder. There is a lack of good reasoning to use a view outside of either the controller folder or the shared folder.
It seems to me that you can just redirect to list of surveys (if that's your intent).
return RedirectToAction("Index", "Survey");

What's the recommended pattern for handling control display logic in ASP.NET MVC?

I'm going through some of the MVC3 tutorials, namely the Pluralsight videos, and I'm thinking of how our existing application would function if it were overhauled to ASP.NET MVC (not the plan, but it gives me a frame of reference). We have quite a bit of code that looks something like this in our aspx code-behinds:
if (SomeBooleanCheck){SomeControl.Visible = true;}else {SomeControl.Visible = false;}
Granted that example is greatly simplified, but assuming the boolean logic is fairly complex and assuming multiple things need to happen as part of making the control visible (maybe changing color, size, text, etc.) what's the pattern for doing this in ASP.NET MVC? It seems like you'd have to do that same boolean checking in the view itself, which to me seems kind of ugly. Seems like there has to be a better way and this surely came up on MS's use case list, I'm just not seeing the answer.
The approach you may take will vary greatly depending on the specific scenario. A few options incude:
Doing as you say and adding the conditional in the view
Abstracting the conditional (if it is complex) into your view model so that the lines in the view are still simple (just accessing a preset boolean value on your view model).
Doing this conditional at the route or controller level and calling a different overall view (which may share a layout (razor) or master view (webforms mvc))
You don't mention explicitly how you would render the controls in the conditional. I assume you would be doing a RenderPartial. So the lines themselves in the view would be quite 'small'.
if(myViewModel.ComplexBoolean) // Boolean set in generation of view model
Html.RenderPartial('firstPartial')
else
Html.RenderPartial('secondPartial')
EDIT: If the item you are setting as 'visible' is simply a single control you may just output the control directly e.g.
if(myViewModel.ComplexBoolean) {
Html.DropDownListFor(m => m.Type, Model.Types /* An IEnumerable<SelectListItem>*/, new { #class = "myList" });
}
Additionally if you didn't want to set that 'Model.Types' property (to save a db hit for example) then the conditional could be in the location you create your view model (either the controller or some service/view model repo). The view could then just check for the properties existance instead:
if(Model.Types != null) {
Html.DropDownListFor(m => m.Type, Model.Types /* An IEnumerable<SelectListItem>*/, new { #class = "myList" });
}
If your controls does not use the data found in your View's ViewModel, you can also use Html.RenderAction to call Child Actions. For example, suppose you want to display a different menu to users with different roles. You can call #{Html.RenderAction("Menu", "Account");} in your View, which will call the "Menu" Action in your "Account" controller. Your complex Boolean logic and the logic to formulate your controllers’ settings will reside in the "Account" controller's "Menu" action. The "Menu" action will decide what Partial View/Controller to display.
// This goes in your View (clean single line!)
#{Html.RenderAction("Menu", "Account");}
// This goes in your controller
[ChildActionOnly]
public ActionResult Menu()
{
bool isAdmin = false;
// Your complex boolean logic goes here
// Set your controller settings here
string controllerSettings = ""; // Use class or array for multiple settings
if (isAdmin)
{
return PartialView("~/Views/Account/_AdminMenu.cshtml", controllerSettings);
}
else
{
return PartialView("~/Views/Account/_StandardMenu.cshtml", controllerSettings);
}
}

Can I share the same view for a create and edit in MVC3

I have a fairly complex view that's almost the same for the create and edit functionality in MVC3.
Every time I change one I have to remember to make the same changes in the other.
Is there a way that I can share a view between create and edit. For example can I have two view files with different names and link them or is there another even better way.
thanks
Marcel
You could simply make a partial view with your form contents and include this partial view in your create and edit view. With that, you you are able the have some differences in your views (maybe headline "edit" / "create").
#Html.Partial("FormView")
On the other side, you could specify your view in your controller action.
public ActionResult Create()
{
return View("CreateEditView");
}
public ActionResult Edit()
{
return View("CreateEditView");
}

ASP.NET MVC partial view that updates without controller

I have a partial view that shows a list of Categories. I'd like to put that partial view on any page, but I'd like to have it to call to the service and get a list of categories by itself without me having to do that in every controller action. Something like webforms in which you can put a code-behind on it.
For eg.
Actions
public ActionResult Index()
{
JobListViewModel model = new JobListViewModel();
model.Categories= jobService.GetCategories();
return View(model);
}
public ActionResult Details(int id)
{
Job job = jobService.GetJob(id);
return View(job);
}
I created a partial that will take the model.Categories model and display a list. As you can see, the Index page will work fine, but I do not want to call it again in the Details page. Is there a way to make my partialview call to the GetCategories() service by itself?
Use Html.RenderAction - that gives the partial view its own controller action.
You should also mark you partial action with the attribute [ChildActionOnly].
DVark,
As noted in the accepted answer, for your scenario, RenderAction is the most appropriate.
I thought I'd link a little article that distils my thinking on the topic (i.e. when to use RenderPartial vs RenderAction):
http://cbertolasio.wordpress.com/2010/09/21/mvc-html-renderaction-vs-html-renderpartial/
hope it helps
[edit] - as an aside. a year or so ago, i got myself into a few scrapes by not appreciating the power of RenderAction, in favour of RenderPartial. as a result, i had littered the shared view space with lots of partialviews in order to access them from a variety of sources. the moral of the story: know your 'territory' before planting your flag.

Disable layout in ASP.NET MVC?

In MonoRail you can just CancelLayout() to not render the layout. In ASP.NET MVC, the only way to affect the layout seems to be to pass the layout name into the View() method like View("myview", "mylayout"); only it seems that passing null or an empty string doesn't do what I'd want.
I ended up creating an empty layout that just rendered the content, but that seems silly.
"Not Render the layout" means exactly that. In the web forms view engine they call layouts "master pages". I want to render just my action's view and not surround it with the master page.
In MVC 3, you can remove the master layout code with:
#{
Layout = "";
}
At the beginning of view add this:
#{
Layout = null;
}
If you want style sheet to remain, you'll need to add reference to it in that view.
To disable this for all pages, edit the _ViewStart.cshtml (in the root, under the 'Views' folder), and ensure that it contains the following:
#{
Layout = null;
}
And to enable the template for any specific view, the following can be added to the .cshtml file for that view, to enable the template:
#{
Layout = "~/Views/Shared/_Layout.cshtml";
}
In the Controller action we can set the required layout.
return View("Index", "_LAYOUT_NAME", model);
https://stackoverflow.com/a/5161384/2039603
I see in the right answer it says that "It seems this was impossible in the version of ASP.NET MVC"
Which version are you using? Because I found the solution (I had the same issue) to your problem
So, to Disable Layout in the page, you should use:
#{
Layout = null;
}
And, as suggested here, this could solve your problem:
public ActionResult Index()
{
SampleModel model = new SampleModel();
//Any Logic
return View("Index", "_WebmasterLayout", model);
}
Instead of using a normal view, create a partial view. These can then be used on their own, which acts very much like CancelLayout() - or you can incorporate them into a view that references the Master Page, in which case it will be the full layout. They are also useful if you want to send back a partial HTML chunk in response to an AJAX request.
Not having any luck trying to set the masterPage parameter to "" or null and returning a View (like I didn't)?
Then try this and use PartialView instead:
public ActionResult Article(string id)
{
return PartialView("~/Areas/Store/Views/CustomerService/" + id);
}
I needed to do this to load the contents of a view asynchronously from JS.
It seems this was impossible in the version of ASP.NET MVC I was asking about.
You can create a custom ActionResult that does pretty much anything. The ActionResult controls what is sent back to the client as the response. It would be trivial to create a class that extends ActionResult that does nothing.
One alternative is to actually specify a layout but make that layout empty
"_EmptyLayout.cshtml" that contains nothing or just a comment that says it contains nothing so later someone sees it as intended.

Resources