web-dev-qa-db-fra.com

Injection de contenu dans des sections spécifiques à partir d'une vue partielle ASP.NET MVC 3 avec Razor View Engine

J'ai cette section définie dans mon _Layout.cshtml

@RenderSection("Scripts", false)

Je peux facilement l'utiliser depuis une vue: 

@section Scripts { 
    @*Stuff comes here*@
}

Ce qui me pose problème, c'est comment obtenir du contenu partiel dans cette section à partir d'une vue partielle.

Supposons que ceci est ma page de vue: 

@section Scripts { 

    <script>
        //code comes here
    </script>
}

<div>
    poo bar poo
</div>

<div>
  @Html.Partial("_myPartial")
</div>

Je dois injecter du contenu dans la section Scripts à partir de la vue partielle _myPartial.

Comment puis-je faire ceci?

293
tugberk

Les sections ne fonctionnent pas dans les vues partielles et cela est voulu. Vous pouvez utiliser certains assistants personnalisés pour obtenir un comportement similaire, mais honnêtement, il incombe à la vue d'inclure les scripts nécessaires, et non la responsabilité du partiel. Je vous recommande d'utiliser la section @scripts de la vue principale pour le faire sans vous soucier des partiels au sujet des scripts.

214
Darin Dimitrov

C'est une question assez populaire, alors je vais poster ma solution.
J'ai eu le même problème et bien que ce ne soit pas idéal, je pense que cela fonctionne plutôt bien et ne rend pas le partiel dépendant de la vue.
Mon scénario était qu’une action était accessible par elle-même mais pouvait également être intégrée dans une vue - une carte Google.

Dans mon _layout j'ai: 

@RenderSection("body_scripts", false)

Dans ma vue index, j'ai:

@Html.Partial("Clients")
@section body_scripts
{
    @Html.Partial("Clients_Scripts")
}

Dans ma vue clients j'ai (toute la carte et assoc. Html):

@section body_scripts
{
    @Html.Partial("Clients_Scripts")
}

Ma vue Clients_Scripts contient le javascript à afficher sur la page.

Ainsi, mon script est isolé et peut être restitué dans la page, le cas échéant, la balise body_scripts n'étant rendue que lors de la première occurrence détectée par le moteur de vue rasoir.

Cela me permet de tout séparer - c'est une solution qui fonctionne assez bien pour moi, d'autres peuvent avoir des problèmes avec cela, mais cela corrige le trou "by design".

78
dan richardson

Parmi les solutions de ce fil , j’ai proposé la solution suivante, probablement trop compliquée, qui vous permet de retarder le rendu du code HTML (également des scripts) dans un bloc using.

USAGE

Créer la "section"

  1. Scénario typique: Dans une vue partielle, incluez uniquement le bloc une fois, quel que soit le nombre de répétitions de la vue partielle dans la page:

    @using (Html.Delayed(isOnlyOne: "some unique name for this section")) {
        <script>
            someInlineScript();
        </script>
    }
    
  2. Dans une vue partielle, incluez le bloc pour chaque utilisation du partiel:

    @using (Html.Delayed()) {
        <b>show me multiple times, @Model.Whatever</b>
    }
    
  3. Dans une vue partielle, incluez le bloc une seule fois, quel que soit le nombre de fois que le partiel est répété. Rendez-le ensuite plus précisément avec le nom when-i-call-you:

    @using (Html.Delayed("when-i-call-you", isOnlyOne: "different unique name")) {
        <b>show me once by name</b>
        <span>@Model.First().Value</span>
    }
    

Rendre les "sections"

