I have a View Component that contains some jQuery in the Razor (.cshtml) file. The script itself is quite specific to the view (deals with some some configuration of third-p
Here's the solution I'm using. It supports both external script loading and custom inline script. While some setup code needs to go in your layout file (e.g. _Layout.cshtml), everything is orchestrated from within the View Component.
Layout file:
Add this near the top of your page (inside the tag is a good place):
Add this near the bottom of your page (just before the closing tag is a good place):
View Component:
Now anywhere in your code, including your View Component, you can do this and have the script executed at the bottom of your page:
With External Script Dependency
But sometimes that's not enough. Sometimes you need to load an external JavaScript file and only execute your custom script once the external file is loaded. You also want to orchestrate this all in your View Component for full encapsulation. To do this, I add a little more setup code in my layout page (or external JavaScript file loaded by the layout page) to lazy load the external script file. That looks like this:
Layout file:
Lazy load script
View Component:
Now you can do this in your View Component (or anywhere else for that matter):
To clean things up a bit, here's a tag helper for the View Component (inspired by @JakeShakesworth's answer):
[HtmlTargetElement("script", Attributes = "delay")]
public class ScriptDelayTagHelper : TagHelper
{
///
/// Delay script execution until the end of the page
///
public bool Delay { get; set; }
///
/// Execute only after this external script file is loaded
///
[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();
}
}
Now in my View Component I can do this:
You can also leave out the after
attribute if the View Component doesn't have an external file dependency.