How To Implement Dynamic Highchart With Angular V6 And ASP.NET Core

In this post, we are going to implement the dynamic high chart with Angular 6 and ASP.NET Core. In the previous article, we have explored how a Single Page Application (SPA) sample can be put together using ASP.NET Core & Angular from scratch.

Based on the previous post this article is extended to implement charting. We are going to modify/extend the existing sample application by downloading the full source code from GitHub.

Let’s get started by opening the existing application, first of all, we are going to add packages to our application.

Install Node Packages

Let’s add frontend packages to our application. We need to modify the package.json file. Open the package.json file, then add listed dependencies from below.

Dependencies    

  • "angular-highcharts": "^6.2.6",
  • "highcharts": "^6.1.1"

Dev Dependencies

  • "@types/highcharts": "^5.0.22",

Here’s our list of frontend package dependencies.

  1. {  
  2.   "version""1.0.0",  
  3.   "name""asp.net",  
  4.   "private"true,  
  5.   "dependencies": {  
  6.     "@angular/common""^6.0.2",  
  7.     "@angular/compiler""^6.0.2",  
  8.     "@angular/core""^6.0.2",  
  9.     "@angular/forms""^6.0.2",  
  10.     "@angular/http""^6.0.2",  
  11.     "@angular/platform-browser""^6.0.2",  
  12.     "@angular/platform-browser-dynamic""^6.0.2",  
  13.     "@angular/router""^6.0.2",  
  14.     "@angular/upgrade""^6.0.2",  
  15.     "bootstrap""^4.1.1",  
  16.     "core-js""^2.5.6",  
  17.     "reflect-metadata""^0.1.12",  
  18.     "rxjs""^6.1.0",  
  19.     "systemjs""^0.21.3",  
  20.     "zone.js""^0.8.26",  
  21.     "angular-highcharts""^6.2.6",  
  22.     "highcharts""^6.1.1"  
  23.   },  
  24.   "devDependencies": {  
  25.     "@types/core-js""^0.9.46",  
  26.     "typescript""^2.8.3",  
  27.     "typings""^2.1.1",  
  28.     "@types/node""^10.0.4",  
  29.     "@types/highcharts""^5.0.22",  
  30.     "concurrently""^3.5.1",  
  31.     "json-server""^0.12.2",  
  32.     "gulp""^3.9.1",  
  33.     "gulp-concat""^2.6.1",  
  34.     "gulp-rename""^1.2.2",  
  35.     "gulp-cssmin""^0.2.0",  
  36.     "gulp-uglify""^3.0.0",  
  37.     "gulp-htmlclean""^2.7.20",  
  38.     "rimraf""^2.6.2"  
  39.   }  
  40. }  

After installation all packages let’s transfer the required libraries from node_modules folder to “wwwroot/lib”.

Manage Installed Packages

We need to add the below listed task to a gulp file, which will transfer the newly added package libraries to “wwwroot/lib” folder.

  1. gulp.src('./node_modules/angular-highcharts/**/*.js')  
  2.     .pipe(gulp.dest(root_path.package_lib + 'angular-highcharts'));  
  3.   
  4. gulp.src('./node_modules/highcharts/**.js')  
  5.     .pipe(gulp.dest(root_path.package_lib + 'highcharts'));  