(c'est-à-dire afficher la section retardée dans une vue parent)

@Html.RenderDelayed(); // writes unnamed sections (#1 and #2, excluding #3)
@Html.RenderDelayed("when-i-call-you", false); // writes the specified block, and ignore the `isOnlyOne` setting so we can dump it again
@Html.RenderDelayed("when-i-call-you"); // render the specified block by name
@Html.RenderDelayed("when-i-call-you"); // since it was "popped" in the last call, won't render anything due to `isOnlyOne` provided in `Html.Delayed`

CODE

public static class HtmlRenderExtensions {

    /// <summary>
    /// Delegate script/resource/etc injection until the end of the page
    /// <para>@via https://stackoverflow.com/a/14127332/1037948 and http://jadnb.wordpress.com/2011/02/16/rendering-scripts-from-partial-views-at-the-end-in-mvc/ </para>
    /// </summary>
    private class DelayedInjectionBlock : IDisposable {
        /// <summary>
        /// Unique internal storage key
        /// </summary>
        private const string CACHE_KEY = "DCCF8C78-2E36-4567-B0CF-FE052ACCE309"; // "DelayedInjectionBlocks";

        /// <summary>
        /// Internal storage identifier for remembering unique/isOnlyOne items
        /// </summary>
        private const string UNIQUE_IDENTIFIER_KEY = CACHE_KEY;

        /// <summary>
        /// What to use as internal storage identifier if no identifier provided (since we can't use null as key)
        /// </summary>
        private const string EMPTY_IDENTIFIER = "";

        /// <summary>
        /// Retrieve a context-aware list of cached output delegates from the given helper; uses the helper's context rather than singleton HttpContext.Current.Items
        /// </summary>
        /// <param name="helper">the helper from which we use the context</param>
        /// <param name="identifier">optional unique sub-identifier for a given injection block</param>
        /// <returns>list of delayed-execution callbacks to render internal content</returns>
        public static Queue<string> GetQueue(HtmlHelper helper, string identifier = null) {
            return _GetOrSet(helper, new Queue<string>(), identifier ?? EMPTY_IDENTIFIER);
        }

        /// <summary>
        /// Retrieve a context-aware list of cached output delegates from the given helper; uses the helper's context rather than singleton HttpContext.Current.Items
        /// </summary>
        /// <param name="helper">the helper from which we use the context</param>
        /// <param name="defaultValue">the default value to return if the cached item isn't found or isn't the expected type; can also be used to set with an arbitrary value</param>
        /// <param name="identifier">optional unique sub-identifier for a given injection block</param>
        /// <returns>list of delayed-execution callbacks to render internal content</returns>
        private static T _GetOrSet<T>(HtmlHelper helper, T defaultValue, string identifier = EMPTY_IDENTIFIER) where T : class {
            var storage = GetStorage(helper);

            // return the stored item, or set it if it does not exist
            return (T) (storage.ContainsKey(identifier) ? storage[identifier] : (storage[identifier] = defaultValue));
        }

        /// <summary>
        /// Get the storage, but if it doesn't exist or isn't the expected type, then create a new "bucket"
        /// </summary>
        /// <param name="helper"></param>
        /// <returns></returns>
        public static Dictionary<string, object> GetStorage(HtmlHelper helper) {
            var storage = helper.ViewContext.HttpContext.Items[CACHE_KEY] as Dictionary<string, object>;
            if (storage == null) helper.ViewContext.HttpContext.Items[CACHE_KEY] = (storage = new Dictionary<string, object>());
            return storage;
        }


        private readonly HtmlHelper helper;
        private readonly string identifier;
        private readonly string isOnlyOne;

        /// <summary>
        /// Create a new using block from the given helper (used for trapping appropriate context)
        /// </summary>
        /// <param name="helper">the helper from which we use the context</param>
        /// <param name="identifier">optional unique identifier to specify one or many injection blocks</param>
        /// <param name="isOnlyOne">extra identifier used to ensure that this item is only added once; if provided, content should only appear once in the page (i.e. only the first block called for this identifier is used)</param>
        public DelayedInjectionBlock(HtmlHelper helper, string identifier = null, string isOnlyOne = null) {
            this.helper = helper;

            // start a new writing context
            ((WebViewPage)this.helper.ViewDataContainer).OutputStack.Push(new StringWriter());

            this.identifier = identifier ?? EMPTY_IDENTIFIER;
            this.isOnlyOne = isOnlyOne;
        }

        /// <summary>
        /// Append the internal content to the context's cached list of output delegates
        /// </summary>
        public void Dispose() {
            // render the internal content of the injection block helper
            // make sure to pop from the stack rather than just render from the Writer
            // so it will remove it from regular rendering
            var content = ((WebViewPage)this.helper.ViewDataContainer).OutputStack;
            var renderedContent = content.Count == 0 ? string.Empty : content.Pop().ToString();
            // if we only want one, remove the existing
            var queue = GetQueue(this.helper, this.identifier);

            // get the index of the existing item from the alternate storage
            var existingIdentifiers = _GetOrSet(this.helper, new Dictionary<string, int>(), UNIQUE_IDENTIFIER_KEY);

            // only save the result if this isn't meant to be unique, or
            // if it's supposed to be unique and we haven't encountered this identifier before
            if( null == this.isOnlyOne || !existingIdentifiers.ContainsKey(this.isOnlyOne) ) {
                // remove the new writing context we created for this block
                // and save the output to the queue for later
                queue.Enqueue(renderedContent);

                // only remember this if supposed to
                if(null != this.isOnlyOne) existingIdentifiers[this.isOnlyOne] = queue.Count; // save the index, so we could remove it directly (if we want to use the last instance of the block rather than the first)
            }
        }
    }


    /// <summary>
    /// <para>Start a delayed-execution block of output -- this will be rendered/printed on the next call to <see cref="RenderDelayed"/>.</para>
    /// <para>
    /// <example>
    /// Print once in "default block" (usually rendered at end via <code>@Html.RenderDelayed()</code>).  Code:
    /// <code>
    /// @using (Html.Delayed()) {
    ///     <b>show at later</b>
    ///     <span>@Model.Name</span>
    ///     etc
    /// }
    /// </code>
    /// </example>
    /// </para>
    /// <para>
    /// <example>
    /// Print once (i.e. if within a looped partial), using identified block via <code>@Html.RenderDelayed("one-time")</code>.  Code:
    /// <code>
    /// @using (Html.Delayed("one-time", isOnlyOne: "one-time")) {
    ///     <b>show me once</b>
    ///     <span>@Model.First().Value</span>
    /// }
    /// </code>
    /// </example>
    /// </para>
    /// </summary>
    /// <param name="helper">the helper from which we use the context</param>
    /// <param name="injectionBlockId">optional unique identifier to specify one or many injection blocks</param>
    /// <param name="isOnlyOne">extra identifier used to ensure that this item is only added once; if provided, content should only appear once in the page (i.e. only the first block called for this identifier is used)</param>
    /// <returns>using block to wrap delayed output</returns>
    public static IDisposable Delayed(this HtmlHelper helper, string injectionBlockId = null, string isOnlyOne = null) {
        return new DelayedInjectionBlock(helper, injectionBlockId, isOnlyOne);
    }

    /// <summary>
    /// Render all queued output blocks injected via <see cref="Delayed"/>.
    /// <para>
    /// <example>
    /// Print all delayed blocks using default identifier (i.e. not provided)
    /// <code>
    /// @using (Html.Delayed()) {
    ///     <b>show me later</b>
    ///     <span>@Model.Name</span>
    ///     etc
    /// }
    /// </code>
    /// -- then later --
    /// <code>
    /// @using (Html.Delayed()) {
    ///     <b>more for later</b>
    ///     etc
    /// }
    /// </code>
    /// -- then later --
    /// <code>
    /// @Html.RenderDelayed() // will print both delayed blocks
    /// </code>
    /// </example>
    /// </para>
    /// <para>
    /// <example>
    /// Allow multiple repetitions of rendered blocks, using same <code>@Html.Delayed()...</code> as before.  Code:
    /// <code>
    /// @Html.RenderDelayed(removeAfterRendering: false); /* will print */
    /// @Html.RenderDelayed() /* will print again because not removed before */
    /// </code>
    /// </example>
    /// </para>

    /// </summary>
    /// <param name="helper">the helper from which we use the context</param>
    /// <param name="injectionBlockId">optional unique identifier to specify one or many injection blocks</param>
    /// <param name="removeAfterRendering">only render this once</param>
    /// <returns>rendered output content</returns>
    public static MvcHtmlString RenderDelayed(this HtmlHelper helper, string injectionBlockId = null, bool removeAfterRendering = true) {
        var stack = DelayedInjectionBlock.GetQueue(helper, injectionBlockId);

        if( removeAfterRendering ) {
            var sb = new StringBuilder(
#if DEBUG
                string.Format("<!-- delayed-block: {0} -->", injectionBlockId)
#endif
                );
            // .count faster than .any
            while (stack.Count > 0) {
                sb.AppendLine(stack.Dequeue());
            }
            return MvcHtmlString.Create(sb.ToString());
        } 

        return MvcHtmlString.Create(
#if DEBUG
                string.Format("<!-- delayed-block: {0} -->", injectionBlockId) + 
#endif
            string.Join(Environment.NewLine, stack));
    }


}
36
drzaus

J'ai eu ce problème et utilisé this technique.

C'est la meilleure solution que j'ai trouvée et qui est très flexible. 

Aussi merci de voterici pour ajouter le support pour la déclaration de section cumulative

15
iBoy

Si vous avez un besoin légitime d'exécuter un js à partir d'un partial, voici comment procéder: jQuery est requis:

<script type="text/javascript">        
    function scriptToExecute()
    {
        //The script you want to execute when page is ready.           
    }

    function runWhenReady()
    {
        if (window.$)
            scriptToExecute();                                   
        else
            setTimeout(runWhenReady, 100);
    }
    runWhenReady();
</script>
8
Serj Sagan

Suivant le principe discret , il n’est pas nécessaire que "_myPartial" injecte le contenu directement dans la section scripts. Vous pouvez ajouter ces scripts de vue partielle dans un fichier .js séparé et les référencer dans la section @scripts de la vue parent.

8
archil

Notre conception du Web présente un défaut fondamental, en particulier lors de l'utilisation de MVC. Le défaut est que JavaScript est en quelque sorte la responsabilité de la vue. Une vue est une vue, JavaScript (comportemental ou autre) est JavaScript. Dans Silverlight et le modèle MVVM de WPF, nous nous trouvons face à "voir en premier" ou "modèle en premier". Dans MVC, nous devrions toujours essayer de raisonner du point de vue du modèle et JavaScript fait partie de ce modèle à bien des égards. 

Je suggère d'utiliser le motif AMD (j'aime moi-même RequireJS ). Séparez votre JavaScript en modules, définissez vos fonctionnalités et accrochez-vous à votre code HTML à partir de JavaScript au lieu de compter sur une vue pour charger le JavaScript. Cela va nettoyer votre code, séparer vos préoccupations et vous rendre la vie plus facile en un seul coup.

