In ASP.NET Core MVC it is possible to define a script section for a page like this:
@section scripts {
Here is a solution :
In Layout page :
@Html.PageScripts()
In the Partial :
@using (Html.BeginScripts())
{
<script>
alert('hello');
</script>
}
And The Helper Class for MVC.core
using Microsoft.AspNetCore.Html;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Rendering;
using System;
using System.Collections.Generic;
using System.IO;
namespace MyProjectNamespace
{
public static class HtmlHelpers
{
private const string ScriptsKey = "DelayedScripts";
public static IDisposable BeginScripts(this IHtmlHelper helper)
{
return new ScriptBlock(helper.ViewContext);
}
public static HtmlString PageScripts(this IHtmlHelper helper)
{
return new HtmlString(string.Join(Environment.NewLine, GetPageScriptsList(helper.ViewContext.HttpContext)));
}
private static List<string> GetPageScriptsList(HttpContext httpContext)
{
var pageScripts = (List<string>)httpContext.Items[ScriptsKey];
if (pageScripts == null)
{
pageScripts = new List<string>();
httpContext.Items[ScriptsKey] = pageScripts;
}
return pageScripts;
}
private class ScriptBlock : IDisposable
{
private readonly TextWriter _originalWriter;
private readonly StringWriter _scriptsWriter;
private readonly ViewContext _viewContext;
public ScriptBlock(ViewContext viewContext)
{
_viewContext = viewContext;
_originalWriter = _viewContext.Writer;
_viewContext.Writer = _scriptsWriter = new StringWriter();
}
public void Dispose()
{
_viewContext.Writer = _originalWriter;
var pageScripts = GetPageScriptsList(_viewContext.HttpContext);
pageScripts.Add(_scriptsWriter.ToString());
}
}
}
}
Tip: import you class helper in _ViewImports.cshtml so you can use it in all views.
Generally this is a bad idea because you aren't bundling/minifying your scripts.
@ErikPhilips that not true, imagine that i want a specific javascript code that only run in that partial. why should i bundle it and import all over the application? And for minifying, i can create my typescript file minifyied and import it on the partial inside my script block.
imagine that i want a specific javascript code that only run in that partial.
The script won't only run in that partial it will run for the entire page. It's client side code delivered in a single http call (assuming normal usage because you haven't specified anything else). Consider the partial:
@Model SomeModel
<div class='my-component'>
<div>
<script>
$('.my-component').css('width', model.Width);
</script>
Not reusable because all components same page will be the same width regardless of model.
Instead you can create a single script file and use data-* attributes to store configuration information and let the the single script figure it out (like many MANY libraries do, for example bootstrap):
<div class='my-component green' data-config='{ "width": 200, "height": 200 }'>
</div>
then in the single script file:
$(document).ready(function(){
$('.my-component').each(function(){
var $this = $(this);
var config = $this.data('config');
$this.css("width", config.width);
$this.css("height", config.height);
});
});
why should i bundle it
Because then it's cached by the browser automatically. That means less to download every instance. Consider the following:
<div class='my-component'>
<div>
<script>
// lots of scripts say 100-200 lines of it.
</script>
Every time the client visits any page, they have to download probably the same exact code every time, possibly multiple times per page. That takes up both client bandwidth and server bandwidth that is not necessary.
and import all over the application?
You import it once, either globally or maybe once in a specific layout. Because after the first time, it's cached.
And for minifying, i can create my typescript file minifyied and import it on the partial inside my script block.
Then why have script in the partial at all.
Recommended Reading: Decoupling Your HTML, CSS, and JavaScript