Injecting content into specific sections from a pa

2018-12-31 07:31发布

I have this section defined in my _Layout.cshtml

@RenderSection("Scripts", false)

I can easily use it from a view:

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

What I'm struggling with is how to get some content injected inside this section from a partial view.

Let's assume this is my view page:

@section Scripts { 

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

<div>
    poo bar poo
</div>

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

I need to inject some content inside the Scripts section from _myPartial partial view.

How can I do this?

22条回答
泪湿衣
2楼-- · 2018-12-31 07:53

I had a similar problem, where I had a master page as follows:

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

...

@Html.Partial("_Charts", Model)

but the partial view depended on some JavaScript in the Scripts section. I solved it by encoding the partial view as JSON, loading it into a JavaScript variable and then using this to populate a div, so:

@{
    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>
查看更多
千与千寻千般痛.
3楼-- · 2018-12-31 07:54

I solved this a completely different route (because I was in a hurry and didn't want to implement a new HtmlHelper):

I wrapped my Partial View in a big if-else statement:

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

Then, I called the Partial twice with a custom ViewData:

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

@section scripts{
    @Html.Partial("MyPartialView", Model, 
        new ViewDataDictionary { { "ShouldRenderScripts", true } })
}
查看更多
宁负流年不负卿
4楼-- · 2018-12-31 07:55

The goal of the OP is that he wants to define inline scripts into his Partial View, which I assume that this script is specific only to that Partial View, and have that block included into his script section.

I get that he wants to have that Partial View to be self contained. The idea is similar to components when using Angular.

My way would be to just keep the scripts inside the Partial View as is. Now the problem with that is when calling Partial View, it may execute the script in there before all other scripts (which is typically added to the bottom of the layout page). In that case, you just have the Partial View script wait for the other scripts. There are several ways to do this. The simplest one, which I've used before, is using an event on body.

On my layout, I would have something on the bottom like this:

// 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>

Then on my Partial View (at the bottom):

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

      // .. do your thing here

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

Another solution is using a stack to push all your scripts, and call each one at the end. Other solution, as mentioned already, is RequireJS/AMD pattern, which works really well also.

查看更多
闭嘴吧你
5楼-- · 2018-12-31 07:56

I had the similar problem solved it with this:

@section ***{
@RenderSection("****", required: false)
}

Thats a pretty way to inject i guesse.

查看更多
长期被迫恋爱
6楼-- · 2018-12-31 07:57

Sections don't work in partial views and that's by design. You may use some custom helpers to achieve similar behavior, but honestly it's the view's responsibility to include the necessary scripts, not the partial's responsibility. I would recommend using the @scripts section of the main view to do that and not have the partials worry about scripts.

查看更多
人间绝色
7楼-- · 2018-12-31 07:58

Using Mvc Core you can create a tidy TagHelper scripts as seen below. This could easily be morphed into a section tag where you give it a name as well (or the name is taken from the derived type). Note that dependency injection needs to be setup for IHttpContextAccessor.

When adding scripts (e.g. in a partial)

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

When outputting the scripts (e.g. in a layout file)

<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()));
            }
        }
    }
查看更多
登录 后发表回答