9

One problem with partial views and MVC, is that if your reusable partial view requires certain javascript, there was no way to include it and have it loaded at the bottom of the page in the scripts section. Beyond just the performance issue, it means that things necessary like jquery are not yet present and you have to use funky deferred execution of any jquery dependent code.

The solution to this problem would be to allow sections in partials, such that the partial can register it's scripts to appear in the correct location of the Layout.

Supposedly, MVC4's Optimization/bundling features are supposed to solve this problem. However, when I call @Scripts.Render in a partial, it includes them wherever the partial is. It doesn't do any kind of magic to place the scripts at the end of the page.

Here see Erik Porter's comment: http://aspnet.uservoice.com/forums/41199-general-asp-net/suggestions/2351628-support-section-render-in-partialviews

A few other places I've seen people saying MVC 4 solves this problem, but no examples as to how.

How do I include scripts needed by a partial at the end of the body after other scripts, using MVC4 Optimizations to solve the problem?

2
  • Scripts don't belong in partial views. Use the parent views for your scripts. Commented Mar 3, 2014 at 20:55
  • @MatijaGrcic Even if you externalize the scripts, you still have the same challenge. I wouldn't want to clutter the parent views with a bunch of bootstrap code for the partials, and then repeat that for every "parent" where you reuse that partial. Commented Mar 5, 2014 at 8:40

1 Answer 1

3

One thing you can do is create some HtmlHelper extension methods like the following:

using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Optimization;

public static class ScriptBundleManager
{
    private const string Key = "__ScriptBundleManager__";

    /// <summary>
    /// Call this method from your partials and register your script bundle.
    /// </summary>
    public static void Register(this HtmlHelper htmlHelper, string scriptBundleName)
    {
        //using a HashSet to avoid duplicate scripts.
        HashSet<string> set = htmlHelper.ViewContext.HttpContext.Items[Key] as HashSet<string>;
        if (set == null)
        {
            set = new HashSet<string>();
            htmlHelper.ViewContext.HttpContext.Items[Key] = set;
        }

        if (!set.Contains(scriptBundleName))
            set.Add(scriptBundleName);
    }

    /// <summary>
    /// In the bottom of your HTML document, most likely in the Layout file call this method.
    /// </summary>
    public static IHtmlString RenderScripts(this HtmlHelper htmlHelper)
    {
        HashSet<string> set = htmlHelper.ViewContext.HttpContext.Items[Key] as HashSet<string>;
        if (set != null)
            return Scripts.Render(set.ToArray());
        return MvcHtmlString.Empty;
    }
}

From your partials you would use it like this:

@{Html.Register("~/bundles/script1.js");}

And in your Layout file:

   ...
   @Html.RenderScripts()
</body>

Since your partials run before the end of the layout file all the script bundles will be registered and they will be safely rendered.

Sign up to request clarification or add additional context in comments.

1 Comment

did you mean : @{Html.Register("~/bundles/script1.js");} to actually load the file name OR @{Html.Register("~/bundles/scriptbundle");} to load a buddle set up in BundleConfig.cs as implied by your ~/bundles... notation Let me know - thanks

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.