4
Mr. Baudin

La première solution à laquelle je puisse penser, consiste à utiliser ViewBag pour stocker les valeurs à restituer. 

Je n'ai jamais essayé de voir si cela fonctionnait sous un angle partiel, mais il devrait en être autrement.

2
Iridio

Vous pouvez utiliser ces méthodes d'extension : (Enregistrer sous PartialWithScript.cs)

namespace System.Web.Mvc.Html
{
    public static class PartialWithScript
    {
        public static void RenderPartialWithScript(this HtmlHelper htmlHelper, string partialViewName)
        {
            if (htmlHelper.ViewBag.ScriptPartials == null)
            {
                htmlHelper.ViewBag.ScriptPartials = new List<string>();
            }

            if (!htmlHelper.ViewBag.ScriptPartials.Contains(partialViewName))
            {
                htmlHelper.ViewBag.ScriptPartials.Add(partialViewName);
            }

            htmlHelper.ViewBag.ScriptPartialHtml = true;
            htmlHelper.RenderPartial(partialViewName);
        }

        public static void RenderPartialScripts(this HtmlHelper htmlHelper)
        {
            if (htmlHelper.ViewBag.ScriptPartials != null)
            {
                htmlHelper.ViewBag.ScriptPartialHtml = false;
                foreach (string partial in htmlHelper.ViewBag.ScriptPartials)
                {
                    htmlHelper.RenderPartial(partial);
                }
            }
        }
    }
}

