Angular

Angular is a platform and framework for building single-page client applications (SPA) in HTML and typescript.

The architecture of an Angular application relies on certain fundamental concepts. The basic building blocks are NgModules, which provide a compilation context for components.

Concepts from AngularJS

MVVM

In Angular (MVVM)(MVC)

Model–view–viewmodel is also referred to as model–view–binder, especially in implementations not involving the .NET platform

MVVM facilitates a separation of development of the graphical user interface – be it via a markup language or GUI code – from development of the business logic or back-end logic (the data model).

The view model of MVVM is a value converter,[1] meaning the view model is responsible for exposing (converting) the data objects from the model in such a way that objects are easily managed and presented.

View Model is a conversion of data from the Model to be used by the View.

Components

Components define views. Components use services, which provide specific functionality not directly related to views. Service providers can be injected into components as dependencies, making your code modular, reusable, and efficient.

Each component defines a class that contains application data and logic, and is associated with an HTML template that defines a view to be displayed in a target environment.

Template

A template combines HTML with Angular markup that can modify HTML elements before they are displayed. Template directives provide program logic, and binding markup connects your application data and the DOM. There are two types of data binding: Event binding lets your app respond to user input in the target environment by updating your application data; Property binding lets you interpolate values that are computed from your application data into the HTML.

Services, dependency injection

For data or logic that isn't associated with a specific view, and that you want to share across components, you create a service class. A service class definition is immediately preceded by the @Injectable() decorator.

Router - navigation

The Angular Router NgModule provides a service that lets you define a navigation path among the different application states and view hierarchies in your app

Project structure

ng new command creates a workspace. ng new <my-project>

Run angular tests with code coverage

   1 ng test --codeCoverage=true --watch=false

Karma jasmine show console.log()

In karma.conf

Example project

   1 ng new test-ng
   2 cd test-ng/
   3 ng build
   4 ng serve
   5 ng generate component abscomponent
   6 ng generate component conccomponent

Structure without dist and node_modules

.
├── angular.json
├── browserslist
├── e2e
│   ├── protractor.conf.js
│   ├── src
│   │   ├── app.e2e-spec.ts
│   │   └── app.po.ts
│   └── tsconfig.json
├── karma.conf.js
├── package.json
├── package-lock.json
├── README.md
├── src
│   ├── app
│   │   ├── abscomponent
│   │   │   ├── abscomponent.component.css
│   │   │   ├── abscomponent.component.html
│   │   │   ├── abscomponent.component.spec.ts
│   │   │   ├── abscomponent.component.ts
│   │   │   ├── tableheader.ts
│   │   │   ├── tablerow.ts
│   │   │   └── testdata.ts
│   │   ├── app.component.css
│   │   ├── app.component.html
│   │   ├── app.component.spec.ts
│   │   ├── app.component.ts
│   │   ├── app.module.ts
│   │   └── conccomponent
│   │       ├── conccomponent.component.css
│   │       ├── conccomponent.component.html
│   │       ├── conccomponent.component.spec.ts
│   │       └── conccomponent.component.ts
│   ├── assets
│   ├── environments
│   │   ├── environment.prod.ts
│   │   └── environment.ts
│   ├── favicon.ico
│   ├── index.html
│   ├── main.ts
│   ├── polyfills.ts
│   ├── styles.css
│   └── test.ts
├── tsconfig.app.json
├── tsconfig.json
├── tsconfig.spec.json
└── tslint.json

app.component.html

Add conccomponent to app.component.html

   1 <div class="content" role="main">
   2   <app-conccomponent></app-conccomponent>

abscomponent.component.html

   1 <p>abscomponent works! {{message}}</p>
   2 
   3 <div style="height: 100px; overflow-y: scroll;margin-bottom: 25px;">
   4     <table>
   5         <tr>
   6             <th *ngFor="let h of headers">{{h.name}}</th>
   7         </tr>
   8         <tr *ngFor="let row of rows">
   9             <td *ngFor="let value of row.values">
  10                 {{value}}
  11             </td>
  12         </tr>
  13     </table>
  14 </div>

