New to Telerik UI for ASP.NET Core? Download free 30-day trial

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:

  1. Add the Deferred() method of the HTML helper or enable the deferred attribute of the Tag helper. This option suppresses the immediate rendering of the <script> tag after the HTML 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.

  1. 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 a Boolean parameter which determines whether the script elements will be automatically rendered. This behavior is useful for rendering the deferred initialization scripts inside an existing script 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 the script 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:

  1. Enable the DeferToScriptFiles setting in the AddKendo 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 the Program.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 the ConfigureServices method in the Startup.cs file.

      public void ConfigureServices(IServiceCollection services)
      {
          services.AddKendo(x =>
          {
              x.DeferToScriptFiles = true;
          });
      }
      
  2. Set the KendoDefferedScriptsMiddleware middleware. After the compilation of the views, all scripts are stored in the memory cache. When the browser requests the dynamic js file, this middleware handles the request and returns the cached scripts.

        app.UseMiddleware<KendoDeferredScriptsMiddleware>();
    
  3. 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"))

See Also

In this article