Javascript in the View component

I have a View component containing some jQuery in a Razor file (.cshtml). The script itself is very presentation specific (it deals with some configuration of third-party libraries), so I would like to save the script and HTML in one file for the organization's sake.

The problem is that the script does not appear in the _Layout Scripts section. Apparently, this is just how MVC handles scripts in relation to View Components.

I can get around this by simply having the scripts in the Razor file, but not inside the Scripts section.

But then I run into dependency problems - since jQuery is used before the library link (the library link is at the bottom of the _Layout file).

Is there any clever solution to this other than including a link to jQuery as part of Razor code (which will interfere with HTML rendering, wherever it is)?

Currently, I do not see the code, but I can, of course, provide it as soon as I have a chance, if someone needs to look at it in order to better understand it.

+15
source share
6 answers

ScriptTagHelper, "OnContentLoaded". true, script Javascript , . jQuery, ViewComponent.

[HtmlTargetElement("script", Attributes = "on-content-loaded")]
public class ScriptTagHelper : TagHelper
{
  /// <summary>
  /// Execute script only once document is loaded.
  /// </summary>
  public bool OnContentLoaded { get; set; } = false;

  public override void Process(TagHelperContext context, TagHelperOutput output)
  {
     if (!OnContentLoaded)
     {
        base.Process(context, output);
     } 
     else
     {
        var content = output.GetChildContentAsync().Result;
        var javascript = content.GetContent();

        var sb = new StringBuilder();
        sb.Append("document.addEventListener('DOMContentLoaded',");
        sb.Append("function() {");
        sb.Append(javascript);
        sb.Append("});");

        output.Content.SetHtmlContent(sb.ToString()); 
     }
  }
}

ViewComponent:

<script type="text/javascript" on-content-loaded="true">
    $('.button-collapse').sideNav();
</script>

, , , .

+21

   , (Default.cshtml ViewResult, Layout null.) .

render sections Layout, partial view view component. , , . jQuery View, head, body Layout.

:

:

public class ContactViewComponent : ViewComponent
{
    public IViewComponentResult Invoke()
    {
        return View();
    }
}

ViewComponent:

/Views/[CurrentController]/Components/[NameOfComponent]/Default.cshtml
/Views/Shared/Components/[NameOfComponent]/Default.cshtml

Default.cshtml:

@model ViewComponentTest.ViewModels.Contact.ContactViewModel

<form method="post" asp-action="contact" asp-controller="home">
    <fieldset>
        <legend>Contact</legend>
        Email: <input asp-for="Email" /><br />
        Name: <input asp-for="Name" /><br />
        Message: <textarea asp-for="Message"></textarea><br />
        <input type="submit" value="Submit" class="btn btn-default" />
    </fieldset>
</form>

_Layout.cshtml :

    <!DOCTYPE html>
    <html>
    <head>
    ...
        @RenderSection("styles", required: false)
     <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
    </head>
    <body>
        @RenderBody()
    ...
    //script move to head
      @RenderSection("scripts", required: false)
    </body>
    </html>

View.cshtml:

@{
    Layout =  "~/Views/Shared/_Layout.cshtml";     
}
..................
@{Html.RenderPartial("YourPartialView");}
..................
@await Component.InvokeAsync("Contact")
..................
@section Scripts {
    <script>
    //Do somthing
    </script>
}

grahamehorner: ( )

@section ViewComponent, @ .

+6

, . script, script. (, _Layout.cshtml), View.

:

( <head> - ):

<script>
    MYCOMPANY = window.MYCOMPANY || {};
    MYCOMPANY.delayed = null;
    MYCOMPANY.delay = function (f) { var e = MYCOMPANY.delayed; MYCOMPANY.delayed = e ? function () { e(); f(); } : f; };
</script>

( </body>):

<script>MYCOMPANY.delay = function (f) { setTimeout(f, 1) }; if (MYCOMPANY.delayed) { MYCOMPANY.delay(MYCOMPANY.delayed); MYCOMPANY.delayed = null; }</script>

:

, View Component, script :

<script>
    MYCOMPANY.delay(function() {
        console.log('Hello from the bottom of the page');
    });
</script>




script

. JavaScript script . View . , ( JavaScript, ), script. :

:

Lazy load script

<script>
    MYCOMPANY.loadScript = (function () {
        var ie = null;
        if (/MSIE ([^;]+)/.test(navigator.userAgent)) {
            var version = parseInt(RegExp['$1'], 10);
            if (version)
                ie = {
                    version: parseInt(version, 10)
                };
        }

        var assets = {};

        return function (url, callback, attributes) {

            attributes || (attributes = {});

            var onload = function (url) {
                assets[url].loaded = true;
                while (assets[url].callbacks.length > 0)
                    assets[url].callbacks.shift()();
            };

            if (assets[url]) {

                if (assets[url].loaded)
                    callback();

                assets[url].callbacks.push(callback);

            } else {

                assets[url] = {
                    loaded: false,
                    callbacks: [callback]
                };

                var script = document.createElement('script');
                script.type = 'text/javascript';
                script.async = true;
                script.src = url;

                for (var attribute in attributes)
                    if (attributes.hasOwnProperty(attribute))
                        script.setAttribute(attribute, attributes[attribute]);

                // can't use feature detection, as script.readyState still exists in IE9
                if (ie && ie.version < 9)
                    script.onreadystatechange = function () {
                        if (/loaded|complete/.test(script.readyState))
                            onload(url);
                    };
                else
                    script.onload = function () {
                        onload(url);
                    };

                document.getElementsByTagName('head')[0].appendChild(script);
            }
        };
    }());
