Deferred Initialization
By default, the helpers output the initialization script of the component immediately after its HTML
markup. This scenario may not always be desired—for example, if the script files are registered at the bottom of the page, when you nest components, or when the Content Security Policy (CSP) is enabled.
The following example illustrates how the initialization script of a Button component is generated after its HTML
markup:
-
Button declaration
@(Html.Kendo().Button() .Name("primaryTextButton") .ThemeColor(ThemeColor.Primary) .Content("Primary Button") )
<kendo-button name="primaryTextButton" theme-color="ThemeColor.Primary"> Primary Button </kendo-button>
-
Generated HTML markup and initialization script
<button id="primaryTextButton" name="primaryTextButton" data-role="button" class="k-button k-button-md k-rounded-md k-button-solid k-button-solid-primary" type="button" role="button" aria-disabled="false" tabindex="0"><span class="k-button-text">Primary Button</span></button> <script>kendo.syncReady(function(){jQuery("#primaryTextButton").kendoButton({"themeColor":"primary"});});</script>
To defer the initialization script of the Telerik UI for ASP.NET Core components in the application, apply either of the following approaches:
Deferring Specific Components
To defer individual components:
-
Add the
Deferred()
method of the HTML helper or enable thedeferred
attribute of the Tag helper. This option suppresses the immediate rendering of the<script>
tag after theHTML
of the component.@(Html.Kendo().NumericTextBox() .Name("age") .Deferred() )
<kendo-numerictextbox name="age" deferred="true"> </kendo-numerictextbox>
Avoid deferring child components such as editors, components initialized inside client templates, or inside (inline or external Kendo UI templates). Otherwise, the initialization script of each child component will appear outside the parent component.
Serialize the component initialization script by using any of the following methods:
-
Call the
DeferredScripts
method. As a result, all previously deferred initialization statements will be output as an inline script.@Html.Kendo().DeferredScripts()
The
DeferredScripts
method accepts aBoolean
parameter which determines whether thescript
elements will be automatically rendered. This behavior is useful for rendering the deferred initialization scripts inside an existingscript
element.<script> @Html.Kendo().DeferredScripts(false) </script>
To render the deferred initialization script of a particular helper, use the
DeferredScriptsFor
method.@(Html.Kendo().NumericTextBox() .Name("age") .Deferred() ) <!-- other code --> @Html.Kendo().DeferredScriptsFor("age")
<kendo-numerictextbox name="age" deferred="true"> </kendo-numerictextbox> <!-- other code --> @Html.Kendo().DeferredScriptsFor("age")
You can also use the
DeferredScriptsFor
method to suppress thescript
element that wraps the initialization script.<script> @Html.Kendo().DeferredScriptsFor("age", false) </script>
Deferring Components Globally
As of the R1 2023 SP1 release, you can configure a global option to defer the initialization scripts of all components in your application and avoid setting the deferred option for every component. This method simulates loading the initialization scripts as a JS
file through a middleware.
To defer components globally:
-
Enable the
DeferToScriptFiles
setting in theAddKendo
method that registers the Kendo UI service.-
For applications using .NET 6 or later and the minimal hosting model, the
AddKendo
method is defined in theProgram.cs
file.var builder = WebApplication.CreateBuilder(args); builder.Services.AddKendo(x => { x.DeferToScriptFiles = true; });
-
For applications using .NET 5 or earlier, the
AddKendo
method is defined in theConfigureServices
method in theStartup.cs
file.public void ConfigureServices(IServiceCollection services) { services.AddKendo(x => { x.DeferToScriptFiles = true; }); }
-
-
Set the
KendoDefferedScriptsMiddleware
middleware. After the compilation of the views, all scripts are stored in the memory cache. When the browser requests the dynamicjs
file, this middleware handles the request and returns the cached scripts.app.UseMiddleware<KendoDeferredScriptsMiddleware>();
-
Serialize the script tag into a file by adding
@(Html.Kendo().DeferredScriptFile())
after all components HtmlHelper or TagHelper declarations. Any components registered after it will not be included in the script.Alternatively, call the
DeferredScripts
method to format the components scripts as inline script.@(Html.Kendo().DeferredScriptFile())
@Html.Kendo().DeferredScripts()
The functionality of the StackLayout and the GridLayout components relies on inline styles. When the application is configured to defer the initialization of all components and return a
JS
file, as demonstrated above, the use of inline styles in those components will also be deferred. In this scenrio an additional stylesheet will be served by the middleware.
Deferring Dynamically Loaded Components
When deferring the components globally and calling the DeferredScriptFile()
method, the simulated JS
file stores the initialization scripts of the components that are defined in the currently loaded View.
The following example shows the content of the generated JS
file when the loaded page contains only a TabStrip component with two tabs. The content of the second tab loads from a Partial View.
@{
ViewData["Title"] = "Home Page";
}
@(Html.Kendo().TabStrip()
.Name("tabstrip")
.Items(tabstrip =>
{
tabstrip.Add().Text("Engine").Selected(true)
.Content("Engine information");
tabstrip.Add().Text("Dimensions & Weights")
.LoadContentFrom(@Url.Action("Details", "Home"));
})
)
@{
ViewData["Title"] = "Home Page";
}
@addTagHelper *, Kendo.Mvc
<kendo-tabstrip name="tabstrip">
<items>
<tabstrip-item text="Engine" selected="true">
<content>Engine information</content>
</tabstrip-item>
<tabstrip-item text="Dimensions & Weights" content-url=@Url.Action("Details", "Home")>
</tabstrip-item>
</items>
</kendo-tabstrip>
public class HomeController : Controller
{
public ActionResult Details()
{
return PartialView();
}
}
Partial View Content
kendo.syncReady(function() {
jQuery("#tabstrip").kendoTabStrip({
"contentUrls": ["", "/Home/Details"]
});
});
According to this example, if the Partial View that is returned by the Details
Action contains Telerik UI for ASP.NET Core components, they will not be initialized because their initialization scripts are not included in the simulated kendo-deferred-scripts-XXX.js
file. To overcome this behavior, you need to call the DeferredScriptFile()
method in the Partial View after all components declarations. As a result, their initialization scripts will be stored in an external JS
file, which will load
with the Partial View.
The following example demonstrates how to load a Grid in a TabStrip item through a Partial View when the global deferred initialization is enabled.
@(Html.Kendo().TabStrip()
.Name("tabstrip")
.Items(tabstrip =>
{
tabstrip.Add().Text("Engine").Selected(true)
.Content("Engine information");
tabstrip.Add().Text("Dimensions & Weights")
.LoadContentFrom(@Url.Action("Details", "Home"));
})
)
@addTagHelper *, Kendo.Mvc
<kendo-tabstrip name="tabstrip">
<items>
<tabstrip-item text="Engine" selected="true">
<content>Engine information</content>
</tabstrip-item>
<tabstrip-item text="Dimensions & Weights" content-url=@Url.Action("Details", "Home")>
</tabstrip-item>
</items>
</kendo-tabstrip>
public class HomeController : Controller
{
public ActionResult Details()
{
return PartialView();
}
}
@(Html.Kendo().Grid<OrderViewModel>()
.Name("grid")
.Columns(columns =>
{
columns.Bound(c => c.OrderID);
columns.Bound(c => c.ShipName);
columns.Bound(c => c.OrderDate).Format("{0:MM/dd/yyyy}").Width(150);
})
.HtmlAttributes(new { style = "height:400px;" })
.Scrollable()
.Pageable()
.DataSource(dataSource => dataSource
.Ajax()
.PageSize(20)
.Read(read => read.Action("Read", "Grid"))
)
)
@(Html.Kendo().DeferredScriptFile())
@addTagHelper *, Kendo.Mvc
<kendo-grid name="grid" height="400">
<datasource type="DataSourceTagHelperType.Ajax" page-size="20">
<schema>
<model id="OrderID">
<fields>
<field name="OrderID" type="number"></field>
<field name="OrderDate" type="date"></field>
<field name="ShipName" type="string"></field>
</fields>
</model>
</schema>
<transport>
<read url="@Url.Action("Read","Grid")"/>
</transport>
</datasource>
<columns>
<column field="OrderID"/>
<column field="ShipName"/>
<column field="OrderDate" width="150" format="{0:MM/dd/yyyy}"/>
</columns>
<pageable enabled="true"/>
<scrollable enabled="true"/>
</kendo-grid>
@(Html.Kendo().DeferredScriptFile())
When the Content Security Policy (CSP) is enabled, you need to use a nonce-source when loading components dynamically, for example, through Partial Views, or inside Windows or Dialogs.
The DeferredScriptFile()
method accepts a nonce, so you can call the method with the respective nonce value. Thereby, the CSP will allow the inline <script>
tag that loads the external script file, which contains the initialization scripts of the components from the Partial View.
As of the R2 2023 SP1, the
DeferredScriptFile()
method supports nonce.
@(Html.Kendo().DeferredScriptFile("Telerik-CSP-Example"))
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'nonce-Telerik-CSP-Example' https://kendo.cdn.telerik.com;" />
The following example showcases how to load a Grid in a TabStrip item through a Partial View when the CSP is enabled.
@(Html.Kendo().TabStrip()
.Name("tabstrip")
.Items(tabstrip =>
{
tabstrip.Add().Text("Engine").Selected(true)
.Content("Engine information");
tabstrip.Add().Text("Dimensions & Weights")
.LoadContentFrom(@Url.Action("Details", "Home"));
})
)
@addTagHelper *, Kendo.Mvc
<kendo-tabstrip name="tabstrip">
<items>
<tabstrip-item text="Engine" selected="true">
<content>Engine information</content>
</tabstrip-item>
<tabstrip-item text="Dimensions & Weights" content-url=@Url.Action("Details", "Home")>
</tabstrip-item>
</items>
</kendo-tabstrip>
public class HomeController : Controller
{
public ActionResult Details()
{
return PartialView();
}
}
@(Html.Kendo().Grid<OrderViewModel>()
.Name("grid")
.Columns(columns =>
{
columns.Bound(c => c.OrderID);
columns.Bound(c => c.ShipName);
columns.Bound(c => c.OrderDate).Format("{0:MM/dd/yyyy}").Width(150);
})
.HtmlAttributes(new { style = "height:400px;" })
.Scrollable()
.Pageable()
.DataSource(dataSource => dataSource
.Ajax()
.PageSize(20)
.Read(read => read.Action("Read", "Grid"))
)
)
@(Html.Kendo().DeferredScriptFile("Telerik-CSP-Example"))
@addTagHelper *, Kendo.Mvc
<kendo-grid name="grid" height="400">
<datasource type="DataSourceTagHelperType.Ajax" page-size="20">
<schema>
<model id="OrderID">
<fields>
<field name="OrderID" type="number"></field>
<field name="OrderDate" type="date"></field>
<field name="ShipName" type="string"></field>
</fields>
</model>
</schema>
<transport>
<read url="@Url.Action("Read","Grid")"/>
</transport>
</datasource>
<columns>
<column field="OrderID"/>
<column field="ShipName"/>
<column field="OrderDate" width="150" format="{0:MM/dd/yyyy}"/>
</columns>
<pageable enabled="true"/>
<scrollable enabled="true"/>
</kendo-grid>
@(Html.Kendo().DeferredScriptFile("Telerik-CSP-Example"))