Since we're not able to use sections inside a partial view, what's the cleanest approach to including scripts that are only required by the partial?
I know I can include my scripts section in the page calling the partial, but if my partial includes a Javascript component that I want to re-use throughout my site, then including custom scripts in every base page is a maintenance nightmare.
Considering that not being able to use JS inside a partial is by design, am I even correct in wanting to use a partial for a re-usable view that includes Javascript components?
You could make a partial signal to the layout page that it should include a script by for example using an IOC scoped or HttpContext Bag. which is read by the layout page.
The only, and main problem is that the script will only be in this bag once this the partial is executed and then most probably your html head section is already closed in the layout view. So its fine for adding scripts in the bottom of the page but it wont work for css.
A better way is to create your own kind of view compontents (or extend them) and make an option to specify necessary views. IOC these components at the top and render them where needed.
A better solution would be, if like half of the pages need this java-script to bundle it inside the main bundle. The minifier would probably be able to minify more variables, and the user would need to request 1 less script (http request) for the page being loaded, thus creating less traffic, creating a faster page load, creating a better user experience.
I won't pretend this is optimal, but if you don't want to create your own viewpage extensions, you might be able to get away with building something like this:
public static class DeferredScripts
{
static IList<string> paths = new List<string>();
public static IList<string> Scripts { get; set; }
public static void Add(string path)
{
if (Scripts == null)
{
Scripts = new List<string>();
}
if (!paths.Any(s => s.Equals(path, StringComparison.OrdinalIgnoreCase)))
{
var script = new TagBuilder("script");
script.Attributes.Add("src", path);
Scripts.Add(script.ToString());
paths.Add(path);
}
}
}
Which you could then use like this in a partial view:
@{
DeferredScripts.Add("/scripts/testscript1.js");
}
And use this in your layout (or in a view page):
@foreach (var script in DeferredScripts.Scripts)
{
@Html.Raw(script)
}
Seems to work in the test project I threw together: https://github.com/tiesont/DeferredScriptsTestApp
Telerik has something similar for their KendoUI ASP.NET MVC helpers, although I assume their implementation is more robust than what I've shown here.
I think it would be fair but probably least helpful answer is to say "You're using the MVC6 wrong if you want to use sections in a partial or simulate it".
There are 3 main cases for an ideal solution to your problem:
3 main options are
<hidden data-myTool-*="MyData">
and have a main script at the bottom of the page to read it all in (Not ideal because it violates #1)This is an example of option 3:
Partial:
@model List<string>
FROM TEST PARTIAL
@{ Model.Add("Partial.js");}
View:
@{
var jsfiles = new List<string>();
jsfiles.Add("View.js");
}
@Html.Partial("_Test", jsfiles)
@Html.Partial("_Test", jsfiles)
@Html.Partial("_Test", jsfiles)
@section scripts {
@foreach (string file in jsfiles.Distinct().ToList())
{
<script src="@file"></script>
}
}
Result:
<script src="View.js"></script>
<script src="Partial.js"></script>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With