Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does MVC4 optimization allow partial view scripts?

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?

like image 544
AaronLS Avatar asked Jan 24 '13 00:01

AaronLS


1 Answers

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.

like image 162
epignosisx Avatar answered Jan 07 '23 11:01

epignosisx