Here’s the modified gulp file.

  1. /// <binding AfterBuild='build-all' />  
  2.   
  3. var gulp = require("gulp"),  
  4.     rimraf = require("rimraf"),  
  5.     concat = require("gulp-concat"),  
  6.     cssmin = require("gulp-cssmin"),  
  7.     uglify = require("gulp-uglify"),  
  8.     rename = require("gulp-rename");  
  9.   
  10. var root_path = {  
  11.     webroot: "./wwwroot/"  
  12. };  
  13.   
  14. //library source  
  15. root_path.nmSrc = "./node_modules/";  
  16.   
  17. //library destination  
  18. root_path.package_lib = root_path.webroot + "lib/";  
  19.   
  20. gulp.task('copy-lib-js'function () {  
  21.   
  22.     gulp.src('./node_modules/core-js/**/*.js')  
  23.         .pipe(gulp.dest(root_path.package_lib + 'core-js'));  
  24.   
  25.     gulp.src('./node_modules/@angular/**/*.js')  
  26.         .pipe(gulp.dest(root_path.package_lib + '@angular'));  
  27.   
  28.     gulp.src('./node_modules/zone.js/**/*.js')  
  29.         .pipe(gulp.dest(root_path.package_lib + 'zone.js'));  
  30.   
  31.     gulp.src('./node_modules/systemjs/**/*.js')  
  32.         .pipe(gulp.dest(root_path.package_lib + 'systemjs'));  
  33.   
  34.     gulp.src('./node_modules/reflect-metadata/**/*.js')  
  35.         .pipe(gulp.dest(root_path.package_lib + 'reflect-metadata'));  
  36.   
  37.     gulp.src('./node_modules/rxjs/**.js')  
  38.         .pipe(gulp.dest(root_path.package_lib + 'rxjs'));  
  39.   
  40. gulp.src('./node_modules/angular-highcharts/**/*.js')  
  41.     .pipe(gulp.dest(root_path.package_lib + 'angular-highcharts'));  
  42.   
  43. gulp.src('./node_modules/highcharts/**.js')  
  44.     .pipe(gulp.dest(root_path.package_lib + 'highcharts'));  
  45. });  
  46.   
  47. gulp.task("copy-all", ["copy-lib-js"]);  
  48. //Copy End  
  49.   
  50. gulp.task('min-js'function () {  
  51.     gulp.src(['./clientapp/**/*.js'])  
  52.         .pipe(uglify())  
  53.         .pipe(gulp.dest(root_path.webroot + 'app'))  
  54. });  
  55.   
  56. gulp.task('copy-html'function () {  
  57.     gulp.src('clientapp/**/*.html')  
  58.         .pipe(gulp.dest(root_path.webroot + 'app'));  
  59. });  
  60.   
  61. gulp.task("build-all", ["min-js""copy-html"]);  
  62. //Build End  

Right click on gulpfile.js then go to “Task Runner Explorer”.

Dynamic Highchart - ASP.Net Core, Angular6

From the new window refresh, the task then right-clicks on the task to run it like below screen.

Dynamic Highchart - ASP.Net Core, Angular6

As we can see our required libraries are loaded in “wwwroot/lib” folder.

Dynamic Highchart - ASP.Net Core, Angular6

Before importing module we need to modify SystemJS by adding below listed bundle to System.config() function.

'angular-highcharts': 'npm:angular-highcharts/angular-highcharts.umd.js',

'highcharts': 'npm:highcharts/highcharts.src.js'

SystemJS Config - systemjs.config.js

  1. /** 
  2.  * System configuration for Angular samples 
  3.  * Adjust as necessary for your application needs. 
  4.  */  
  5. (function (global) {  
  6.     System.config({  
  7.         paths: {  
  8.             // paths serve as alias  
  9.             'npm:''/lib/'  
  10.         },  
  11.         // map tells the System loader where to look for things  
  12.         map: {  
  13.             // our app is within the app folder  
  14.             'app''app',  
  15.   
  16.             // angular bundles  
  17.             '@angular/core''npm:@angular/core/bundles/core.umd.js',  
  18.             '@angular/common''npm:@angular/common/bundles/common.umd.js',  
  19.             '@angular/compiler''npm:@angular/compiler/bundles/compiler.umd.js',  
  20.             '@angular/platform-browser''npm:@angular/platform-browser/bundles/platform-browser.umd.js',  
  21.             '@angular/platform-browser-dynamic''npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',  
  22.             '@angular/http''npm:@angular/http/bundles/http.umd.js',  
  23.             '@angular/router''npm:@angular/router/bundles/router.umd.js',  
  24.             '@angular/forms''npm:@angular/forms/bundles/forms.umd.js',  
  25.   
  26.             // highchart bundles  
  27.             'angular-highcharts''npm:angular-highcharts/angular-highcharts.umd.js',  
  28.             'highcharts''npm:highcharts/highcharts.src.js',  
  29.   
  30.             // other libraries  
  31.             'rxjs''npm:rxjs',  
  32.             'rxjs-compat''npm:rxjs-compat',  
  33.             'rxjs/operators''npm:rxjs/operators'  
  34.         },  
  35.         // packages tells the System loader how to load when no filename and/or no extension  
  36.         packages: {  
  37.             'app': {  
  38.                 main: 'main.js',  
  39.                 defaultExtension: 'js',  
  40.                 meta: {  
  41.                     '': {  
  42.                         format: 'cjs'  
  43.                     }  
  44.                 }  
  45.             },  
  46.             'rxjs': {  
  47.                 main: 'index.js',  
  48.                 defaultExtension: 'js'  
  49.             },  
  50.             'rxjs/operators': {  
  51.                 main: 'index.js',  
  52.                 defaultExtension: 'js'  
  53.             }  
  54.         }  
  55.     });  
  56. })(this);  

