Hierarchical structure using Telerik TreeView in ASP.NET MVC

One of our customers required hierarchical UI to be implemented. The data was residing in an API and required remote data binding. This task is very easy to implement with Telerik TreeView from Telerik UI for ASP.NET MVC suite.

A TreeView component represents hierarchical data in a tree structure. It allows users to perform single or multiple selection of items, drag and drop of elements within the TreeView.

The Telerik UI for ASP.NET MVC TreeView component comes with built-in checkbox support, keyboard navigation, RTL support, accessibility and provides templates for complete customization of each node. You can bind the TreeView to various data sources and take advantage of its load on demand feature, and request data only when a node is expanded.

Let’s see how we can use Telerik TreeView control to implement heirarchial structures:

  1. Sample Database and Table Using below script

For hierarchical structure we need to do one to many relation in tables, but in a below example, we are doing relation one-to-many from the Products table to itself (in a single table). In the table, EmployeeId is primary key and ReportsTo is foreign key. See the highlighted lines below:

CREATE DATABASE [Sample]

GO
USE [Sample]
GO
/****** Object:  Table [dbo].[Employees]    Script Date: 2/16/2021 1:34:48 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Employees](
	[EmployeeID] [int] IDENTITY(1,1) NOT NULL,
	[LastName] [nvarchar](20) NOT NULL,
	[FirstName] [nvarchar](10) NOT NULL,
	[Title] [nvarchar](30) NULL,
	[TitleOfCourtesy] [nvarchar](25) NULL,
	[BirthDate] [datetime] NULL,
	[HireDate] [datetime] NULL,
	[Address] [nvarchar](60) NULL,
	[City] [nvarchar](15) NULL,
	[Region] [nvarchar](15) NULL,
	[PostalCode] [nvarchar](10) NULL,
	[Country] [nvarchar](15) NULL,
	[HomePhone] [nvarchar](24) NULL,
	[Extension] [nvarchar](4) NULL,
	[ReportsTo] [int] NULL,
 CONSTRAINT [PK_Employees] PRIMARY KEY CLUSTERED 
(
	[EmployeeID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET IDENTITY_INSERT [dbo].[Employees] ON 

INSERT [dbo].[Employees] ([EmployeeID], [LastName], [FirstName], [Title], [TitleOfCourtesy], [BirthDate], [HireDate], [Address], [City], [Region], [PostalCode], [Country], [HomePhone], [Extension], [ReportsTo]) VALUES (1, N'Davolio', N'Nancy', N'Sales Representative', N'Ms.', CAST(N'1948-12-08T00:00:00.000' AS DateTime), CAST(N'1992-05-01T00:00:00.000' AS DateTime), N'507 - 20th Ave. E.
Apt. 2A', N'Seattle', N'WA', N'98122', N'USA', N'(206) 555-9857', N'5467', 2)

INSERT [dbo].[Employees] ([EmployeeID], [LastName], [FirstName], [Title], [TitleOfCourtesy], [BirthDate], [HireDate], [Address], [City], [Region], [PostalCode], [Country], [HomePhone], [Extension], [ReportsTo]) VALUES (2, N'Fuller', N'Andrew', N'Vice President, Sales', N'Dr.', CAST(N'1952-02-19T00:00:00.000' AS DateTime), CAST(N'1992-08-14T00:00:00.000' AS DateTime), N'908 W. Capital Way', N'Tacoma', N'WA', N'98401', N'USA', N'(206) 555-9482', N'3457', NULL)

INSERT [dbo].[Employees] ([EmployeeID], [LastName], [FirstName], [Title], [TitleOfCourtesy], [BirthDate], [HireDate], [Address], [City], [Region], [PostalCode], [Country], [HomePhone], [Extension], [ReportsTo]) VALUES (3, N'Leverling', N'Janet', N'Sales Representative', N'Ms.', CAST(N'1963-08-30T00:00:00.000' AS DateTime), CAST(N'1992-04-01T00:00:00.000' AS DateTime), N'722 Moss Bay Blvd.', N'Kirkland', N'WA', N'98033', N'USA', N'(206) 555-3412', N'3355', 2)

INSERT [dbo].[Employees] ([EmployeeID], [LastName], [FirstName], [Title], [TitleOfCourtesy], [BirthDate], [HireDate], [Address], [City], [Region], [PostalCode], [Country], [HomePhone], [Extension], [ReportsTo]) VALUES (4, N'Peacock', N'Margaret', N'Sales Representative', N'Mrs.', CAST(N'1937-09-19T00:00:00.000' AS DateTime), CAST(N'1993-05-03T00:00:00.000' AS DateTime), N'4110 Old Redmond Rd.', N'Redmond', N'WA', N'98052', N'USA', N'(206) 555-8122', N'5176', 2)

INSERT [dbo].[Employees] ([EmployeeID], [LastName], [FirstName], [Title], [TitleOfCourtesy], [BirthDate], [HireDate], [Address], [City], [Region], [PostalCode], [Country], [HomePhone], [Extension], [ReportsTo]) VALUES (5, N'Buchanan', N'Steven', N'Sales Manager', N'Mr.', CAST(N'1955-03-04T00:00:00.000' AS DateTime), CAST(N'1993-10-17T00:00:00.000' AS DateTime), N'14 Garrett Hill', N'London', NULL, N'SW1 8JR', N'UK', N'(71) 555-4848', N'3453', 2)

INSERT [dbo].[Employees] ([EmployeeID], [LastName], [FirstName], [Title], [TitleOfCourtesy], [BirthDate], [HireDate], [Address], [City], [Region], [PostalCode], [Country], [HomePhone], [Extension], [ReportsTo]) VALUES (6, N'Suyama', N'Michael', N'Sales Representative', N'Mr.', CAST(N'1963-07-02T00:00:00.000' AS DateTime), CAST(N'1993-10-17T00:00:00.000' AS DateTime), N'Coventry House
Miner Rd.', N'London', NULL, N'EC2 7JR', N'UK', N'(71) 555-7773', N'428', 5)

INSERT [dbo].[Employees] ([EmployeeID], [LastName], [FirstName], [Title], [TitleOfCourtesy], [BirthDate], [HireDate], [Address], [City], [Region], [PostalCode], [Country], [HomePhone], [Extension], [ReportsTo]) VALUES (7, N'King', N'Robert', N'Sales Representative', N'Mr.', CAST(N'1960-05-29T00:00:00.000' AS DateTime), CAST(N'1994-01-02T00:00:00.000' AS DateTime), N'Edgeham Hollow
Winchester Way', N'London', NULL, N'RG1 9SP', N'UK', N'(71) 555-5598', N'465', 5)

INSERT [dbo].[Employees] ([EmployeeID], [LastName], [FirstName], [Title], [TitleOfCourtesy], [BirthDate], [HireDate], [Address], [City], [Region], [PostalCode], [Country], [HomePhone], [Extension], [ReportsTo]) VALUES (8, N'Callahan', N'Laura', N'Inside Sales Coordinator', N'Ms.', CAST(N'1958-01-09T00:00:00.000' AS DateTime), CAST(N'1994-03-05T00:00:00.000' AS DateTime), N'4726 - 11th Ave. N.E.', N'Seattle', N'WA', N'98105', N'USA', N'(206) 555-1189', N'2344', 2)

INSERT [dbo].[Employees] ([EmployeeID], [LastName], [FirstName], [Title], [TitleOfCourtesy], [BirthDate], [HireDate], [Address], [City], [Region], [PostalCode], [Country], [HomePhone], [Extension], [ReportsTo]) VALUES (9, N'Dodsworth', N'Anne', N'Sales Representative', N'Ms.', CAST(N'1966-01-27T00:00:00.000' AS DateTime), CAST(N'1994-11-15T00:00:00.000' AS DateTime), N'7 Houndstooth Rd.', N'London', NULL, N'WG2 7LT', N'UK', N'(71) 555-4444', N'452', 5)

SET IDENTITY_INSERT [dbo].[Employees] OFF
GO

ALTER TABLE [dbo].[Employees]  WITH NOCHECK ADD  CONSTRAINT [FK_Employees_Employees] FOREIGN KEY([ReportsTo])
REFERENCES [dbo].[Employees] ([EmployeeID])
GO

ALTER TABLE [dbo].[Employees] CHECK CONSTRAINT [FK_Employees_Employees]
GO

ALTER TABLE [dbo].[Employees]  WITH NOCHECK ADD  CONSTRAINT [CK_Birthdate] CHECK  (([BirthDate] < getdate()))
GO

ALTER TABLE [dbo].[Employees] CHECK CONSTRAINT [CK_Birthdate]
GO

The Employee table should look like the below:

Next create Entity Module.

After Creation of Entity, Employee class look like below

public partial class Employee
    {
        public Employee()
        {
            this.Employees1 = new HashSet<Employee>();
        }
    
        public int EmployeeID { get; set; }
        public string LastName { get; set; }
        public string FirstName { get; set; }
        public string Title { get; set; }
        public string TitleOfCourtesy { get; set; }
        public Nullable<System.DateTime> BirthDate { get; set; }
        public Nullable<System.DateTime> HireDate { get; set; }
        public string Address { get; set; }
        public string City { get; set; }
        public string Region { get; set; }
        public string PostalCode { get; set; }
        public string Country { get; set; }
        public string HomePhone { get; set; }
        public string Extension { get; set; }
        public Nullable<int> ReportsTo { get; set; }
        public string PhotoPath { get; set; }
    
        public virtual ICollection<Employee> Employees1 { get; set; }
        public virtual Employee Employee1 { get; set; }
    }

2. Now in the controller TreeviewController.cs

Note also, that the hasChildren uses a navigation property generated in the EF model (Employees1). That would be present if you have created a relation one-to-many from the Products table to itself.

public JsonResult Remote_Data_Binding_Get_Employees(int? id)
{			
  using (TelerikEntities entities = new TelerikEntities())
  {
     var data = from e in entities.Employees
     where (id.HasValue ? e.ReportsTo == id : e. ReportsTo == null)
      select new
       {
         id = e.EmployeeID,
         Name = e.FirstName,
         hasChildren = e.Employees1.Any()

       };
      return Json(data.ToList(), JsonRequestBehavior.AllowGet);
   }
}

In the Remote_Data_Binding_Get_Employees action of the TreeviewController.cs you will notice the yellow colored variables:

Note that as the Name field is used in the controller, the same should also be used in the TreeView in index.cstml file and make sure return of data in list.

3. In View index.cshtml

<div class="demo-section k-content">
        @(Html.Kendo().TreeView()
        .Name("treeview")
        .DataTextField("Name")
        .DataSource(dataSource => dataSource
            .Read(read => read
                .Action("Remote_Data_Binding_Get_Employees", "TreeView")
                )
        )
    )
</div>

In a above code we are doing remote data binding in .Action function we are passing “Method name” and “Controller name”.

Here is the hierarchical output we have acheived:-

Make reusable web controls with Angular and Telerik Kendo UI

Angular requires the use of the entire framework for it to work making it a takeover for the entire application being built. Web Components provide a specification by which we make these Angular components available for use with plain simple HTML. It is a web standard for defining new HTML elements in a framework-agnostic way.

Specifically, Angular elements are Angular components packaged as custom elements (also called Web Components).

One of the questions that our customers ask us is when they use Kendo UI is Angular Elements supported? The answer is a resounding yes and we detail a simple step by step to showcase this capability by using Kendo UI charts control:

1. Install Angular CLI and create a new project

npm i -g @angular/cli
ng new angular-custom-elements

2. Activate your Trial or commercial License

Kendo UI for Angular is a professionally developed library distributed under a commercial license. Starting from December 2020, using any of the UI components from the Kendo UI for Angular library requires either a commercial license key or an active trial license key.

After login in your telerik account Download your Telerik license key and Save the kendo-ui-license.txt license key file in the project folder.

Install or Update a License Key

  • Copy the license key file (kendo-ui-license.txt) to the root folder of your project. Alternatively, copy the contents of the file to the KENDO_UI_LICENSE environment variable.
  • Install @progress/kendo-licensing as a project dependency by running npm install --save @progress/kendo-licensing or yarn add @progress/kendo-licensing.
  • Run npx kendo-ui-license activate or yarn run kendo-ui-license activate in the console.

Adding the Kendo UI Components

Kendo UI for Angular is distributed as multiple NPM packages scoped to @progress. For example, the name of the Grid package is @progress/kendo-angular-grid. As of the Angular 6 release, Angular CLI introduces the ng add command which provides for a faster and more user-friendly package installation. For more information, refer to the article on using Kendo UI for Angular with Angular CLI.

3. Let’s start and add the Charts package:

Angular CLI supports the addition of packages through the ng add command which executes in one step the set of otherwise individually needed commands.

ng add @progress/kendo-angular-charts

The command installs all necessary packages, sets up the default theme, and imports the component module. The full set of applied changes can be seen by running git diff at any time.

Manual Setup

All components that you reference during the installation will be present in the final bundle of your application. To avoid ending up with components you do not actually need, either:

  • Import all Charts components at once by using the ChartsModule, or
  • Import a specific Charts component by adding it as an individual NgModule.

Download and install the package.

npm install --save @progress/kendo-angular-charts @progress/kendo-angular-common @progress/kendo-angular-intl @progress/kendo-angular-l10n @progress/kendo-angular-popup @progress/kendo-drawing hammerjs @progress/kendo-licensing

Once installed, import Hammer.js and the NgModule of the components you need.

To get all package components, import the ChartsModule in your [application root]({{ site.data.url.angular[‘ngmodules’] }}#angular-modularity) or feature module in app.module.ts.

3. Add elements package

Custom elements are a Web Platform feature currently supported by Chrome, Edge (Chromium-based), Firefox, Opera, and Safari, and available in other browsers through polyfills

ng add @angular/elements

4. Create a component

ng g component chart --inline-style --inline-template -v None

5. Add properties to the component

5. Update NgModule

6. Building the Angular Project for Production

ng build –prod –output-hashing=none

Now we need to create a build script(angular-elements-build.js) to produce only one JS file from the multiple files generated by the Angular CLI.

You need to install fs-extra and concat from npm using:

npm install fs-extra concat

7. In your root application, create a build script file and add below code, angular-element-build.js

const fs = require('fs-extra');
const concat  = require('concat');
(async function build() {
const files = [
'./dist/chart-custom-element/runtime.js',
'./dist/chart-custom-element/polyfills.js',
'./dist/chart-custom-element/main.js',
]
try{
await fs.ensureDir('angular-elements')
await fs.copy('./dist/chart-custom-element/styles.css','angular-elements/styles.css')
await concat(files,'angular-elements/chart-angular-element.js')
}catch(err){
console.log(err);
}
})()

7. run the script using below command.

node angular-element-build.js

The above command will create an angular-elements folder and chat-angular-element.js and copy styles.css file inside in angular-elements folder

8. Use the Angular Element in simple HTML

Add index.html file in angular-elements folder with below code:

<!DOCTYPE html>
<html lang="en">
<head>
    <base href="/">
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="icon" type="image/x-icon" href="favicon.ico">
    <link rel="stylesheet" href="styles.css" />
    <title>Testing our custom chart element</title>
</head>
<body>
    <div class="container">
        New component
        <app-chart></app-chart>
        <script type="text/javascript" src="chart-angular-element.js"></script>
        <script>
            let arr = [2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011];
            let arrseries = [{
                name: 'India',
                data: [3.907, 7.943, 7.848, 9.284, 9.263, 9.801, 3.890, 8.238, 9.552, 6.855]
            }, {
                name: 'Russian Federation',
                data: [4.743, 7.295, 7.175, 6.376, 8.153, 8.535, 5.247, -7.832, 4.3, 4.3]
            }, {
                name: 'Germany',
                data: [0.010, -0.375, 1.161, 0.684, 3.7, 3.269, 1.083, -5.127, 3.690, 2.995]
            }, {
                name: 'World',
                data: [1.988, 2.733, 3.994, 3.464, 4.001, 3.939, 1.333, -2.245, 4.339, 2.727]
            }]
            let title = "New Title"
            let querySelect = document.querySelector('app-chart');
            querySelect.categories = arr;
            querySelect.series = arrseries;
            querySelect.title = title;
        </script>
    </div>
</body>
</html>

Install live-server using below command:

npm install -g live-server

Navigate to your angular-element folder and run below command:

cd angular-element
npx live-server

Browser window will open with the URL http://localhost:8080/

Now you can see the angular component is working outside of the angular application.

Get Started with Kendo UI for Angular

Our customers enjoy building a good UI for their projects. They rely on Kendo UI to deliver an outstanding development experience along with the most popular JS framework of the modern web – Angular. Kendo UI for Angular is a professionally developed library distributed under a commercial license.

Some of them are not sure how to get started with Kendo UI for Angular. In the post below we detail how you can start using Kendo UI with Angular and include a Chart control:

First Step => Setting up the angular project

The easiest way to start with Angular is to use the Angular CLI Tool. To scaffold your project structure, follow its installation instructions.

npm install -g @angular/cli
ng new my-first-angular-project
cd my-first-angular-project

Second Step => Activate your Trial or commercial License

Starting from December 2020, using any of the UI components from the Kendo UI for Angular library requires either a commercial license key or an active trial license key.

After login in your telerik account Download your Telerik license key Next, save the kendo-ui-license.txt license key file in the project folder.

Install or Update a License Key

  • Copy the license key file (kendo-ui-license.txt) to the root folder of your project. Alternatively, copy the contents of the file to the KENDO_UI_LICENSE environment variable.
  • Install @progress/kendo-licensing as a project dependency by running npm install --save @progress/kendo-licensing or yarn add @progress/kendo-licensing.
  • Run npx kendo-ui-license activate or yarn run kendo-ui-license activate in the console.

Adding the Kendo UI Components

Kendo UI for Angular is distributed as multiple NPM packages scoped to @progress. For example, the name of the Grid package is @progress/kendo-angular-grid. As of the Angular 6 release, Angular CLI introduces the ng add command which provides for a faster and more user-friendly package installation. For more information, refer to the article on using Kendo UI for Angular with Angular CLI.

1. Let’s start and add the Charts package:

Angular CLI supports the addition of packages through the ng add command which executes in one step the set of otherwise individually needed commands.

ng add @progress/kendo-angular-charts

The command installs all necessary packages, sets up the default theme, and imports the component module. The full set of applied changes can be seen by running git diff at any time.

Manual Setup

All components that you reference during the installation will be present in the final bundle of your application. To avoid ending up with components you do not actually need, either:

  • Import all Charts components at once by using the ChartsModule, or
  • Import a specific Charts component by adding it as an individual NgModule.

Download and install the package.

npm install --save @progress/kendo-angular-charts @progress/kendo-angular-common @progress/kendo-angular-intl @progress/kendo-angular-l10n @progress/kendo-angular-popup @progress/kendo-drawing hammerjs @progress/kendo-licensing

Once installed, import Hammer.js and the NgModule of the components you need.

To get all package components, import the ChartsModule in your [application root]({{ site.data.url.angular[‘ngmodules’] }}#angular-modularity) or feature module in app.module.ts.

    import { NgModule } from '@angular/core';
    import { BrowserModule } from '@angular/platform-browser';
    import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
    import { ChartsModule } from '@progress/kendo-angular-charts';
    import { AppComponent } from './app.component';

    import 'hammerjs';

    @NgModule({
        bootstrap:    [AppComponent],
        declarations: [AppComponent],
        imports:      [BrowserModule, BrowserAnimationsModule, ChartsModule]
    })
    export class AppModule {
    }

and Use Chart in app.component.js

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  template:'<kendo-chart>
  <kendo-chart-title text="Units sold"></kendo-chart-title>
  <kendo-chart-category-axis>
      <kendo-chart-category-axis-item [categories]="['Q1', 'Q2', 'Q3', 'Q4']">
      </kendo-chart-category-axis-item>
  </kendo-chart-category-axis>
  <kendo-chart-series>
    <kendo-chart-series-item type="bar" [gap]="2" [spacing]=".25" [data]="[100, 123, 234, 343]">
    </kendo-chart-series-item>
    <kendo-chart-series-item type="bar" [data]="[120, 67, 231, 196]">
    </kendo-chart-series-item>
    <kendo-chart-series-item type="bar" [data]="[45, 124, 189, 143]">
    </kendo-chart-series-item>
    <kendo-chart-series-item type="bar" [data]="[87, 154, 210, 215]">
    </kendo-chart-series-item>
  </kendo-chart-series>
</kendo-chart>',
 
})
export class AppComponent {
  title = 'chart-sample';
}

Kendo UI for Angular provides themes that you can use to style your application.

Currently, the suite ships the following themes:

Let us know your experience getting started with Kendo UI in Angular…