Utilisez comme ceci:

Exemple partial: (_MyPartial.cshtml) Placez le code HTML dans le if, et le js dans le reste.

@if (ViewBag.ScriptPartialHtml ?? true)
    <p>I has htmls</p>
}
else {
    <script type="text/javascript">
        alert('I has javascripts');
    </script>
}

Dans votre _Layout.cshtml, ou à n'importe quel endroit où vous souhaitez que les scripts des partiels soient rendus, insérez (une fois) le texte suivant: Il restituera uniquement le javascript de tous les partiels de la page en cours à cet emplacement.

@{ Html.RenderPartialScripts(); }

Ensuite, pour utiliser votre partial, procédez comme suit: Il ne restituera que le code HTML à cet emplacement.

@{Html.RenderPartialWithScript("~/Views/MyController/_MyPartial.cshtml");}
1
Lomak

Il y a un moyen d'insérer des sections dans des vues partielles, bien que ce ne soit pas beau. Vous devez avoir accès à deux variables à partir de la vue parent. Étant donné qu'une partie de l'objectif même de votre vue partielle est de créer cette section, il est logique d'exiger ces variables.

Voici à quoi cela ressemble d'insérer une section dans la vue partielle:

@model KeyValuePair<WebPageBase, HtmlHelper>
@{
    Model.Key.DefineSection("SectionNameGoesHere", () =>
    {
        Model.Value.ViewContext.Writer.Write("Test");
    });
}