abscomponent.component.ts

   1 import { Component, OnInit, Input } from '@angular/core';
   2 import { TestData } from './testdata';
   3 import { TableHeader } from './tableheader';
   4 import { TableRow } from './tablerow';
   5 
   6 @Component({
   7   selector: 'app-abscomponent',
   8   templateUrl: './abscomponent.component.html',
   9   styleUrls: ['./abscomponent.component.css']
  10 })
  11 export abstract class AbscomponentComponent implements OnInit {
  12 
  13   @Input()
  14   message: string = "Message";
  15 
  16   items: TestData[];
  17   headers: TableHeader[];
  18   rows: TableRow[];
  19 
  20   constructor() {
  21     this.items = [];
  22     this.headers = [];
  23     this.rows = [];
  24   }
  25 
  26   ngOnInit(): void {
  27   }
  28 
  29   public configure(input: string, data: TestData[], header: TableHeader[], rows: TableRow[]): void {
  30     this.message = input;
  31     this.items = [];
  32     this.headers = [];
  33     this.rows = [];
  34 
  35     // on push detector
  36     data.forEach(element => {
  37       this.items.push(element);
  38     });
  39 
  40     header.forEach(element => {
  41       this.headers.push(element);
  42     });
  43 
  44     rows.forEach(element => {
  45       this.rows.push(element);
  46     });
  47 
  48     console.log("configure called");
  49   }
  50 }

testdata.ts

   1 export interface TestData {
   2     name: string;
   3 }

tableheader.ts

   1 export interface TableHeader {
   2     name: string;
   3 }

tablerow.ts

   1 export interface TableRow {
   2     values: string[];
   3 }

conccomponent.component.ts

   1 import { Component, OnInit } from '@angular/core';
   2 import { AbscomponentComponent } from '../abscomponent/abscomponent.component';
   3 import { TestData } from '../abscomponent/testdata';
   4 import { TableHeader } from '../abscomponent/tableheader';
   5 import { TableRow } from '../abscomponent/tablerow';
   6 
   7 @Component({
   8   selector: 'app-conccomponent',
   9   templateUrl: '../abscomponent/abscomponent.component.html', //uses base class html
  10   styleUrls: ['../abscomponent/abscomponent.component.css']  // uses base class css
  11 })
  12 export class ConccomponentComponent extends AbscomponentComponent implements OnInit {
  13 
  14   constructor() {
  15     super();
  16   }
  17 
  18   ngOnInit(): void {
  19     let itemsx: TestData[];
  20     itemsx = [];
  21     itemsx.push({ name: "concrete" });
  22     itemsx.push({ name: "concreteaaa" });
  23     itemsx.push({ name: "asd" });
  24     let headers: TableHeader[];
  25     let rows: TableRow[];
  26     headers = [];
  27     headers.push({ name: "namea" });
  28     headers.push({ name: "nameb" });
  29 
  30     rows = [];
  31     rows.push({ values: ["x1", "y1"] });
  32     rows.push({ values: ["x2", "y2"] });
  33     rows.push({ values: ["x3", "y3"] });
  34     rows.push({ values: ["x4", "y4"] });
  35     rows.push({ values: ["x5", "y5"] });
  36     rows.push({ values: ["x6", "y6"] });
  37     rows.push({ values: ["x7", "y7"] });
  38     rows.push({ values: ["x8", "y8"] });
  39     this.configure(this.message + " extended !", itemsx, headers, rows);
  40   }
  41 
  42 }

Angular change detection

In short, the framework will trigger a change detection if one of the following events occurs:

   1 constructor(private ref: ChangeDetectorRef) {
   2 //...
   3 }
   4 this.ref.detectChanges(); // trigger detection change
   5 

Angular (last edited 2023-05-26 11:50:52 by 127)