In this post, we are going to implement dynamic highchart with Angular6 and Asp.net Core. In the previous article we have explore how a Single Page Application (SPA) sample can be put together using ASP.Net Core & Angular from scratch.
Based on previous post this article is extended to implement charting. We are going to modify/extend existing sample application by downloading full source code from .
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 package.json file. Open package.json file then add listed dependencies from below.
Dependencies:
"angular-highcharts": "^6.2.6", "highcharts": "^6.1.1"
Dev Dependencies
"/highcharts": "^5.0.22",
Here’s our list of frontend package dependencies.
{ "version": "1.0.0", "name": "asp.net", "private": true, "dependencies": { "/common": "^6.0.2", "/compiler": "^6.0.2", "/core": "^6.0.2", "/forms": "^6.0.2", "/http": "^6.0.2", "/platform-browser": "^6.0.2", "/platform-browser-dynamic": "^6.0.2", "/router": "^6.0.2", "/upgrade": "^6.0.2", "bootstrap": "^4.1.1", "core-js": "^2.5.6", "reflect-metadata": "^0.1.12", "rxjs": "^6.1.0", "systemjs": "^0.21.3", "zone.js": "^0.8.26", "angular-highcharts": "^6.2.6", "highcharts": "^6.1.1" }, "devDependencies": { "/core-js": "^0.9.46", "typescript": "^2.8.3", "typings": "^2.1.1", "/node": "^10.0.4", "/highcharts": "^5.0.22", "concurrently": "^3.5.1", "json-server": "^0.12.2", "gulp": "^3.9.1", "gulp-concat": "^2.6.1", "gulp-rename": "^1.2.2", "gulp-cssmin": "^0.2.0", "gulp-uglify": "^3.0.0", "gulp-htmlclean": "^2.7.20", "rimraf": "^2.6.2" } }
After installation all packages let’s transfer the required libraries from node_modules folder to “wwwroot/lib”.
Manage Installed Packages:
We need to add below listed task to gulp file, which will transfer the newly added package libraries to “wwwroot/lib” folder.
gulp.src('./node_modules/angular-highcharts/**/*.js') .pipe(gulp.dest(root_path.package_lib + 'angular-highcharts')); gulp.src('./node_modules/highcharts/**.js') .pipe(gulp.dest(root_path.package_lib + 'highcharts'));
Here’s the modified gulp file.
///var gulp = require("gulp"), rimraf = require("rimraf"), concat = require("gulp-concat"), cssmin = require("gulp-cssmin"), uglify = require("gulp-uglify"), rename = require("gulp-rename"); var root_path = { webroot: "./wwwroot/" }; //library source root_path.nmSrc = "./node_modules/"; //library destination root_path.package_lib = root_path.webroot + "lib/"; gulp.task('copy-lib-js', function () { gulp.src('./node_modules/core-js/**/*.js') .pipe(gulp.dest(root_path.package_lib + 'core-js')); gulp.src('./node_modules//**/*.js') .pipe(gulp.dest(root_path.package_lib + '')); gulp.src('./node_modules/zone.js/**/*.js') .pipe(gulp.dest(root_path.package_lib + 'zone.js')); gulp.src('./node_modules/systemjs/**/*.js') .pipe(gulp.dest(root_path.package_lib + 'systemjs')); gulp.src('./node_modules/reflect-metadata/**/*.js') .pipe(gulp.dest(root_path.package_lib + 'reflect-metadata')); gulp.src('./node_modules/rxjs/**.js') .pipe(gulp.dest(root_path.package_lib + 'rxjs')); gulp.src('./node_modules/angular-highcharts/**/*.js') .pipe(gulp.dest(root_path.package_lib + 'angular-highcharts')); gulp.src('./node_modules/highcharts/**.js') .pipe(gulp.dest(root_path.package_lib + 'highcharts')); }); gulp.task("copy-all", ["copy-lib-js"]); //Copy End gulp.task('min-js', function () { gulp.src(['./clientapp/**/*.js']) .pipe(uglify()) .pipe(gulp.dest(root_path.webroot + 'app')) }); gulp.task('copy-html', function () { gulp.src('clientapp/**/*.html') .pipe(gulp.dest(root_path.webroot + 'app')); }); gulp.task("build-all", ["min-js", "copy-html"]); //Build End
Right click on gulpfile.js then go to “Task Runner Explorer”.
From the new window refresh the task then right click on task to run it like below screen.
As we can see our required libraries are loaded in “wwwroot/lib” folder.
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
/** * System configuration for Angular samples * Adjust as necessary for your application needs. */ (function (global) { System.config({ paths: { // paths serve as alias 'npm:': '/lib/' }, // map tells the System loader where to look for things map: { // our app is within the app folder 'app': 'app', // angular bundles '/core': 'npm:/core/bundles/core.umd.js', '/common': 'npm:/common/bundles/common.umd.js', '/compiler': 'npm:/compiler/bundles/compiler.umd.js', '/platform-browser': 'npm:/platform-browser/bundles/platform-browser.umd.js', '/platform-browser-dynamic': 'npm:/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js', '/http': 'npm:/http/bundles/http.umd.js', '/router': 'npm:/router/bundles/router.umd.js', '/forms': 'npm:/forms/bundles/forms.umd.js', // highchart bundles 'angular-highcharts': 'npm:angular-highcharts/angular-highcharts.umd.js', 'highcharts': 'npm:highcharts/highcharts.src.js', // other libraries 'rxjs': 'npm:rxjs', 'rxjs-compat': 'npm:rxjs-compat', 'rxjs/operators': 'npm:rxjs/operators' }, // packages tells the System loader how to load when no filename and/or no extension packages: { 'app': { main: 'main.js', defaultExtension: 'js', meta: { '': { format: 'cjs' } } }, 'rxjs': { main: 'index.js', defaultExtension: 'js' }, 'rxjs/operators': { main: 'index.js', defaultExtension: 'js' } } }); })(this);
TypeScript Configuration:
We need to add new types “highcharts” in compiler options, below code snippet is for tsconfig.json file.
Configure Typescript : tsconfig.json
{ "compileOnSave": false, "compilerOptions": { "baseUrl": "./", "sourceMap": true, "declaration": false, "moduleResolution": "node", "emitDecoratorMetadata": true, "experimentalDecorators": true, "target": "es5", "typeRoots": [ "node_modules/" ], "lib": [ "es2017", "dom" ], "types": [ "core-js", "highcharts" ] }, "includes": [ "/**/*.ts" ] }
Root Module:
Now let’s import newly added chart module, component in module.ts.
import { ChartModule } from 'angular-highcharts';
Below is the updated code snippet in module.ts.
import { NgModule } from '/core'; import { BrowserModule } from '/platform-browser'; import { Routes, RouterModule } from '/router'; import { LocationStrategy, HashLocationStrategy } from '/common'; import { FormsModule, ReactiveFormsModule } from '/forms'; import { HttpModule } from '/http'; import { ChartModule } from 'angular-highcharts'; //Components import { AppComponent } from './component/app/component'; import { HomeComponent } from './component/home/component'; import { AboutComponent } from './component/about/component'; import { UserComponent } from './component/user/component'; import { ChartComponent } from './component/chart/component'; //Routes const routes: Routes = [ { path: '', redirectTo: 'home', pathMatch: 'full' }, { path: 'home', component: HomeComponent }, { path: 'about', component: AboutComponent }, { path: 'user', component: UserComponent }, { path: 'chart', component: ChartComponent } ]; ({ imports: [BrowserModule, HttpModule, FormsModule, ReactiveFormsModule, RouterModule.forRoot(routes), ChartModule], declarations: [AppComponent, HomeComponent, AboutComponent, UserComponent, ChartComponent], bootstrap: [AppComponent] }) 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 below script in query window to create new database.
CREATE DATABASE [dbCore]
Creating Table:
USE [dbCore] GO /****** Object: Table [dbo].[User] Script Date: 8/15/2018 9:22:00 AM ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE TABLE [dbo].[User]( [Id] [int] IDENTITY(1,1) NOT NULL, [FirstName] [nvarchar](250) NULL, [LastName] [nvarchar](250) NULL, [Email] [nvarchar](250) NULL, [Phone] [nvarchar](50) NULL, CONSTRAINT [PK_User] PRIMARY KEY CLUSTERED ( [Id] 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 /****** Object: Table [dbo].[UserMarks] Script Date: 8/15/2018 9:22:00 AM ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE TABLE [dbo].[UserMarks]( [id] [int] NOT NULL, [userId] [int] NULL, [mark] [decimal](18, 2) NULL, CONSTRAINT [PK_UserMarks] PRIMARY KEY CLUSTERED ( [id] 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
Scaffolding MSSQL Database:
We are going to re-generate EF models from existing database using reverse engineering using command in Package Manager Console.
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.
Now open the DbContext file then add a constructor to pass configuration like connectionstring into the DbContext.
public dbCoreContext(DbContextOptionsoptions) : base(options) { } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { //if (!optionsBuilder.IsConfigured) //{ // #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. // optionsBuilder.UseSqlServer(@"Server=DESKTOP-7OJNKVF;Database=dbCore;Trusted_Connection=True;"); //} }
Modify WebAPI:
Add below result function to existing web-api to retrieve result data from database.
// GET: api/Values/GetResult [HttpGet, Route("GetResult")] public async Task> GetResult() { List
query = null; try { using (_ctx) { query = await (from um in _ctx.UserMarks join m in _ctx.User on um.UserId equals m.Id select new vmMarks { mid = (int)m.Id, mName = m.FirstName + " " + m.LastName, mMark = (decimal)um.Mark }).OrderByDescending(x => x.mMark).ToListAsync(); } } catch (Exception ex) { ex.ToString(); } return query; }
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 WebAPI’s.
Let’s create a typescript model class, then use it in another component by importing like
//Model import { ResultModel } from './model';
Typescript Model : ResultModel
export class ResultModel { mid: number; mName: string; mMark: any; }
Component : ChartComponent
import { Component } from '/core'; import { ResultModel } from './model'; import { ResultService } from './service'; import { Chart } from 'angular-highcharts'; ({ selector: 'chart', templateUrl: './app/component/chart/chart.html', providers: [ResultService] }) export class ChartComponent { public marks: ResultModel[]; public chart: Chart; title: string; constructor(private resService: ResultService) { this.title = '' } ngOnInit() { this.getChart(); } //Get All getChart() { //debugger this.resService.getall().subscribe( response => { this.marks = response; let chartData = []; for (var i = 0; i < this.marks.length; i++) { chartData.push({ "name": this.marks[i].mName, "y": this.marks[i].mMark, sliced: true, selected: true }) } this.chart = new Chart({ chart: { plotBackgroundColor: null, plotBorderWidth: null, plotShadow: false, type: 'pie', backgroundColor: null, options3d: { enabled: true, alpha: 45, beta: 0 } }, title: { text: 'Angular-6 + Highcharts-6', }, subtitle: { text: 'Result Pie-Chart!' }, tooltip: { pointFormat: '{series.name}: {point.y}' }, plotOptions: { pie: { allowPointSelect: true, cursor: 'pointer', depth: 35, dataLabels: { enabled: true, format: '{point.name}: {point.percentage:.1f} %' } } }, series: [{ name: 'Total Mark', data: chartData }] }); }, error => { console.log(error); } ); } }
Http Client Services : ResultService
import { Injectable, Component } from '/core'; import { HttpModule, Http, Request, RequestMethod, Response, RequestOptions, Headers } from '/http'; import { Observable, Subject, ReplaySubject } from 'rxjs'; import { map, catchError } from 'rxjs/operators'; //Model import { ResultModel } from './model'; ({ providers: [Http] }) () export class ResultService { public headers: Headers; public _getUrl: string = '/api/Values/GetResult'; constructor(private _http: Http) { } //Get getall(): Observable{ return this._http.get(this._getUrl) .pipe(map(res => res.json())) .pipe(catchError(this.handleError)); } private handleError(error: Response) { return Observable.throw(error.json().error || 'Opps!! Server error'); } }
Http View : chart.html
{{title}}
Test in Browser:
Now it’s time to build & run the application, go to chart menu, as we can see from below screenshot pie chart is generated dynamically.
Summary:
In this sample we have combine ASP.Net Core & Angular to create the sample SPA app without any CLI, learn how to start with an empty ASP.Net Core application to serve static html page.
We also have deep dive into latest frontend technology like Angular6 from scratch to build a single page application. Have a short overview on Angular6 dependencies & also have ideas of module, components. Then we have perform some database operation using our sample application. Finally we have implemented Dynamic Highchart. Hope this will help.
Downloads:
I’ve uploaded the full source code to download/clone , Thanks 🙂
Dynamic Highstock Chart – SHASHANGKA SHEKHAR'S BLOG says:
[…] In this post, we are going to implement dynamic Highstock chart with Angular8 and ASP.Net Core. Previous post on Highchart will help, please have an overview by following the link: https://shashangka.com/2018/06/15/dynamic-highchart-asp-net-core-angular6 […]