Et dans la page insérant la vue partielle ...

@Html.Partial(new KeyValuePair<WebPageBase, HtmlHelper>(this, Html))

Vous pouvez également utiliser cette technique pour définir le contenu d'une section par programmation dans n'importe quelle classe.

Prendre plaisir!

1
Pluto

Cela a fonctionné pour moi, me permettant de co-localiser javascript et html pour une vue partielle dans le même fichier. Aide le processus de réflexion à voir le langage HTML et les parties connexes dans le même fichier à vue partielle.


Dans la vue qui utilise la vue partielle appelée "_MyPartialView.cshtml"

<div>
    @Html.Partial("_MyPartialView",< model for partial view>,
            new ViewDataDictionary { { "Region", "HTMLSection" } } })
</div>

@section scripts{

    @Html.Partial("_MyPartialView",<model for partial view>, 
                  new ViewDataDictionary { { "Region", "ScriptSection" } })

 }

En vue partielle fichier

@model SomeType

@{
    var region = ViewData["Region"] as string;
}

@if (region == "HTMLSection")
{


}

@if (region == "ScriptSection")
{
        <script type="text/javascript">
    </script">
}
1
purvin

Vous n'avez pas besoin d'utiliser des sections en vue partielle.

Inclure dans votre vue partielle . Il exécute la fonction après le chargement de jQuery . Vous pouvez modifier la clause de condition pour votre code.

<script type="text/javascript">    
var time = setInterval(function () {
    if (window.jQuery != undefined) {
        window.clearInterval(time);

        //Begin
        $(document).ready(function () {
           //....
        });
        //End
    };
}, 10); </script>

Julio Spader

1
Julio Spader

En utilisant Mvc Core, vous pouvez créer une rangée TagHelper scripts comme indiqué ci-dessous. Cela pourrait facilement être transformé en une balise section où vous lui donnerez également un nom (ou le nom provient du type dérivé). Notez que l'injection de dépendance doit être configurée pour IHttpContextAccessor.

Lors de l'ajout de scripts (par exemple dans un partiel)

<scripts>
    <script type="text/javascript">
        //anything here
    </script>
</scripts>

Lors de la sortie des scripts (dans un fichier de mise en page, par exemple)

<scripts render="true"></scripts>

Code

public class ScriptsTagHelper : TagHelper
    {
        private static readonly object ITEMSKEY = new Object();

        private IDictionary<object, object> _items => _httpContextAccessor?.HttpContext?.Items;

        private IHttpContextAccessor _httpContextAccessor;

        public ScriptsTagHelper(IHttpContextAccessor httpContextAccessor)
        {
            _httpContextAccessor = httpContextAccessor;
        }

        public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
        {
            var attribute = (TagHelperAttribute)null;
            context.AllAttributes.TryGetAttribute("render",out attribute);

            var render = false;

            if(attribute != null)
            {
                render = Convert.ToBoolean(attribute.Value.ToString());
            }

            if (render)
            {
                if (_items.ContainsKey(ITEMSKEY))
                {
                    var scripts = _items[ITEMSKEY] as List<HtmlString>;

                    var content = String.Concat(scripts);

                    output.Content.SetHtmlContent(content);
                }
            }
            else
            {
                List<HtmlString> list = null;

                if (!_items.ContainsKey(ITEMSKEY))
                {
                    list = new List<HtmlString>();
                    _items[ITEMSKEY] = list;
                }

                list = _items[ITEMSKEY] as List<HtmlString>;

                var content = await output.GetChildContentAsync();

                list.Add(new HtmlString(content.GetContent()));
            }
        }
    }
0
BlackjacketMack

J'ai résolu ce problème de manière complètement différente (parce que j'étais pressé et que je ne voulais pas implémenter un nouveau HtmlHelper):

J'ai enveloppé ma vue partielle dans une grosse déclaration if-else:

@if ((bool)ViewData["ShouldRenderScripts"] == true){
// Scripts
}else{
// Html
}

Ensuite, j'ai appelé le Partial deux fois avec un ViewData personnalisé:

@Html.Partial("MyPartialView", Model, 
    new ViewDataDictionary { { "ShouldRenderScripts", false } })

