0

I have one razor layout this layout spread across all my views.
Until today navigation menu was (separate controller) in this layout. But now this menu has dynamic data. And I can't keep it anymore in layout page.
So should I render this navigation menu in each view or there is some other way to make it only once and just pass data to it?

This is how I render navigation menu in razor layout:

@Html.Action("CommonMenu", "Navigation", new { area = "CityPage" })

In CommonMenu view I have home link:

<li> @Html.ActionLink("Home", "Index", "Home", new { area = "CityPage", city = ViewBag.City, countryCode = ViewBag.CountryCode }, null)

And I open one page with that menu. When I click home I expect to go to home of the city home (like UK, London).

But I can go from this page to some other city (like CH, Zurich).
And now I need to rebind whole navigation menu.
And I don't know can I do that if I render menu in razor layout?
Update
This is how I go from one city page to another:

@Html.ActionLink("Go To London", "Index", "Home", new { area = "CityPage", city = "London", countryCode = "UK" }, null)

When I click on this link mu 'CommonMenu' action is called:

[ChildActionOnly]
        public PartialViewResult CommonMenu(string countryCode, string city)
        {...

But from some reason this action is called a few times:
First time both values are null.
Second time values are UK,London.
Third time are null.
And this couse my page to break.

1110
  • 7,829
  • 55
  • 176
  • 334
  • What's the problem with this dynamic data? Why can't you leave it in the Layout? That's the best place for a menu that should be rendered on each view. – Darin Dimitrov Jan 15 '12 at 15:02
  • I really don't understand what the problem is. Why can't you use Html.Action? – Darin Dimitrov Jan 15 '12 at 16:06
  • I update question with more info. From some reason my menu action is called a few times and lat call return null values. – 1110 Jan 15 '12 at 16:13
  • you are saying that your child action is called multiple times but you are not showing the code where you are effectively calling this action (using Html.Action helper). So it will be a little difficult to help you under those circumstances. – Darin Dimitrov Jan 15 '12 at 16:25
  • I made a real mess now :( I remove Layout=".../MyRazorLayout.cshtml" from all views except one and now it is called just once. I call Html.Action just once in layout page "@Html.Action("CommonMenu", "Navigation", new { area = "CityPage" })" – 1110 Jan 15 '12 at 16:33
  • If you have Layout defined in your _ViewStart.cshtml file, you do not need it in each of your views. – danludwig Jan 15 '12 at 16:46

2 Answers2

1

You are on the right track using a child action for your layout navigation. However, instead of using viewbag, why not strongly-type it?

ViewModel:

public class CommonMenuLinkModel
{
    public string Text { get; set; }
    public string Area { get; set; }
    public string Controller { get; set; }
    public string Action { get; set; }
    public string City { get; set; }
    public string CountryCode { get; set; }
}

View:

@model IEnumerable<CommonMenuLinkModel>
<ul>
@foreach(var link in Model)
{
    <li>@Html.ActionLink(link.Text, link.Controller, link.Action, 
        new {area = link.Area, city = link.City, countryCode = link.CountryCode}, 
        null)</li>
}
</ul>

In your controller, rather than putting things in the ViewBag, put them in a strongly-typed collection of CommonMenuLinkModels, and pass that to the partial view.

Note: You would keep this as a child action called from your layout.

Update

I'd like to reiterate something I said in one of your questions that I previously answered. Using T4MVC, you could generate your action links like this:

<li>@Html.ActionLink(link.Text, 
    MVC.CityPage.Home.Index(link.CountryCode, link.City))</li>

Or even better, like this, so you can more clearly control the HTML:

<a href="@Url.Action(MVC.CityPage.Home.Index(link.CountryCode, link.City))">
    @link.Text</a>
Community
  • 1
  • 1
danludwig
  • 46,965
  • 25
  • 159
  • 237
  • I use viewbag just temporary I will change this. But my problem menu action is called few times. It's in my question last update. – 1110 Jan 15 '12 at 16:21
  • I can't tell by looking at your code why the action would be called multiple times. Could be because of route definitions. Have you considered using T4MVC to generate links instead of magic strings? http://stackoverflow.com/a/8810526/304832 – danludwig Jan 15 '12 at 16:27
0

You can use RenderAction in your layout. It will call an action from a controller and render it using the dynamic way you want:

@{ Html.RenderAction("Index", "NavigationMenu"); }

In this case, it will render the result of the action "Index" of the controller "NavigationMenu"

Ivo
  • 8,172
  • 5
  • 27
  • 42
  • Why use `@{ RenderAction("Index", "Navigation"); }` when you can just do `@Html.Action("Index", "Navigation")`? – danludwig Jan 15 '12 at 15:51
  • 1
    RenderAction renders directly to the response and Action returns the string. RenderAction is more efficient. – Ivo Jan 15 '12 at 15:59
  • http://stackoverflow.com/questions/2955261/difference-between-html-renderaction-and-html-action – Ivo Jan 16 '12 at 03:22