0
votes

In my _Layout.cshtml I want to include a dropdown list in the site header. I'm not positive of the best way to do this, but I've tried to code it using a PartialView. It seems to be working, but when the form is submitted the page loads with only the dropdownlist.

ViewModel:

namespace XXXX_Web_App.Models
{
    public class LanguageListPartial
    {
        [DataType(DataType.Text)]
        [Display(Name = "Language")]
        public string Language { get; set; }
    }
}

Controller:

[AllowAnonymous]
[ChildActionOnly]
public ActionResult LanguageList()
{
    ViewBag.LanguageList = GetLanguageList();

    return PartialView("_LanguageListPartial");
}

[AllowAnonymous]
[HttpPost]
public async Task<ActionResult> LanguageList(string language)
{
    // Save selection to cookie
    HttpCookie cookie = new HttpCookie("UserSettings");
    cookie["Language"] = language;
    cookie.Expires = DateTime.Now.AddDays(-1);
    Response.Cookies.Add(cookie);

    // Save selection to user profile
    if (User.Identity.IsAuthenticated)
    {
        String userId = User.Identity.GetUserId();
        ApplicationUser user = await UserManager.FindByIdAsync(userId);
        user.Language = language;
        await UserManager.UpdateAsync(user);
    }

    ViewBag.LanguageList = GetLanguageList();

    return PartialView("_LanguageListPartial");
}

public List<SelectListItem> GetLanguageList()
{
    List<SelectListItem> languages = new List<SelectListItem>();
    languages.Add(new SelectListItem { Text = "English", Value = "en-US" });
    languages.Add(new SelectListItem { Text = "Fran&#231;ais", Value = "fr-CA" });
    languages.Add(new SelectListItem { Text = "Portugu&#234;s", Value = "pt-BR" });
    languages.Add(new SelectListItem { Text = "Espa&#241;ol", Value = "es-MX" });
    return languages;
}

Partial View:

@model XXXX_Web_App.Models.LanguageListPartial

@Html.DropDownListFor(
    x => x.Language,
    new SelectList(ViewBag.LanguageList, "Value", "Text"), 
    new { @class = "form-control toggle", onchange = "this.form.submit();"
})

_Layout.cshtml:

@using Westwind.Globalization;
@using Westwind.Globalization.Resources;

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>@ViewBag.Title</title>

    @Styles.Render("~/Content/css")
    @Scripts.Render("~/bundles/modernizr") 
    @Scripts.Render("~/bundles/jquery")
    @Scripts.Render("~/bundles/jqueryUI")
    @Scripts.Render("~/bundles/bootstrap")
    @RenderSection("scripts", required: false)


  <script src="/Scripts/jquery.cookie.js"></script>

</head>
<body>

<div style="">

    <div class="header container">

         ... nav menu ...

    </div>

    <form action="/Account/LanguageList" method="post" >
        @{Html.RenderAction("LanguageList", "Account");}
    </form>

    <div class="container">
        <div class="row">
            <div class="col-md-12">
                @RenderBody()
            </div>
        </div>
    </div>

    <footer class="container">
        <hr />
        <p>&copy; @DateTime.Now.Year</p>
    </footer>

</div>

</body>
</html>

The desired logic is:

Every site/page visit

  • Anonymous user - load selection from cookie. Default to English. (not done yet)
  • Authenticated user - load selection from user profile (not done yet)

On selection

  • Anonymous user - save selection to cookie
  • Authenticated user - save selection to cookie and update user profile

Like I said, this seems to be working except that when a selection is made the Controller action gets called and when the page reloads the only thing on the page is the dropdown list.

How do I return the View in this situation?

One other question, I would like the text in the dropdown list items to include the culture specific decorations, but they are displaying literally like Fran&#231;ais instead. I don't see how I can use Html.Encode() in this situation. It's probably being caused by the way I am adding the items in GetLanguageList(). How do I avoid this?

EDIT

To clarify, my excerpt from _Layout.cshtml above is just that - an excerpt. My _Layout.cshtml contains what you might expect of it - a header with logo and subtitle, navigation menu, and RenderBody() code. The page displays properly on the Partial View's GET Controller Action, but when I make a selection from the dropdown list the POST Controller Action only the dropdown list is displayed on the page - nothing else. _Layout.cshtml is gone and so are the contents of whatever page I am on.

1

1 Answers

1
votes

When you submit the form the /Account/LanguageList action is called. It returns with only a partial view:

return PartialView("_LanguageListPartial");

When you return just this, your _layout file is not called.

So what you want is to return another view. Unless you specify it, all your views will contain your _layout.cshtml file. And that already contains the partial view.

So create a new view and return that when you post to the form.