@section scripts{
    @Html.Partial("MyPartialView", Model, 
        new ViewDataDictionary { { "ShouldRenderScripts", true } })
}
0
Rick Love

de manière judicieuse, vous pouvez utiliser votre dossier/index.cshtml comme page maître puis ajouter des scripts de section. Ensuite, dans votre mise en page, vous avez:

@RenderSection("scripts", required: false) 

et votre index.cshtml:

@section scripts{
     @Scripts.Render("~/Scripts/file.js")
}

et cela fonctionnera sur toutes vos vues partielles. Ça marche pour moi

0
RogerEdward

Je viens d'ajouter ce code sur ma vue partielle et de résoudre le problème, bien que pas très propre, cela fonctionne. Vous devez vous assurer que les identifiants des objets que vous rendez.

0
luis

J'ai eu un problème similaire, où j'avais une page maître comme suit:

@section Scripts {
<script>
    $(document).ready(function () {
        ...
    });
</script>
}

...

@Html.Partial("_Charts", Model)

mais la vue partielle dépendait de JavaScript dans la section Scripts. Je l'ai résolu en encodant la vue partielle au format JSON, en la chargeant dans une variable JavaScript, puis en l'utilisant pour renseigner un div.

@{
    var partial = Html.Raw(Json.Encode(new { html = Html.Partial("_Charts", Model).ToString() }));
}

@section Scripts {
<script>
    $(document).ready(function () {
        ...
        var partial = @partial;
        $('#partial').html(partial.html);
    });
</script>
}

<div id="partial"></div>
0
John M

L'idée de Pluto d'une manière plus agréable:

CustomWebViewPage.cs:

    public abstract class CustomWebViewPage<TModel> : WebViewPage<TModel> {

    public IHtmlString PartialWithScripts(string partialViewName, object model) {
        return Html.Partial(partialViewName: partialViewName, model: model, viewData: new ViewDataDictionary { ["view"] = this, ["html"] = Html });
    }

    public void RenderScriptsInBasePage(HelperResult scripts) {
        var parentView = ViewBag.view as WebPageBase;
        var parentHtml = ViewBag.html as HtmlHelper;
        parentView.DefineSection("scripts", () => {
            parentHtml.ViewContext.Writer.Write(scripts.ToHtmlString());
        });
    }
}

Vues\web.config:

<pages pageBaseType="Web.Helpers.CustomWebViewPage">

Vue:

@PartialWithScripts("_BackendSearchForm")

Partielle (_BackendSearchForm.cshtml):

@{ RenderScriptsInBasePage(scripts()); }

@helper scripts() {
<script>
    //code will be rendered in a "scripts" section of the Layout page
</script>
}

Page de mise en page:

@RenderSection("scripts", required: false)
0
PaulSanS

Le but de l'OP est qu'il veuille définir des scripts inline dans sa vue partielle. Je suppose que ce script est spécifique à cette vue partielle et que ce bloc est inclus dans sa section de script.

Je comprends qu'il veuille que cette vue partielle soit autonome. L'idée est similaire aux composants lors de l'utilisation angulaire. 

Ma façon de faire serait simplement de conserver les scripts dans la vue partielle tels quels. Maintenant, le problème avec cela, c'est quand on appelle Partial View, il peut exécuter le script ici avant tous les autres scripts (qui sont généralement ajoutés au bas de la page de présentation). Dans ce cas, il vous reste à attendre que le script Vue partielle attende les autres scripts. Il y a plusieurs moyens de le faire. Le plus simple, que j'ai utilisé auparavant, utilise un événement sur body

Sur ma mise en page, j'aurais quelque chose en bas comme ceci:

// global scripts
<script src="js/jquery.min.js"></script>
// view scripts
@RenderSection("scripts", false)
// then finally trigger partial view scripts
<script>
  (function(){
    document.querySelector('body').dispatchEvent(new Event('scriptsLoaded'));
  })();
</script>

Puis sur ma vue partielle (en bas):

<script>
  (function(){
    document.querySelector('body').addEventListener('scriptsLoaded', function() {

      // .. do your thing here

    });
  })();
</script>

Une autre solution consiste à utiliser une pile pour envoyer tous vos scripts et les appeler à la fin. Une autre solution, comme déjà mentionné, est le modèle RequireJS/AMD, qui fonctionne très bien également.

0
alans