TypeScript Configuration

We need to add new types "highcharts" in compiler options, the below code snippet is for tsconfig.json file.

Configure Typescript - tsconfig.json

  1. {  
  2.   "compileOnSave"false,  
  3.   "compilerOptions": {  
  4.     "baseUrl""./",  
  5.     "sourceMap"true,  
  6.     "declaration"false,  
  7.     "moduleResolution""node",  
  8.     "emitDecoratorMetadata"true,  
  9.     "experimentalDecorators"true,  
  10.     "target""es5",  
  11.     "typeRoots": [  
  12.       "node_modules/@types"  
  13.     ],  
  14.     "lib": [  
  15.       "es2017",  
  16.       "dom"  
  17.     ],  
  18.     "types": [  
  19.       "core-js",  
  20.       "highcharts"  
  21.     ]  
  22.   },  
  23.   "includes": [  
  24.     "/**/*.ts"  
  25.   ]  
  26. }  

Root Module

Now, let’s import a newly added chart module component in module.ts.

  1. import { ChartModule } from 'angular-highcharts';  

Below is the updated code snippet for module.ts.

  1. import { NgModule } from '@angular/core';  
  2. import { BrowserModule } from '@angular/platform-browser';  
  3. import { Routes, RouterModule } from '@angular/router';  
  4. import { LocationStrategy, HashLocationStrategy } from '@angular/common';  
  5. import { FormsModule, ReactiveFormsModule } from '@angular/forms';  
  6. import { HttpModule } from '@angular/http';  
  7. import { ChartModule } from 'angular-highcharts';  
  8.   
  9. //Components  
  10. import { AppComponent } from './component/app/component';  
  11. import { HomeComponent } from './component/home/component';  
  12. import { AboutComponent } from './component/about/component';  
  13. import { UserComponent } from './component/user/component';  
  14. import { ChartComponent } from './component/chart/component';  
  15.   
  16. //Routes  
  17. const routes: Routes = [  
  18.     { path: '', redirectTo: 'home', pathMatch: 'full' },  
  19.     { path: 'home', component: HomeComponent },  
  20.     { path: 'about', component: AboutComponent },  
  21.     { path: 'user', component: UserComponent },  
  22.     { path: 'chart', component: ChartComponent }  
  23. ];  
  24.   
  25. @NgModule({  
  26.     imports: [BrowserModule, HttpModule, FormsModule, ReactiveFormsModule, RouterModule.forRoot(routes), ChartModule],  
  27.     declarations: [AppComponent, HomeComponent, AboutComponent, UserComponent, ChartComponent],  
  28.     bootstrap: [AppComponent]  
  29. })  
  30.   
  31. export class AppModule { }  

Next we will create SQL Database tables.

Creating Database

Let’s Create a Database in MSSQL Server. Here is the table where we are storing data. Run the below script in the query window to create a new database.

  1. CREATE DATABASE [dbCore]  

