Web Client Application
Bootstrap the frontend application
In this section, you will use Angular 8 to create the frontend application project.
If you do not have Angular CLI installed on your machine, open a terminal window and run npm install -g @angular/cli@8
. This will install the version 8 of Angular.
To create the frontend application
- In a terminal, navigate to the same root directory as the backend application directory.
- Run
ng new events-ui
and accept the defaults. This creates the frontend project directory named events-ui and installs Angular8 dependencies. - Open the project directory in your favorite frontend IDE.
- Create or edit the following folders and files in the project directory:
- /src/app/model directory - to create
- /src/environments directory - to edit
- /src/app/component directory - to create
- /src/app/app.module.ts file - to edit
Model
To implement the model
- Create a directory named model
- In the model directory create the event.ts file which defines the event received on the web-socket.
- Write the following code for the event class:
export class Event {
tenant: string;
eventTime: string;
}
Environment
The environments directory is created by default at the ng new
command. It contains 2 files:
- environment.ts - the default configuration file with the default environment settings
- environment.prod.ts - the production specific configuration file
To edit the environment.ts
file
- Open environment.ts and copy the following code in it:
export const environment = {
production: false,
apiEndpoint: '<%WEBSOCKET-URL%>'
; }
- Replace
<%WEBSOCKET-URL%>
with the public web socket endpoint of the events-application server app. For examplehttp://localhost:8080/socket
, if the app is running on localhost.
Component
To implement the component
directory
- Create a component directory named component
- By default, Angular8 creates component files. Their names start with app.component. Move the following types of component files to the previously created directory:
- app.component.ts - which stores the service that initiates web-socket and receives events on it
- app.component.html - which stores the display of the component
- app.component.css - which stores the style for the component
- Write the following code for the app.component.ts:
Component({
@selector: 'app-root',
templateUrl: 'app.component.html',
styleUrls: ['app.component.css'],
providers: [],
})export class EventComponent implements OnInit {
event: Event;
_eventSubscription: ISubscription;
= environment.apiEndpoint;
serverUrl stompClient: any;
connect() {
const socket = new SockJS(this.serverUrl);
this.stompClient = Stomp.over(socket);
const _this = this;
this.stompClient.connect({}, function (frame: any) {
console.log('Connected: ' + frame);
.stompClient.subscribe('/clock/event', function (data: any) {
_this.event = JSON.parse(data.body);
_this;
});
})
}
constructor() { }
ngOnInit() {
this.event = new Event();
this.event.tenant = 'N/A';
this.event.eventTime = 'N/A';
this.connect();
}
ngOnDestroy() {
this._eventSubscription.unsubscribe();
}
}
- Import the required packages for app.component.ts above the class declaration.
import { Component, OnInit } from '@angular/core';
import { Event } from '../model/event';
import { ISubscription } from 'rxjs/Subscription';
import * as Stomp from 'stompjs';
import * as SockJS from 'sockjs-client';
import { environment } from '../../environments/environment';
- Write the following code for the app.component.html:
<div class="event-container">
<mat-form-field>
<input matInput [disabled]="true" placeholder="Tenant" value="{{ event.tenant }}">
</mat-form-field>
<mat-form-field>
<input matInput [disabled]="true" placeholder="EventTime" value="{{ event.eventTime }}">
</mat-form-field>
</div>
- Write the following code for the app.component.css:
.event-container {
display: flex;
flex-direction: column;
}
.event-container > * {
width: 100%;
}
Application Module
The module file stores the links to other modules and the imports for the frontend application.
To edit the app.module.ts
file
- Open the typescript file named app.module.ts
- Write the following code for the app.module.ts
NgModule({
@exports: [
,
A11yModule,
CdkStepperModule,
CdkTableModule,
CdkTreeModule,
DragDropModule,
MatAutocompleteModule,
MatBadgeModule,
MatBottomSheetModule,
MatButtonModule,
MatButtonToggleModule,
MatCardModule,
MatCheckboxModule,
MatChipsModule,
MatStepperModule,
MatDatepickerModule,
MatDialogModule,
MatDividerModule,
MatExpansionModule,
MatGridListModule,
MatIconModule,
MatInputModule,
MatListModule,
MatMenuModule,
MatNativeDateModule,
MatPaginatorModule,
MatProgressBarModule,
MatProgressSpinnerModule,
MatRadioModule,
MatRippleModule,
MatSelectModule,
MatSidenavModule,
MatSliderModule,
MatSlideToggleModule,
MatSnackBarModule,
MatSortModule,
MatTableModule,
MatTabsModule,
MatToolbarModule,
MatTooltipModule,
MatTreeModule,
PortalModule,
ScrollingModule
]
})export class DemoMaterialModule {}
- Import all the required libraries and modules:
import {NgModule} from '@angular/core';
import {A11yModule} from '@angular/cdk/a11y';
import {DragDropModule} from '@angular/cdk/drag-drop';
import {PortalModule} from '@angular/cdk/portal';
import {ScrollingModule} from '@angular/cdk/scrolling';
import {CdkStepperModule} from '@angular/cdk/stepper';
import {CdkTableModule} from '@angular/cdk/table';
import {CdkTreeModule} from '@angular/cdk/tree';
import {MatAutocompleteModule} from '@angular/material/autocomplete';
import {MatBadgeModule} from '@angular/material/badge';
import {MatBottomSheetModule} from '@angular/material/bottom-sheet';
import {MatButtonModule} from '@angular/material/button';
import {MatButtonToggleModule} from '@angular/material/button-toggle';
import {MatCardModule} from '@angular/material/card';
import {MatCheckboxModule} from '@angular/material/checkbox';
import {MatChipsModule} from '@angular/material/chips';
import {MatStepperModule} from '@angular/material/stepper';
import {MatDatepickerModule} from '@angular/material/datepicker';
import {MatDialogModule} from '@angular/material/dialog';
import {MatDividerModule} from '@angular/material/divider';
import {MatExpansionModule} from '@angular/material/expansion';
import {MatGridListModule} from '@angular/material/grid-list';
import {MatIconModule} from '@angular/material/icon';
import {MatInputModule} from '@angular/material/input';
import {MatListModule} from '@angular/material/list';
import {MatMenuModule} from '@angular/material/menu';
import {MatNativeDateModule, MatRippleModule} from '@angular/material/core';
import {MatPaginatorModule} from '@angular/material/paginator';
import {MatProgressBarModule} from '@angular/material/progress-bar';
import {MatProgressSpinnerModule} from '@angular/material/progress-spinner';
import {MatRadioModule} from '@angular/material/radio';
import {MatSelectModule} from '@angular/material/select';
import {MatSidenavModule} from '@angular/material/sidenav';
import {MatSliderModule} from '@angular/material/slider';
import {MatSlideToggleModule} from '@angular/material/slide-toggle';
import {MatSnackBarModule} from '@angular/material/snack-bar';
import {MatSortModule} from '@angular/material/sort';
import {MatTableModule} from '@angular/material/table';
import {MatTabsModule} from '@angular/material/tabs';
import {MatToolbarModule} from '@angular/material/toolbar';
import {MatTooltipModule} from '@angular/material/tooltip';
import {MatTreeModule} from '@angular/material/tree';
Edit Other Angular Default Files
For the frontend application to work, you need to edit some of the default angular files, created by the ng new name-of-the-app
command.
Find the files that need editing in the src/ directory:
- main.ts - the main entry point for your app. Compiles the application with the JIT compiler and bootstraps the application’s root module AppModule to run in the browser.
import './polyfills';
import {HttpClientModule} from '@angular/common/http';
import {NgModule} from '@angular/core';
import {FormsModule, ReactiveFormsModule} from '@angular/forms';
import {MatNativeDateModule} from '@angular/material/core';
import {BrowserModule} from '@angular/platform-browser';
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
import {NoopAnimationsModule} from '@angular/platform-browser/animations';
import {DemoMaterialModule} from './app/app.module';
import {EventComponent} from './app/component/app.component';
NgModule({
@imports: [
,
BrowserModule,
NoopAnimationsModule,
FormsModule,
HttpClientModule,
DemoMaterialModule,
MatNativeDateModule,
ReactiveFormsModule,
]entryComponents: [EventComponent],
declarations: [EventComponent],
bootstrap: [EventComponent],
providers: []
})export class AppModule {}
platformBrowserDynamic().bootstrapModule(AppModule);
- polyfills.ts - the polyfill scripts that make the application compatible with different browsers
import 'zone.js/dist/zone';
import 'hammerjs';
window as any).global = window; (
- styles.css - the global style file
@use '@angular/material/prebuilt-themes/deeppurple-amber.css';
body {font-family: Roboto, Arial, sans-serif;
margin: 0;
}.basic-container {
padding: 30px;
}.version-info {
font-size: 8pt;
float: right;
}
- index.html - the main HTML page that is served when you access the default port.
<!doctype html>
<html>
<head>
<title>Event Notifications</title>
</head>
<body>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons&display=block" rel="stylesheet">
<div class="mat-app-background basic-container">
<app-root></app-root>
</div>
</body>
</html>
- angular.json - CLI configuration defaults for all projects in the workspace, including configuration options for build, serve, and test tools that the CLI uses
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"events-ui": {
"projectType": "application",
"schematics": {},
"root": "",
"sourceRoot": "src",
"prefix": "app",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"outputPath": "dist/events-ui",
"index": "src/index.html",
"main": "src/main.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.app.json",
"aot": false,
"assets": [
"src/favicon.ico",
"src/assets"
],
"styles": [
"src/styles.css"
],
"scripts": []
},
"configurations": {
"production": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"extractCss": true,
"namedChunks": false,
"aot": true,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true,
"budgets": [
{
"type": "initial",
"maximumWarning": "2mb",
"maximumError": "5mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "6kb",
"maximumError": "10kb"
}
]
}
}
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "events-ui:build"
},
"configurations": {
"production": {
"browserTarget": "events-ui:build:production"
}
}
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "events-ui:build"
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "src/test.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.spec.json",
"karmaConfig": "karma.conf.js",
"assets": [
"src/favicon.ico",
"src/assets"
],
"styles": [
"src/styles.css"
],
"scripts": []
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": [
"tsconfig.app.json",
"tsconfig.spec.json",
"e2e/tsconfig.json"
],
"exclude": [
"**/node_modules/**"
]
}
},
"e2e": {
"builder": "@angular-devkit/build-angular:protractor",
"options": {
"protractorConfig": "e2e/protractor.conf.js",
"devServerTarget": "events-ui:serve"
},
"configurations": {
"production": {
"devServerTarget": "events-ui:serve:production"
}
}
}
}
}},
"defaultProject": "events-ui"
}
This UI application was built with Angular 8.2.9 version. Using a greater version may lead to conflicts for the imports of dependencies and modules. To resolve the conflicts, modify the package.json file as follows and run
npm install
after saving the file.
- package.json - the npm package dependencies that are available to all projects in the workspace
{"name": "events-ui",
"version": "0.0.0",
"license": "MIT",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
,
}"private": true,
"dependencies": {
"@angular/animations": "^8.2.9",
"@angular/cdk": "~8.2.2",
"@angular/common": "^8.2.9",
"@angular/compiler": "^8.2.9",
"@angular/core": "^8.2.9",
"@angular/forms": "^8.2.9",
"@angular/material": "~8.2.2",
"@angular/material-moment-adapter": "~8.2.2",
"@angular/platform-browser": "^8.2.9",
"@angular/platform-browser-dynamic": "^8.2.9",
"@angular/router": "^8.2.9",
"@types/jquery": "^3.3.31",
"@types/sockjs-client": "^1.1.1",
"@types/stompjs": "^2.3.4",
"angular-in-memory-web-api": "~0.9.0",
"core-js": "^2.6.9",
"hammerjs": "^2.0.8",
"jquery": "^3.4.1",
"moment": "^2.24.0",
"net": "^1.0.2",
"rxjs": "^6.5.3",
"rxjs-compat": "^6.5.3",
"sockjs-client": "^1.4.0",
"stompjs": "^2.3.3",
"tslib": "^1.10.0",
"zone.js": "~0.9.1"
,
}"devDependencies": {
"@angular-devkit/build-angular": "^0.803.23",
"@angular/cli": "^8.3.15",
"@angular/compiler-cli": "^8.2.9",
"@angular/language-service": "^8.2.9",
"@types/jasmine": "~3.3.8",
"@types/jasminewd2": "~2.0.3",
"@types/node": "~8.9.4",
"codelyzer": "^5.0.0",
"jasmine-core": "~3.4.0",
"jasmine-spec-reporter": "~4.2.1",
"karma": "~4.1.0",
"karma-chrome-launcher": "~2.2.0",
"karma-coverage-istanbul-reporter": "~2.0.1",
"karma-jasmine": "~2.0.1",
"karma-jasmine-html-reporter": "^1.4.0",
"protractor": "~5.4.0",
"ts-node": "~7.0.0",
"tslint": "~5.15.0",
"typescript": "^3.5.3"
} }
This is how your frontend project should look like at the end: