Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Angular Quickstart

Angular Quickstart

German version of my talk. A quick dive into the elements of angular. Find example source code and a lot of explanations on modules, components and services.

Sebastian Springer

May 10, 2017
Tweet

More Decks by Sebastian Springer

Other Decks in Technology

Transcript

  1. Basti • Sebastian Springer • aus München • arbeite bei

    MaibornWolff GmbH • https://github.com/sspringer82 • @basti_springer • JavaScript Entwickler
  2. ngModule ngModule router Component Service Template Styles DataBinding Pipe Directive

    Compon ent DI PropertyBinding EventBinding imports root module Application
  3. Angular Angular ist ein JavaScript-Framework, das von Google entwickelt wurde.

    Es ist Open Source und wird auf GitHub maintained. Das Projekt selbst ist in mehrere Module unterteilt, sodass man lediglich die Module laden muss, die für einen selbst relevant sind. Alle Module werden parallel entwickelt und wiesen die gleiche Versionsnummer auf. Angular setzt mittlerweile auf Semantic Versioning. Es gibt zweimal im Jahr ein neues Major-Release
  4. TypeScript Das Entwickler Team von Angular hat sich dazu entschieden

    ein Typsystem für JavaScript einzusetzen. Ursprünglich wurde mit AtScript eine eigene Lösung entwickelt. Während der Entwicklung wurde auf TypeScript geschwenkt. TypeScript bietet statische Typenprüfung, die Verwendung von Interfaces und einen Transpiler der moderne JavaScript- Features auch für ältere Browser verfügbar macht.
  5. TypeScript Der TypeScript Compiler (tsc) wandelt den TypeScript-Code in JavaScript

    um, das vom Browser ausgeführt wird. Eine TypeScript-Datei endet per Konvention auf .ts. Dem Compiler können über eine Konfigurationsdatei (tsconfig.json) bestimmte Einstellungen mitgegeben werden. Liegt einen Bibliothek nicht in TypeScript vor, können Typdefinitionen heruntergeladen und installiert werden (http:// definitelytyped.org/)
  6. TypeScript Die Kernfeatures von TypeScript sind: • Datentypen (primitive und

    composite) • Typsichere Funktionen (Parameterliste und Rückgabewert) • Klassen und Interfaces
  7. TypeScript import { Person } from './person'; export class User

    extends Person { private password: string; constructor(public name: string) { super(name); } public setPassword(password: string) { this.password = this.createHash(password); } private createHash(input: string): string {...} }
  8. CLI

  9. CLI Um den Start in eine Angular Applikation so einfach

    wie möglich zu machen, gibt es das Angular-CLI-Tool. Dieses Werkzeug kommt im gesamten Lebenszyklus zum Einsatz von der Erstellung des Projekts, über die Entwicklung des Quellcodes bis zum Bau der fertigen Applikation für den Produktivbetrieb.
  10. CLI Die wichtigsten Kommandos: Neues Projekt anlegen: ng new <Projekt>

    Neues Element (z.B. Component) erzeugen: ng generate <blueprint> <Bezeichnung> Dev Server starten: ng serve Applikation bauen ng build
  11. Module Container-Element in der Applikation. Es fasst zusammengehörige Components, Services,

    etc. zusammen. Eine Applikation kann mehrere Module importieren.
  12. Component Baustein einer Applikation. Eine Component besteht aus Metainformationen, einem

    Template und einer Klasse. Eine Applikation setzt sich aus einem Baum von Komponenten zusammen.
  13. Directive Directives wirken sich auf das Verhalten und die Struktur

    des DOM aus. Sie kommen in den Templates einer Applikation vor. Eine Component ist eine Sonderform der Directive, da sie ein eigenes Template aufweist.
  14. Pipe Mit einer Pipe lässt sich eine gegebene Eingabe nach

    bestimmten Regeln in einen Ausgabe transformieren. Sie dienen vor allem der Anpassung von Anzeigewerten.
  15. Module Das App-Modul ist der Einstiegspunkt in die Applikation. Es

    gibt an, welche weiteren Module importiert werden, welche Components und Services verfügbar sind und welche Component die Wurzel der Applikation bildet. Das App Module wird initial vom CLI erzeugt
  16. Module import { … } from ‘…’; @NgModule({ declarations: […],

    imports: […], providers: […], bootstrap: [AppComponent] }) export class AppModule { } • declarations: Registrierung 
 von Components • imports: Importieren von 
 Modulen • providers: Registrierung von 
 Services • bootstrap: Root Component
  17. Component Erzeugung: ng generate component HelloWorld Es wird ein Verzeichnis

    mit folgendem Inhalt erzeugt: src/app/hello-world/ ├── hello-world.component.css ├── hello-world.component.html ├── hello-world.component.spec.ts └── hello-world.component.ts Die Component wird automatisch im Module registriert
  18. Component import { Component } from '@angular/core'; @Component({ selector: 'app-hello-world',

    templateUrl: './hello-world.component.html', styleUrls: ['./hello-world.component.css'] }) export class HelloWorldComponent { constructor() { } }
  19. Component Der grundlegende Aufbau einer Component ist: • Imports aller

    benötigten Dateien • Decorator mit Metadaten der Component • Component Class Der Selector gibt den Tag-Namen an über den die Component eingebunden wird. Die Component-Klasse dient der Datenhaltung für das Template und stellt Methoden zur Verfügung.
  20. Styling Standardmäßig gelten die in einer Component definierten Styles nur

    für die Component. Diese Lösung wird durch das Umbenennen der CSS-Klassen gelöst. Über die encapsulation-Eigenschaft des Decorators können auch andere Modi verwendet werden: • Native: Der Shadow-DOM wird verwendet • Emulated: CSS Renaming (Standard) • None: Keine Kapselung, Styles gelten global
  21. Template Angular nutzt HTML als Template-Engine. Templates können entweder inline

    im Decorator einer Component definiert werden oder in einer separaten HTML-Datei, was die Empfohlene Lösung ist. Per Interpolation ({{}}) kann vom Template aus auf die Eigenschaften der Component-Klasse zugegriffen werden.
  22. Templates import { Component } from '@angular/core'; @Component({ selector: 'app-list',

    templateUrl: './list.component.html', styleUrls: ['./list.component.css'] }) export class ListComponent { private name: string; constructor() { this.name = 'Klaus'; } } <h1>Hello {{name}}</h1> list/list.component.ts list/list.component.html
  23. Event-Binding Ähnlich wie auf Eigenschaften kann auch auf Methoden der

    Component-Class zugegriffen werden. (click)=“handleClick()” Mit dem Event-Binding wird beim Auslösen des Events z.B. eines Klicks die verbundene Methode der Component-Class aufgerufen. Dieser Methode können Eigenschaften übergeben werden. Mit der $event-Variablen erhält die Methode eine Referenz auf das Event-Objekt.
  24. Event-Binding export class ListComponent { private greeting = ''; greetMe(event,

    name) { console.log(event); this.greeting = `Hello ${name}`; } } <button (click)="greetMe($event, 'Klaus')"> greet me </button> {{greeting}} list.component.html list.component.ts
  25. Lifecycle Im Lebenszyklus einer Component gibt es verschiedene Phase. Für

    jede dieser Phasen gibt es einen Hook, für den man eine Funktion definieren kann. Vorgehensweise: • Interface implementieren • Hook-Methode umsetzen import { Component, OnInit } from '@angular/core'; @Component({…}) export class ListComponent implements OnInit { ngOnInit() { // initialization here } }
  26. Lifecycle Wird bei der Erzeugung ausgeführt Auf eingehende Datenänderungen reagieren

    Initialisierung (wird nur 1x aufgerufen) Wird bei der Change Detection aufgerufen Nachdem externer Inhalt verarbeitet wurde Reaktionsmöglichkeit auf Inhaltsprüfungen Reaktionsmöglichkeit auf Initialisierung Hook nach View und View Children Wird vor der Zerstörung aufgerufen
  27. Child Components Eine Angular-Applikation besteht aus einem Baum von Components.

    In einem Template einer Component können beliebig viele Child Components referenziert werden. Diese Art der Strukturierung erhöht die Wiederverwendbarkeit einzelner Teile der Appliktion. Außerdem wird durch definierte Schnittstellen eine lose Kopplung zwischen den einzelnen Components geschaffen.
  28. Child Components ng generate component list-item Component auf der Kommandozeile

    erzeugen Component in app.module.ts (declarations) registrieren (automatisch) Component verwenden (list.component.html) <ul> <app-list-item *ngFor="let item of items"></app-list-item> </ul>
  29. Child Component - Input Um Informationen in eine Child Component

    hinein zu reichen, wird das Angular Property Binding ([]) in Verbindung mit Input Binding (@Input) verwendet. Achtung: auf @Input folgen immer Klammern. <ul> <app-list-item *ngFor="let item of items" [item]="item"> </app-list-item> </ul> @Component({…}) export class ListItemComponent { @Input() private item: Item; constructor() { } }
  30. Child Component - Output Die Informationen, die per Input-Binding in

    eine Child Component hineingegeben werden, sollten nicht by Reference verändert werden. Werden die Daten angepasst, passiert dies auf einer Kopie der Daten und die Parent Component wird per Event benachrichtigt. 1. Output Binding festlegen 2. Eventhandler erzeugen und emit-Methode aufrufen 3. In der Eltern Component auf das Event reagieren
 Der Zugriff auf die Event-Daten erfolgt über die $event- Variable
  31. Output - Child Component <li> {{item.title}} <a (click)="delete(item.title)">remove</a> </li> @Component({

    selector: 'app-list-item', templateUrl: './list-item.component.html', styleUrls: ['./list-item.component.css'] }) export class ListItemComponent { @Output() public onDelete = new EventEmitter(); … private delete(title) { this.onDelete.emit(title); } }
  32. Output - Parent Component <ul> <app-list-item *ngFor="let item of items"

    [item]="item" (onDelete)="removeItem($event)"> </app-list-item> </ul> export class ListComponent implements OnInit { … removeItem(title) { const index = this.items.findIndex( item => item.title === title ); this.items.splice(index, 1); } }
  33. Pipes Pipes werden verwendet, um Anzeigewerte zu formatieren. Pipes sind

    Datenstreams mit Eingabe, Ausgabe und Parametern. Mit den Parametern kann das Verhalten der Pipe beeinflusst werden. Eine Pipe wird durch das | vom Eingangswert getrennt. Die Parameter werden durch Doppelpunkte getrennt. Mehrere Pipes können miteinander verkettet werden. Sie werden ebenfalls durch das |-Zeichen voneinander getrennt. Die Ausgabe einer Pipe dient dann als Eingabe für die nachfolgende.
  34. Pipes export class ListComponent implements OnInit { private date =

    Date.now(); … } <div>It's {{ date | date: 'shortTime' }}</div>
  35. RxJS Die Reactive Extensions sind eine Bibliothek, die eine Implementierung

    des Observer-Patterns darstellen. Damit wird asynchrone Programmierung über definierte Schnittstellen möglich. Reactive Extensions sind wesentlich flexibler als Callback-Funktionen und Promises. Reactive Extensions wurden von Microsoft entwickelt und sind für viele Sprachen wie Java, C#, C++ oder JavaScript verfügbar.
  36. Operatoren Operatoren sind die Werkzeugkiste von RxJS. Operatoren erfüllen verschiedene

    Zwecke: Sie können verwendet werden, um Observables zu erzeugen, Datenströme zu Filtern oder Fehler in der Applikation zu behandeln.
  37. RxJS in Components import { Component, OnInit } from '@angular/core';

    import { Observable } from 'rxjs/Rx'; @Component({…}) export class DateComponent implements OnInit { private timestamp: number; ngOnInit() { Observable.interval(1000) .timestamp() .map(ts => ts.timestamp) .subscribe(ts => { this.timestamp = ts; }); } }
  38. Services Services kapseln Logik und können zur Datenverwaltung verwendet werden.

    Mit Services kann außerdem mit anderen Systemen kommuniziert werden. Angular gibt für Services keine Struktur vor.
  39. Services ng generate service user Dieser Befehl erzeugt einen Service.

    Dieser muss anschließend noch als Provider registriert werden. Hierfür gibt es zwei Möglichkeiten: • Am Modul: Das gesamte Modul (app.module.ts unter dem Schlüssel provider) teilt sich eine Instanz des Services • An einer bestimmten Component: Eine Instanz pro Component (Component-Datei im @Component-Decorator als provider)
  40. import { Injectable } from '@angular/core'; import { User }

    from './user'; @Injectable() export class UserService { users: Array<User> = []; constructor() { } load() { this.users.push({id: 1, name: 'Peter'}); this.users.push({id: 2, name: 'Paul'}); this.users.push({id: 3, name: 'Mary'}); } get() { return this.users; } add(user: User) { this.users.push(user); } update(user: User) { const index = this.users.findIndex(existingUser => existingUser.id === user.id); this.users[index] = user; } remove(id: number) { const index = this.users.findIndex(user => user.id === id); this.users.splice(index, 1); } }
  41. Dependency Injection Bevor ein Service verwendet werden kann, muss er

    zunächst geladen werden. Dies geschieht über die Dependency Injection von Angular. Im einfachsten Fall werden die Abhängigkeiten zu anderen Elementen der Applikation im Konstruktor einer Klasse angegeben. Angular sucht daraufhin nach einem passenden Provider und liefert entweder eine bestehende Instanz aus dem Cache aus oder erzeugt eine neue Instanz.
  42. Dependency Injection export class ListComponent implements OnInit { private users:

    Array<User> = []; constructor(private userService: UserService) {} ngOnInit() { this.userService.load(); this.users = this.userService.get(); } removeUser(id) { this.userService.remove(id); this.users = this.userService.get(); } }
  43. HTTP Der http Service ist ein separates Modul des Angular-

    Frameworks. Er dient der Kommunikation mit einem Webserver und kann per Dependency Injection sowohl von anderen Services als auch direkt in Components verwendet werden. 1. HttpModule in app.module.ts als imports einbinden (@angular/http) - wird von der CLI automatisch gemacht 2. HttpService per Dependency Injection laden 3. Instanz verwenden.
  44. HTTP import { Injectable } from '@angular/core'; import { Http

    } from '@angular/http'; import { User } from './user'; import 'rxjs/add/operator/map'; @Injectable() export class UserService { users: Array<User> = []; constructor(private http: Http) {} load() { this.http.get('/user') .map(res => res.json()) .subscribe((users: Array<User>) => { this.users = users; }); } }
  45. HTTP Die Methoden des HttpService geben keine Promise, sondern ein

    RxJS-Observable zurück. Bei diesem Objekt handelt es sich um einen asynchronen Datenstrom auf den verschiedene Operatoren wie z.B. map angewendet werden können. Mit der subscribe-Methode können Sie eine Callback-Funktion registrieren.
  46. HTTP Wird bei der Entwicklung ng serve verwendet, kann die

    proxy-Option von Webpack eingesetzt werden, um Anfragen an den Server auf einen anderen Port umzuleiten. Damit kann ein Backend an die, sich im Entwicklungsbetrieb befindende, Applikation angeschlossen werden, ohne dass Anpassungen am Quellcode erforderlich sind.
  47. Reactive Store Ein Reactive Store kapselt die Datenhaltung in einer

    internen Datenstruktur. Der Store wird nicht direkt sondern über eine definierte API modifiziert. Meist ist der Store mit dem HTTP- Service verbunden. Der Store selbst ist als Service umgesetzt, der in Components per Dependency Injection eingebunden wird. Die API verfügt meist über Methoden für CRUD-Operationen.
  48. Reactive Store @Injectable() export class TodoService { todos: Observable<Todo[]> private

    _todos: BehaviorSubject<Todo[]>; private baseUrl: string; private dataStore: { todos: Todo[] }; constructor() { this.dataStore = { todos: [] }; this._todos = <BehaviorSubject<Todo[]>>new BehaviorSubject([]); this.todos = this._todos.asObservable(); } }
  49. Reactive Store Das Observable dient als readonly-Schnittstelle nach außen. Intern

    werden Veränderungen über das BehaviorSubject publiziert. Im internen dataStore werden die Daten vorgehalten. In das BehaviorSubject können sowohl Daten geschrieben werden als auch gelesen werden. Außerdem kann es als Observable exportiert werden.
  50. Reactive Store create(todo: Todo) { this.dataStore.todos.push(todo); this._todos.next(Object.assign({}, this.dataStore).todos); } Operationen

    auf dem Store laufen immer nach dem gleichen Schema ab: Zuerst wird der lokale DataStore modifiziert, danach die next-Methode des BehaviorSubjects mit einem Klon des DataStores aufgerufen.
  51. Forms Angular verfügt über zwei Arten von Formularen: Template Driven

    Forms und Reactive Forms. Template Driven Forms sind einfacher und basieren hauptsächlich auf Templates. Reactive Forms sind flexibler und erfordern mehr TypeScript-Quellcode.
  52. Template Driven Forms 1. Form Modul einbinden 2. Component erstellen

    3. Template erzeugen 4. Formular-Elemente mit ngModel anbinden 5. name-Attribute einfügen 6. Validierung umsetzen 7. Formular abschicken
  53. Template Driven Forms Das Forms Modul stellt Direktiven wie ngModel

    und ngForm zur Verfügung, die zur Erzeugung von Formularen erforderlich sind.
  54. Template Driven Forms <label for="name">Name</label> <input type="text" class="form-control" id="name" required

    [(ngModel)]="model.name" name="name"> Das id-Attribut wird zur Verknüpfung mit dem label verwendet. Das name-Attribut und die ngModel-Direktive dienen der Formularbehandlung durch Angular. Das required-Attribut ist eine Direktive, die einen Validator aktiviert. Durch ngModel werden die Werte direkt mit dem Model der Component synchronisiert.
  55. Template Driven Forms State Wahr falsch Element wurde besucht ng-touched

    ng-untouched Wert hat sich geändert ng-dirty ng-pristine Wert ist gültig ng-valid ng-invalid Auf den Status eines Form-Elements kann zugegriffen werden. Angular trackt verschiedene States als CSS-Klassen. Damit können Styles angewendet werden.
  56. Template Driven Forms <div [hidden]="name.valid || name.pristine" class=“error-message“> Name is

    required </div> Über den Namen des Eingabefeldes kann auch auf dessen Status zugegriffen werden und so z.B. Fehlermeldungen ein- beziehungsweise ausgeblendet werden.
  57. Template Driven Forms Das Formular kann mit der ngSubmit-Direktive abgesendet

    werden. Diese wird direkt an das Formular gebunden. Sobald das Formular über den Submit-Button abgesendet wird, wird die onSubmit-Methode der Component aufgerufen. Durch das disabled-Attribut wird der Submit-Button erst verfügbar, sobald das Formular valide ist. <form (ngSubmit)="onSubmit()" #addressForm="ngForm"> … <button type="submit" class="btn btn-success" [disabled]="! addressForm.form.valid">Submit</button> </form>
  58. Reactive Forms Damit Sie Reactive Forms benutzen können, müssen Sie

    in Ihrem Root-Module das ReactiveFormsModule einbinden (per Imports). Danach erzeugen Sie in Ihrem Template die Struktur. Die Verbindung zum Formular erfolgt hier über die formControlName-Direktive. Alles Weitere geschieht im Code der Component. Hier verwenden Sie den FormBuilder, um das Formular zu erzeugen.
  59. Reactive Forms export class FormComponent implements OnInit { private form:

    FormGroup; constructor(fb: FormBuilder) { this.form = fb.group({ "name": ["", Validators.required], "password":["", Validators.required] }); } ngOnInit() { this.form.valueChanges .map((value) => { value.name = value.name.toUpperCase(); return value; }) .filter((value) => this.form.valid) .subscribe((value) => {…}); } }
  60. Reactive Forms <section class="sample-app-content"> <h1>Model-based Form Example:</h1> <form [formGroup]="form"> <p>

    <label>Name:</label> <input type="text" formControlName="name"> </p> <p> <label>Password:</label> <input type="password" formControlName="password"> </p> <p> <button type="submit" [disabled]="! form.valid">Submit</button> </p> </form> </section>
  61. Routing Routing bezeichnet die Navigation innerhalb einer Single Page Applikation

    über URLs. Eine Änderung der URL sorgt dabei nicht für einen Page Load, sodass der State der Applikation erhalten bleibt. Angular verfügt über ein eigenes Modul zu diesem Zweck: den Angular Router. Dieses Modul wird standardmäßig von der Angular CLI mit installiert.
  62. Routing Damit der Router funktionieren, müssen Sie in Ihrer index.html-

    Datei das Tag <base href=“/"> einfügen. Danach konfigurieren Sie Ihre Routen und registrieren diese in Ihrem Module.
  63. Routing import { RouterModule, Routes } from '@angular/router'; const appRoutes:

    Routes = [ { path: 'list', component: ListComponent }, { path: 'address/:id', component: AddressComponent } ]; @NgModule({ declarations: […], imports: [ RouterModule.forRoot(appRoutes) … ], providers: […], bootstrap: [AppComponent] }) export class AppModule { }
  64. Routing Sie können in Ihrer Routing-Konfiguration auch eine Standardroute für

    den Einstieg in Ihre Applikation definieren. { path: '', redirectTo: '/list', pathMatch: 'full' }
  65. Routing Je nachdem welche Route Sie in Ihrer Applikation aktivieren,

    wird ein anderer Component-Baum angezeigt. Mit dem RouterOutlet geben Sie an, wo diese Components angezeigt werden sollen. <router-outlet></router-outlet>
  66. Routing Innerhalb Ihrer Applikation können Sie entweder über RouterLinks oder

    aus dem Quellcode Ihrer Components heraus navigieren. <a routerLink="/list" routerLinkActive="active">Liste</a> routerLinkActive hilft die aktive Route visuell zu kennzeichnen. export class ListComponent { constructor(private router: Router) { } onShowDetails(address) { this.router.navigate(['/address', address.id]) } }
  67. Routing Routen können sowohl statische als auch dynamische Teile beinhalten.

    Auf diese dynamischen Inhalte können Sie über ein Observable (route.params) zugreifen. export class AddressComponent implements OnInit { constructor( private route: ActivatedRoute, private service: AddressService ) {} ngOnInit() { this.route.params .switchMap((params: Params) => this.service.get(parseInt(params['id'])) .subscribe((add: Address) => this.add = add); } }