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
https://docs.angularjs.org/guide/concepts
Model - the data shown to the user in the view and with which the user interacts
View - what the user sees (the DOM)
Controller - the business logic behind views
Dependency Injection - Creates and wires objects and functions
MVVM
In Angular (MVVM)(MVC)
the component plays the part of the controller or viewmodel,
and the template represents the view.
The model represents the business model/domain model
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.
https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93viewmodel#Components_of_MVVM_pattern
Model: Model refers either to a domain model,
View: structure, layout, and appearance of what a user sees on the screen. It displays a representation of the model and receives the user's interaction with the view and it forwards the handling of these to the view model via the data binding.
View Model: abstraction of the view exposing public properties and commands. It has a binder, which automates communication between the view and its bound properties in the view model. The view model has been described as a state of the data in the model.
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
- find client.jasmine.captureConsole
- change it from false to true
Example project
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
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
tableheader.ts
tablerow.ts
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:
- any browser event (click, keyup, etc.)
- setInterval() and setTimeout()
- HTTP requests via XMLHttpRequest