</script>

:

View ( - ):

<script>
    MYCOMPANY.delay(function () {
        MYCOMPANY.loadScript('/my_external_script.js', function () {
            console.log('This executes after my_external_script.js is loaded.');
        });
    });
</script>

, View ( @JakeShakesworth):

[HtmlTargetElement("script", Attributes = "delay")]
public class ScriptDelayTagHelper : TagHelper
{
    /// <summary>
    /// Delay script execution until the end of the page
    /// </summary>
    public bool Delay { get; set; }

    /// <summary>
    /// Execute only after this external script file is loaded
    /// </summary>
    [HtmlAttributeName("after")]
    public string After { get; set; }

    public override void Process(TagHelperContext context, TagHelperOutput output)
    {
        if (!Delay) base.Process(context, output);

        var content = output.GetChildContentAsync().Result;
        var javascript = content.GetContent();

        var sb = new StringBuilder();
        sb.Append("if (!MYCOMPANY || !MYCOMPANY.delay) throw 'MYCOMPANY.delay missing.';");
        sb.Append("MYCOMPANY.delay(function() {");
        sb.Append(LoadFile(javascript));
        sb.Append("});");

        output.Content.SetHtmlContent(sb.ToString());
    }

    string LoadFile(string javascript)
    {
        if (After == NullOrWhiteSpace)
            return javascript;

        var sb = new StringBuilder();
        sb.Append("if (!MYCOMPANY || !MYCOMPANY.loadScript) throw 'MYCOMPANY.loadScript missing.';");
        sb.Append("MYCOMPANY.loadScript(");
        sb.Append($"'{After}',");
        sb.Append("function() {");
        sb.Append(javascript);
        sb.Append("});");

        return sb.ToString();
    }
}

View :

<script delay="true" after="/my_external_script.js"]">
  console.log('This executes after my_external_script.js is loaded.');
</script>

after, .

0

.netcore 2.1. : Microsoft.AspNetCore.Mvc.Razor.TagHelpers.ITagHelperComponentManager, JavaScript, , body.

, .

, , HTML, & , .

() . , , , .

, . , ( , , ) , ViewComponents.

, JavaScript, shared/_layout.

_layout body. , - javascript, body. JavaScript .

TagHelperComponent TagHelperComponentManager. , ITagHelperComponent , . /Pages/Shared/

ScriptTagHelper

public class ScriptTagHelper : TagHelperComponent
{
    private readonly string _javascript;
    public ScriptTagHelper(string javascript = "") {
        _javascript = javascript;
    }
    public override Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
    {
        if (string.Equals(context.TagName, "body", StringComparison.Ordinal))
        {
            output.PostContent.AppendHtml($"<script type='text/javascript'>{_javascript}</script>");
        }
        return Task.CompletedTask;
    }
}

javascript . ProcessAsync , body JavaScript.

javascript Html-, Html- , . ( , , ).

ViewComponent. , ScriptTagHelper.

. , . , , .

. /Pages/Shared/Components/DataDistribution/Default.cshtml

@model dynamic;
@using Microsoft.AspNetCore.Mvc.Razor.TagHelpers;
@inject ITagHelperComponentManager tagManager;

<div class="col-md-3 grid-margin stretch-card">
    <div class="card">
        <div class="card-body">
            <p class="card-title text-md-center text-xl-left">Data Usage Distribution</p>
            <div class="d-flex flex-wrap justify-content-between justify-content-md-center justify-content-xl-between align-items-center">
                <h3 class="mb-0 mb-md-2 mb-xl-0 order-md-1 order-xl-0">40016</h3>
                <i class="ti-agenda icon-md text-muted mb-0 mb-md-3 mb-xl-0"></i>
            </div>
            <p class="mb-0 mt-2 text-success">10.00%<span class="text-body ml-1"><small>(30 days)</small></span></p>
        </div>
    </div>
</div>


@{
    Layout = null;

    string scriptOptions = Newtonsoft.Json.JsonConvert.SerializeObject(Model);

    string script = @"";

    script += $"console.log({scriptOptions});";

    tagManager.Components.Add(new ScriptTagHelper(javascript: script));
}

ITagHelperComponentManager , . - , javascript , body.

, , . , , , , , jquery, , jquery .

, - . , .netcore 3 , , , 2.1, .

0

, A B, _Scripts :

Views
  Shared
    Components
      A
        Default.cshtml
        _Scripts.cshtml
      B
        Default.cshtml
        _Scripts.cshtml

( ) :

@await Component.InvokeAsync("A")
@await Component.InvokeAsync("B")

@section Scripts {
    @await Html.PartialAsync("~/Views/Shared/Components/A/_Scripts.cshtml", Model);
    @await Html.PartialAsync("~/Views/Shared/Components/B/_Scripts.cshtml", Model);
}

_Scripts , , Scripts.

, . , .

0

Source: https://habr.com/ru/post/1673591/


All Articles