Creating Table

  1. USE [dbCore]  
  2. GO  
  3.   
  4. /****** Object:  Table [dbo].[User]    Script Date: 8/15/2018 9:22:00 AM ******/  
  5. SET ANSI_NULLS ON  
  6. GO  
  7.   
  8. SET QUOTED_IDENTIFIER ON  
  9. GO  
  10.   
  11. CREATE TABLE [dbo].[User](  
  12.     [Id] [int] IDENTITY(1,1) NOT NULL,  
  13.     [FirstName] [nvarchar](250) NULL,  
  14.     [LastName] [nvarchar](250) NULL,  
  15.     [Email] [nvarchar](250) NULL,  
  16.     [Phone] [nvarchar](50) NULL,  
  17.  CONSTRAINT [PK_User] PRIMARY KEY CLUSTERED   
  18. (  
  19.     [Id] ASC  
  20. )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ONON [PRIMARY]  
  21. ON [PRIMARY]  
  22. GO  
  23.   
  24. /****** Object:  Table [dbo].[UserMarks]    Script Date: 8/15/2018 9:22:00 AM ******/  
  25. SET ANSI_NULLS ON  
  26. GO  
  27.   
  28. SET QUOTED_IDENTIFIER ON  
  29. GO  
  30.   
  31. CREATE TABLE [dbo].[UserMarks](  
  32.     [id] [intNOT NULL,  
  33.     [userId] [intNULL,  
  34.     [mark] [decimal](18, 2) NULL,  
  35.  CONSTRAINT [PK_UserMarks] PRIMARY KEY CLUSTERED   
  36. (  
  37.     [id] ASC  
  38. )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ONON [PRIMARY]  
  39. ON [PRIMARY]  
  40. GO  

Scaffolding MSSQL Database

We are going to re-generate EF models from existing database using reverse engineering using command in Package Manager Console.

Dynamic Highchart - ASP.Net Core, Angular6

Command
Scaffold-DbContext "Server=DESKTOP-7OJNKVF;Database=dbCore;Trusted_Connection=True;" Microsoft.EntityFrameworkCore.SqlServer -Output serverapp/models -Force

As we can see from solution explorer models folder is created with Context & Entities.

Dynamic Highchart - ASP.Net Core, Angular6

Now, open the DbContext file then add a constructor to pass configuration like connectionstring into the DbContext.

  1. public dbCoreContext(DbContextOptions<dbCoreContext> options) : base(options)  
  2. {  
  3. }  
  4.   
  5. protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)  
  6. {  
  7.     //if (!optionsBuilder.IsConfigured)  
  8.     //{  
  9.     //    #warning To protect potentially sensitive information in your connection string, you should move it out of source code. See http://go.microsoft.com/fwlink/?LinkId=723263 for guidance on storing connection strings.  
  10.     //    optionsBuilder.UseSqlServer(@"Server=DESKTOP-7OJNKVF;Database=dbCore;Trusted_Connection=True;");  
  11.     //}  
  12. }  

Modify WebAPI

Add the below result function to existing web-api to retrieve result data from database.

  1. // GET: api/Values/GetResult  
  2. [HttpGet, Route("GetResult")]  
  3. public async Task<List<vmMarks>> GetResult()  
  4. {  
  5.     List<vmMarks> query = null;  
  6.   
  7.     try  
  8.     {  
  9.         using (_ctx)  
  10.         {  
  11.             query = await (from um in _ctx.UserMarks  
  12.                             join m in _ctx.User on um.UserId equals m.Id  
  13.                             select new vmMarks  
  14.                             {  
  15.                                 mid = (int)m.Id,  
  16.                                 mName = m.FirstName + " " + m.LastName,  
  17.                                 mMark = (decimal)um.Mark  
  18.                             }).OrderByDescending(x => x.mMark).ToListAsync();  
  19.         }  
  20.     }  
  21.     catch (Exception ex)  
  22.     {  
  23.         ex.ToString();  
  24.     }  
  25.   
  26.     return query;  
  27. }   

All right, our WebAPI is modified and ready to retrieve data. Our next step is to prepare client model, component and services to interact with WebAPIs.

Let’s create a TypeScript model class, then use it in another component by importing it:

  1. //Model  
  2. import { ResultModel } from './model';  

Typescript Model - ResultModel

  1. export class ResultModel {  
  2.     mid: number;  
  3.     mName: string;  
  4.     mMark: any;  
  5. }  

Component - ChartComponent

  1. import { Component } from '@angular/core';  
  2. import { ResultModel } from './model';  
  3. import { ResultService } from './service';  
  4. import { Chart } from 'angular-highcharts';  
  5.   
  6. @Component({  
  7.     selector: 'chart',  
  8.     templateUrl: './app/component/chart/chart.html',  
  9.     providers: [ResultService]  
  10. })  
  11.   
  12. export class ChartComponent {  
  13.     public marks: ResultModel[];  
  14.     public chart: Chart;  
  15.   
  16.     title: string;  
  17.     constructor(private resService: ResultService) {  
  18.         this.title = ''  
  19.     }  
  20.   
  21.     ngOnInit() {  
  22.         this.getChart();  
  23.     }  
  24.   
  25.     //Get All   
  26.     getChart() {  
  27.   
  28.         //debugger  
  29.         this.resService.getall().subscribe(  
  30.             response => {  
  31.                 this.marks = response;  
  32.                 let chartData = [];  
  33.                 for (var i = 0; i < this.marks.length; i++) {  
  34.                     chartData.push({  
  35.                         "name"this.marks[i].mName,  
  36.                         "y"this.marks[i].mMark,  
  37.                         sliced: true,  
  38.                         selected: true  
  39.                     })  
  40.                 }  
  41.   
  42.                 this.chart = new Chart({  
  43.                     chart: {  
  44.                         plotBackgroundColor: null,  
  45.                         plotBorderWidth: null,  
  46.                         plotShadow: false,  
  47.                         type: 'pie',  
  48.                         backgroundColor: null,  
  49.                         options3d: {  
  50.                             enabled: true,  
  51.                             alpha: 45,  
  52.                             beta: 0  
  53.                         }  
  54.                     },  
  55.                     title: {  
  56.                         text: 'Angular-6 + Highcharts-6',  
  57.                     },  
  58.                     subtitle: {  
  59.                         text: 'Result Pie-Chart!'  
  60.                     },  
  61.                     tooltip: {  
  62.                         pointFormat: '{series.name}: <b>{point.y}</b>'  
  63.                     },  
  64.                     plotOptions: {  
  65.                         pie: {  
  66.                             allowPointSelect: true,  
  67.                             cursor: 'pointer',  
  68.                             depth: 35,  
  69.                             dataLabels: {  
  70.                                 enabled: true,  
  71.                                 format: '<b>{point.name}</b>: {point.percentage:.1f} %'  
  72.                             }  
  73.                         }  
  74.                     },  
  75.                     series: [{  
  76.                         name: 'Total Mark',  
  77.                         data: chartData  
  78.                     }]  
  79.                 });  
  80.   
  81.             }, error => {  
  82.                 console.log(error);  
  83.             }  
  84.         );  
  85.     }  
  86. }  

Http Client Services - ResultService

  1. import { Injectable, Component } from '@angular/core';  
  2. import { HttpModule, Http, Request, RequestMethod, Response, RequestOptions, Headers } from '@angular/http';  
  3. import { Observable, Subject, ReplaySubject } from 'rxjs';  
  4. import { map, catchError } from 'rxjs/operators';  
  5.   
  6. //Model  
  7. import { ResultModel } from './model';  
  8.   
  9. @Component({  
  10.     providers: [Http]  
  11. })  
  12.   
  13. @Injectable()  
  14.   
  15. export class ResultService {  
  16.     public headers: Headers;  
  17.     public _getUrl: string = '/api/Values/GetResult';  
  18.   
  19.     constructor(private _http: Http) { }  
  20.   
  21.     //Get  
  22.     getall(): Observable<ResultModel[]> {  
  23.         return this._http.get(this._getUrl)  
  24.             .pipe(map(res => <ResultModel[]>res.json()))  
  25.             .pipe(catchError(this.handleError));  
  26.     }  
  27.   
  28.   
  29.     private handleError(error: Response) {  
  30.         return Observable.throw(error.json().error || 'Opps!! Server error');  
  31.     }  
  32. }  

Http View - chart.html

  1. <div class="container-fluid">  
  2.     <div class="row">  
  3.         <h2>{{title}}</h2>  
  4.         <div [chart]="chart"></div>  
  5.     </div>  
  6. </div>  

Test in Browser

Now, it’s time to build & run the application, go to chart menu, as we can see from the below screenshot, a pie chart is generated dynamically.

Dynamic Highchart - ASP.Net Core, Angular6

Summary

In this sample, we had to combine ASP.NET Core & Angular to create the sample SPA app without any CLI, and learned how to start with an empty ASP.NET Core application to serve a static HTML page.

We also had a  deep dive into the latest frontend technology like Angular 6 from scratch to build a single page application. We had a short overview on Angular 6 dependencies & also learned about the module and components. Then we performed some database operation using our sample application. Finally, we have implemented Dynamic Highchart. I hope this will help.