SPAS wurde trendy als die Antithese zu serverseitigen Websites. Es gibt wie immer Vor- und Nachteile, aber ein Spa kann eine reibungslose Benutzererfahrung schaffen, die ohne einen solchen Ansatz schwer zu replizieren ist. Dies ist Teil des Unternehmens der Webanwendungen in das Gebiet, das traditionell von Desktop -Anwendungen besetzt war. Webanwendungen werden im Allgemeinen dafür kritisiert weniger ein Problem als früher.
SPAS -Funktion, indem eine einzelne HTML -Seite im Client geladen und dann die Inhalt (und die DOM) dynamisch aktualisiert wird - anstatt eine aktualisierte HTML -Seite vom Server abzurufen, wenn der Benutzer überall klickt.
NodeJS
und npm
, indem Sie hier den entsprechenden Anweisungen befolgen.TypeScript
von hier.npm install -g @angular/cli
ng new my-project
cd my-project && ng serve
localhost:4200
in Ihrem Webbrowser besuchen. Wenn Sie my-project/src/app/app.component.ts
öffnen, sollten Sie mit so etwas wie folgt begrüßt werden:
/** app.component.ts */
import { Component } from '@angular/core' ; // #1
@ Component ( { // #2
selector : 'app-root' , // #3
templateUrl : './app.component.html' , // #4
styleUrls : [ './app.component.css' ] // #5
} )
export class AppComponent {
title = 'app' ; // #6
}
Lassen Sie uns dies ein wenig aufschlüsseln:
Component
aus dem @angular
-Modul im Ordner node_modules
.@Component
Decorator markiert eine Klasse als Winkelkomponente. Der Dekorateur wird mit einem Optionsobjekt parametrisiert, von dem wir nur wenige Parameter verwenden werden.selector
definiert, was die HTML-Tags für diese Komponente sein werden-beispielsweise wird dieser mit <app-root> … </app-root>
in HTML injiziert.templateUrl
nimmt ein String -Argument auf, das auf die HTML -Datei hinweist, die als Ansichtsteil der Komponente dient. Sie können auch den template
verwenden, um HTML direkt zu schreiben, anstatt auf eine Datei zu zeigen. Dies wird im Allgemeinen nicht empfohlen, es sei denn, der Ansichtsteil ist einfach ein oder zwei Zeilen.styleUrls
-Parameter enthält eine Liste von Zeichenfolgen, wobei jede Zeichenfolge ein Pfad zu einer CSS -Datei ist.title
von app.component.html
verwiesen werden. Navigieren Sie zu app.component.html
. Dies ist der Einstiegspunkt für unsere Anwendung und der höchste HTML auf höchstem Niveau, den Sie bearbeiten sollten. In diesem Kontext wird alles in diesem Zusammenhang gerendert.
Wir werden nun den Inhalt dieser Datei löschen und ihn durch Folgendes ersetzen:
< div class =" container " >
< h1 > Live football scores </ h1 >
< div class =" score-card-list " >
< div class =" score-card " >
< span > Team 1 </ span >
< span > 0 : 0 </ span >
< span > Team 2 </ span >
</ div >
</ div >
</ div >
Kehren Sie zu Ihrem Webbrowser zurück, und Sie sollten sehen, dass die Seite automatisch aktualisiert wurde. Großartig.
Visuell werden Sie in dieser Phase wahrscheinlich enttäuscht sein, aber es ist eine laufende Arbeit.
Angular Material ist eine Bibliothek, die von einem Team von Google gepflegt wird, um benutzerfreundliche Materialdesignkomponenten für Winkelanwendungen bereitzustellen. Das Styling dieser Komponenten kann in den Inhalt Ihres Herzens optimiert werden, bietet jedoch auch eine einfache Möglichkeit, das Erscheinungsbild einer Prototyp -App mit minimalem Aufwand zu verbessern.
Lassen Sie uns die erforderlichen Bibliotheken mit npm install --save @angular/material @angular/cdk @angular/animations
. Dadurch wird die erforderlichen Dateien in Ihren Ordner node_modules
heruntergeladen und die Datei packages.json
angemessen aktualisiert.
Sie müssen Angular auch angeben, die relevanten Komponenten zu laden. Sie müssen ein bisschen googeln, wie dies funktioniert (dies ist ein Tutorial von 101 Klebeband), aber im Grunde müssen Sie die Datei app.modules.ts
-Datei so ändern, dass diese Module, die Sie benötigen, einbeziehen.
Fügen Sie zunächst die Animationen wie SO hinzu:
import { BrowserAnimationsModule } from '@angular/platform-browser/animations' ;
@ NgModule ( {
...
imports : [ BrowserAnimationsModule ] ,
...
} )
Fügen Sie dann die von uns benötigten Module hinzu:
import { MatButtonModule , MatCardModule } from '@angular/material' ;
@ NgModule ( {
...
imports : [ MatButtonModule , MatCardModule ] ,
...
} )
Beachten Sie, dass Sie die in Ihrer App zu verwendenen Komponenten importieren müssen. Der Grund, nicht die gesamte Bibliothek aufzunehmen, besteht darin, webpack
dabei zu helfen, ein Baumschütteln auszuführen. Dies beinhaltet im Grunde genommen dazu, nicht verwendete Code -Teile auszulassen, wenn der gesamte Code in wenige .js
-Minimified -Dateien bündelt.
Sobald dies erledigt ist, haben wir Zugriff auf eine Reihe vordefinierter Komponenten, und Sie können sie einfach nach Bedarf importieren. Es ist auch erwähnenswert, dass die vorgebauten Themen einfach zu bedienen sind.
In Angular sind Komponenten modular. Jede Komponente verfügt über eigene CSS -Datei, die nur für diese spezifische Ansicht gelten. Die einzige Ausnahme ist die in dem src
-Verzeichnis gefundene styles.css
-Datei, die weltweit gilt.
Styling ist kein Fokus dieses Tutorials, daher werden wir versuchen, es in Zukunft so viel wie möglich zu vermeiden. Um sich etwas besser zu fühlen, was wir machen, finden Sie hier einige einfache CSS zum Kopieren und Einfügen in die Datei styles.css
(bessere Praxis würden relevante Bits zu den CSS -Dateien der Komponenten hinzufügen, um zukünftige Referenz zu erhalten):
// Outer wrapper div
. container {
text-align : center;
}
// Wrapper for the score cards
. score-card-list {
display : flex;
flex-direction : column;
align-items : center;
}
// Each score card
. score-card {
width : 550 px ;
display : flex !important ;
}
// Home team score
. home {
flex : 1 ;
text-align : right;
}
// Away team score
. away {
flex : 1 ;
text-align : left;
}
// Score section of score card
. score {
width : 100 px ;
}
Aktualisieren Sie auch Ihre HTML, um die Klassen einzuschließen:
...
< mat-card class =" score-card " >
< span class =" home " > Team 1 </ span >
< span class =" score " > 0 : 0 </ span >
< span class =" away " > Team 2 </ span >
</ mat-card >
...
Wenn Sie mit flex
verwirrt sind, empfehle ich dringend, Flexbox Froggy zu überprüfen.
Einer der Vorteile der Verwendung eines Frameworks wie Angular ist, dass wir in der HTML einige Programmierlogik implementieren können. In unserem Fall macht For-Loops das Leben viel einfacher.
Probieren Sie Folgendes aus:
...
< mat-card class =" score-card " *ngFor =" let team of ['Arsenal', 'Liverpool', 'Tottenham']; let i=index " >
< span class =" home " > {{ team }} </ span >
< span class =" score " > 0 : 0 </ span >
< span class =" away " > Team {{ i+1 }} </ span >
</ mat-card >
...
Dies führt zu einer Reihe neuer Konzepte und sollte so etwas wie Folgendes produzieren:
Konzepte zu beachten:
{{ 'Some text = ' + a_number }}
Dienste werden verwendet, um den Datenzugriff von den Komponenten abzuwehren. Dies ermöglicht es Komponenten, schlank zu bleiben und sich darauf zu konzentrieren, die Ansicht zu unterstützen. Unit -Tests und Code -Wartung werden vereinfacht, indem diese Verantwortungsteilung aufrechterhalten wird.
Um einen Service mithilfe der CLI zu generieren, können Sie ng generate service football-data
(oder ng gs football-data
für Menschen kurz). Dadurch werden zwei neue Dateien in Ihrem project-dir/src/app
Verzeichnis erstellt: football-data.service.ts
und football-data.service.spec.ts
. Dies folgt der Winkelkonvention, bei der Testdateien die Erweiterung .spec.ts
erhalten. Obwohl Tests nützlich und wichtig sind, fällt es außerhalb des unmittelbaren Umfangs dieses Tutorials, sodass Sie es für den Moment ignorieren können (sorry, @cornel).
Fügen Sie die folgenden Zeilen zu football-data.service.ts
:
import { Injectable } from '@angular/core' ;
import { HttpHeaders } from '@angular/common/http' ;
@ Injectable ( ) // Designate this class as an injectable service
export class FootballDataService {
// Token for accessing data on football-data.org (see: https://www.football-data.org/client/register)
HEADERS = new HttpHeaders ( { 'X-Auth-Token' : 'dc25ff8a05123411sadgvde5bb16lklnmc7' } ) ;
// Convenience constant
COMPETITION_URL = 'http://api.football-data.org/v1/competitions/' ;
// ID for the Premier League
PL_ID = 445 ;
constructor ( ) { }
}
Die Dienste sind mit @Injectable
kommentiert, was dem Compiler mitteilt, dass Instanzen des Dienstes in Komponenten injiziert werden können. Sie müssen auch einen Anbieter für jeden Dienst angeben. Der Anbieter stellt effektiv einen Singleton auf der angegebenen Ebene bereit.
Sie können beispielsweise Ihren Dienst dem Anbieter -Array in app.module.ts
hinzufügen, was dazu führt, dass eine Singleton -Instanz des Dienstes in der gesamten App freigelegt wird. Andernfalls könnten Sie es der Anbieterliste einer Komponente hinzufügen, die zu einer Singleton -Instanz für diese Komponente und alle Komponenten in ihrem Kontext zur Verfügung gestellt wird.
Warnung: Es wird einfach, kreisförmige Abhängigkeiten zwischen Diensten zu erstellen, sobald Ihre App größer wird. Achten Sie darauf. Wenn (wann) Sie jemals eine Fehlermeldung erhalten, die so etwas aussieht, Cannot resolve all parameters for MyDataService(?)
, sie hängt wahrscheinlich mit Problemen mit kreisförmiger Abhängigkeit zusammen.
Wir werden die fantastische API bei Football-Data.org frei nutzen. Sie müssen Ihren eigenen API -Schlüssel erhalten, aber es ist einfach zu tun. Befolgen Sie einfach die Anweisungen auf der Website. Es gibt eine detailliertere Dokumentation, aber 99% Ihrer benötigen, die Sie benötigen, sind in den hier aufgeführten kleinen Beispielen zu sehen.
In diesem Beispiel möchten wir nur die Spielinformationen für alle Spiele in der aktuellen Runde (auch bekannt als "Spielwoche" oder "Match Day") abrufen. Der Endpunkt /v1/competitions/{id}/fixtures
gibt diese Informationen zurück, aber für alle früheren Runden in der laufenden Saison. Um die Informationen für eine einzelne Runde zu erhalten, müssen wir den matchday
-Parameter festlegen, z /v1/competitions/{id}/fixtures?matchday=14
Um den aktuellen Spieltag zu erhalten, können wir nach dem Ligabisch fragen, da er standardmäßig für den aktuellen Spieltag zurückkehrt.
Zunächst müssen wir den HttpClient
-Service in unseren FootballDataService
einbringen, um die HTTP -Funktionen von Angular zu nutzen:
import { HttpClient , HttpHeaders } from '@angular/common/http' ;
...
constructor ( private http : HttpClient ) { }
. . .
WICHTIG : Hinzufügen einer privaten Variablen zum Konstruktor eines Winkeldienstes oder einer Winkelkomponente zusammen mit der spezifischen Deklaration vom TypeScript -Typ ist genügend Informationen, damit die schwarze Magie von Angular funktioniert. Der Compiler wird nun die entsprechende Instanz in diesen Dienst einfließen, sodass Sie Zugriff darauf haben.
Fügen wir eine Funktion hinzu, um die Ligabelle (und den aktuellen Spieltag) vom Server abzurufen:
...
getTable ( ) {
return this . http . get ( this . COMPETITION_URL + this . PL_ID + '/leagueTable' ,
{ headers : this . HEADERS } ) ;
}
...
TypeScript hilft Ihnen dabei, aber die Methodensignatur für die http.get
-Methode von Angular sieht wie folgt aus:
/**
* Construct a GET request which interprets the body as JSON and returns it.
*
* @return an `Observable` of the body as an `Object`.
*/
get ( url : string , options ?: {
headers ?: HttpHeaders | {
[ header : string ] : string | string [ ] ;
} ;
observe?: 'body' ;
params?: HttpParams | {
[ param : string ] : string | string [ ] ;
} ;
reportProgress?: boolean ;
responseType?: 'json' ;
withCredentials?: boolean ;
} ) : Observable < Object > ;
Die Fragezeichen bezeichnen, dass Parameter headers
, observe
, params
, reportProgress
, responseType
und withCredentials
als Teil des optionalen Objekts für options
optional sind. Wir werden nur Werte für die url
und options.headers
übergeben.
Sie fragen sich vielleicht, wie die Funktion getTable()
die wir gerade erstellt haben, die Rückkehr erstellt. Nun, es gibt einen Observable
Strom zurück. Observable
S sind im Wesentlichen, wie Luuk Gruijs es ausdrückte, "faule Sammlungen mehrerer Werte über die Zeit". Was verrückt klingt, aber eigentlich ziemlich einfach ist.
Kurz gesagt, ein Observable
Strom wird als "kalt" angesehen, bis er abonniert wird - dh die Variable wird nur faul geladen, wenn die Ausgabe verwendet wird. Sobald der Stream "heiß" ist, aktualisiert er alle Abonnenten, wenn sich sein Wert ändert. Es ist eine Alternative zur Verwendung von Promise
für den Umgang mit asynchronen Situationen in JavaScript.
In diesem Fall wird die GET
-Anforderung erst dann abgefeuert, sobald die Observable
Variable abonniert wird, da die REST -Schnittstelle immer nur einen einzelnen Wert pro Anruf zurückgibt.
Wir können die Leistung der statischen Typisierung in Typenkript verwenden, um dies expliziter zu gestalten:
...
import { Observable } from 'rxjs/Observable' ;
...
getTable ( ) : Observable < any > {
return this . http . get ( this . COMPETITION_URL + this . PL_ID + '/leagueTable' ,
{ headers : this . HEADERS } ) ;
}
...
Da die Dokumentation der Fußballdaten.org uns genau vom Restanruf erwartet, können wir noch einen Schritt weiter gehen und das Objekt auch in src/app/models/leagueTable.ts
modellieren:
import { Team } from './team' ;
export class LeagueTable {
leagueCaption : string ;
matchday : number ;
standing : Team [ ] ;
}
Und in src/app/models/team.ts
:
export class Team {
teamName : string ;
crestURI : string ;
position : number ;
points : number ;
playedGames : number ;
home : {
goals : number ;
goalsAgainst : number ;
wins : number ;
draws : number ;
losses : number ;
} ;
away : {
goals : number ;
goalsAgainst : number ;
wins : number ;
draws : number ;
losses : number ;
} ;
draws : number ;
goalDifference : number ;
goals : number ;
goalsAgainst : number ;
losses : number ;
wins : number ;
}
Dies ermöglicht es uns, die football-data.service.ts
zu aktualisieren.
import 'rxjs/add/operator/map' ;
import { LeagueTable } from './models/leagueTable' ;
...
getTable ( ) : Observable < LeagueTable > {
return this . http . get ( this . COMPETITION_URL + this . PL_ID + '/leagueTable' ,
{ headers : this . HEADERS } )
. map ( res => res as LeagueTable ) ;
}
...
Dies hilft uns, unsere geistige Gesundheit aufrechtzuerhalten, indem wir das mentale Modell minimieren, das wir benötigen, um während der Arbeit mit komplexen Objekten auf dem Laufenden zu bleiben, wie die IDE uns führen kann.
Randnotiz: Das as
-Keyword zeigt einfach an, dass TypeScript uns über den Typ des Objekts vertraut wird, anstatt es durch eine Art Inspektion herauszufinden. Gefährlich, aber nützlich, wie interessanteste Dinge.
Okay, navigieren Sie zurück zu src/app/app.component.ts
und fügen Sie die folgenden Zeilen hinzu, um den FootballDataService
in die Komponente zu injizieren:
import { FootballDataService } from './football-data.service' ;
...
export class AppComponent {
title = 'app' ;
constructor ( private footballData : FootballDataService ) { }
}
Jetzt werden wir der Komponente auch eine ngOnInit
-Methode hinzufügen. Dies ist ein Standard-Lebenszyklus-Hook, der von Angular bereitgestellt wird, der nach Initialisierungen aller datengebundenen Eigenschaften einer Komponente ausbreitet. Es wird im Grunde auf die Initialisierung des Objekts ausgelöst, jedoch etwas später als die constructor
, die vor allen Eingängen und Ausgängen an die Komponente ausfeuert.
Eine häufige Faustregel ist, dass Sie in dieser speziellen ngOnInit
-Methode und nicht immer den Code, den Sie auf Initialisierung anrufen möchten, und nicht immer in der Initialisierung aufzunehmen. Fügen Sie es einer Komponente wie SO hinzu:
import { Component , OnInit } from '@angular/core' ;
...
export class AppComponent implements OnInit {
...
constructor ( private footballData : FootballDataService ) { }
ngOnInit ( ) {
// Code you want to invoke on initialisation goes here
}
...
In unserem Fall möchten wir den Ligabisch laden, damit wir so etwas hinzufügen können:
...
ngOnInit ( ) {
// Load league table from REST service
this . footballData . getTable ( )
. subscribe (
data => console . log ( data ) ,
error => console . log ( error )
) ;
}
...
Wenn Sie die Konsole in Ihrem Webbrowser öffnen, sollten Sie so etwas sehen:
Großartig. Wir haben jetzt viele coole Daten, mit denen wir in Zukunft etwas tun könnten (nicht zuletzt direkte Links zu Club Crest Images), aber im Moment interessieren wir uns wirklich nur am aktuellen Matchday.
Fügen wir nun unserem Datenservice eine weitere Funktion hinzu, um die Informationen für die aktuelle Runde der Vorrichtungen zu erhalten:
...
import { GameWeek } from './models/gameWeek' ;
...
getFixtures ( matchDay : number ) : Observable < GameWeek > {
return this . http . get ( this . COMPETITION_URL + this . PL_ID + '/fixtures?matchday=' + matchDay , { headers : this . HEADERS } )
. map ( res => res as GameWeek ) ;
}
...
Mit GameWeek
und Fixture
definiert wie folgt:
// src/app/models/gameWeek.ts
import { Fixture } from './fixture'
export class GameWeek {
count : number ;
fixtures : Fixture [ ] ;
}
// src/app/models/fixture.ts
export class Fixture {
awayTeamName : string ;
date : string ;
homeTeamName : string ;
matchday : number ;
result : {
goalsAwayTeam : number ;
goalsHomeTeam : number ;
halfTime : {
goalsAwayTeam : number ;
goalsHomeTeam : number ;
}
} ;
status : 'SCHEDULED' | 'TIMED' | 'POSTPONED' | 'IN_PLAY' | 'CANCELED' | 'FINISHED' ;
_links : {
awayTeam : { href : string ; } ;
competition : { href : string ; } ;
homeTeam : { href : string ; } ;
self : { href : string ; } ;
} ;
}
Mit unserem neu gewonnenen Übereinstimmungskenntnis können wir den Restserver um Informationen über die aktuelle Runde der Vorrichtungen bitten. Wir müssen jedoch darauf warten, dass der erste Restanruf zuerst abgeschlossen ist, bevor wir den zweiten durchführen. Einige Refactoring bedeuten, dass wir dies im Rückruf ziemlich leicht tun können:
import { Component , OnInit } from '@angular/core' ;
import { FootballDataService } from './football-data.service' ;
import { LeagueTable } from './models/leagueTable' ;
@ Component ( {
selector : 'app-root' ,
templateUrl : './app.component.html' ,
styleUrls : [ './app.component.css' ] ,
providers : [ FootballDataService ]
} )
export class AppComponent implements OnInit {
title = 'app' ;
table : LeagueTable ;
gameweek : GameWeek ;
constructor ( private footballData : FootballDataService ) { }
ngOnInit ( ) {
this . getTable ( ) ;
}
getTable ( ) {
this . footballData . getTable ( )
. subscribe (
data => {
this . table = data ; // Note that we store the data locally
this . getFixtures ( data . matchday ) ; // Call this function only after receiving data from the server
} ,
error => console . log ( error )
) ;
}
getFixtures ( matchDay : number ) {
this . footballData . getFixtures ( matchDay )
. subscribe (
data => this . gameweek = data , // Again, save locally
error => console . log ( error )
) ;
}
}
Jetzt kommen wir irgendwo!
Da wir die Daten als Mitgliedsvariable in unserer TypsScript -Komponente festgelegt haben, kann sie direkt von der zugehörigen HTML zugegriffen werden. Wenn Sie Visual Studio Code, den Open-Source-Editor von Microsoft, verwenden, können Sie das Angular Language-Service-Plugin hinzufügen, um JavaScript-Code-Fertigstellung in HTML zu erhalten! Toll. Und es wird vom Angular -Team gepflegt.
Ersetzen wir die Dummy -Daten von zuvor:
< div class =" container " >
< h1 > Live football scores </ h1 >
< div class =" score-card-list " >
< mat-card class =" score-card " *ngFor =" let fixture of gameweek.fixtures " >
< span class =" home " > {{ fixture.homeTeamName }} </ span >
< span class =" score " > {{ fixture.result.goalsHomeTeam }} : {{ fixture.result.goalsAwayTeam }} </ span >
< span class =" away " > {{ fixture.awayTeamName }} </ span >
</ mat-card >
</ div >
</ div >
Beachten Sie die gameweek?.fixtures
syntax: die ?
Symbol fungiert als Kurzhand für if (gameweek != null) { return gameweek.fixtures } else { return null }
, und es ist unglaublich nützlich, wenn Sie auf Variablen zugreifen, die nur von asynchronen REST-Anrufen bevölkert werden.
Et voila!
Dieser nächste Teil ist nicht ausschließlich notwendig, zeigt jedoch eine wichtige Winkelmethode und wird auf jeden Fall dazu beitragen, unseren Code modular zu halten und einzubeziehen, wenn wir uns entscheiden, ihn voranzutreiben (schauen Sie sich Nativescript als einen Weg, um eine zu erstellen native mobile App mit Angular und TypeScript).
Wir werden die Fixture Score -Karte in eine eigene Komponente abziehen. Beginnen Sie mit Hilfe der CLI: ng generate component score-card
(oder ng gc score-card
). Dadurch werden ein .ts
, .html
und .css
Dateien in src/app/score-card
erstellt.
Öffnen Sie score-card.component.ts
um von einem vertrauten Dekorateur begrüßt zu werden:
...
@ Component ( {
selector : 'app-score-card' , // Note this!
templateUrl : './score-card.component.html' ,
styleUrls : [ './score-card.component.css' ]
} )
...
Beachten Sie das Feld selector
-Es wird angezeigt, wie Sie auf die Komponente zugreifen (in diesem Fall <app-score-card></app-score-card>
-Tags).
Refactor unseren Code durch Verschieben des Fleisches von app.component.html
auf score-card.component.html
:
<!-- app.component.html -->
< div class =" container " >
< h1 > Live football scores </ h1 >
< div class =" score-card-list " >
< app-score-card *ngFor =" let fixture of gameweek?.fixtures " [fixture] =" fixture " > </ app-score-card >
</ div >
</ div >
<!-- score-card.component.html -->
< mat-card class =" score-card " >
< span class =" home " > {{ fixture.homeTeamName }} </ span >
< span class =" score " >
{{ fixture.result.goalsHomeTeam }} : {{ fixture.result.goalsAwayTeam }}
</ span >
< span class =" away " > {{ fixture.awayTeamName }} </ span >
</ mat-card >
Beachten Sie das [fixture]="fixture"
-Bit in den <app-score-card>
-Tags. So übergeben wir Informationen zwischen Komponenten.
In Winkelsyntax bezeichnet [...]
Eingänge, (…)
Ausgänge und [(…)]
eine Zwei-Wege-Bindung. [(…)]
Wird auch als "Banana -Box -Syntax" bezeichnet, und Sie werden es häufig in Form von [(ngModel)]="someVariable"
begegnen. Dies impliziert eine Zwei-Wege-Bindung zwischen dem Wert einer Variablen und dem Wert eines DOM-Objekts. Dies ist ein wesentlicher Bestandteil der Verwendung von Angular.
Zum Beispiel könnten wir den Wert eines input
direkt auf eine Variable abbilden, die auf dem Bildschirm angezeigt wird, und das DOM wird automatisch aktualisiert, wenn sich der Wert des input
ändert:
< p >
What is your name?
< input type =" text " [(ngModel)] =" name " />
</ p >
< p >
Your name: {{ name }}
</ p >
Sie können sich hier einen Beispiel Plunker ansehen.
Zurück zum Fußball: Um den Eingangswert in die Komponente zu erhalten, müssen wir wie folgt auch score-card.component.ts
aktualisieren:
import { Component , Input } from '@angular/core' ;
import { Fixture } from '../models/fixture' ;
@ Component ( {
selector : 'app-score-card' ,
templateUrl : './score-card.component.html' ,
styleUrls : [ './score-card.component.css' ]
} )
export class ScoreCardComponent {
@ Input ( ) fixture : Fixture ; // Note the decorator
constructor ( ) { }
}
Es gibt zwei offensichtliche Möglichkeiten, Daten zwischen Komponenten zu übergeben: Verwenden von @Input
/ @Output
und Verwendung von Diensten.
@Input()
Die erste Methode ist nützlich, um Daten zwischen Eltern und Kindern zu übergeben, kann jedoch mühsam sein, wenn Daten durch verschachtelte Schichten fliegen müssen. Daten können mit dem @Input
-Dekorator an eine untergeordnete Komponente übergeben werden. Diese Eingabevariable wird mit Referenz übergeben, wenn es sich um ein Objekt handelt oder von Wert übergeben, wenn es sich um ein Primitiv handelt.
// someComponent.ts
// ...
import { Input } from '@angular/core'
// ...
export class SomeComponent {
// @Input() variables get set after the `constructor(...)`
// method, but before `ngOnInit()` fires
@ Input ( ) aNumber : number ; // This gets set via parent HTML
// ...
}
<!-- someComponentParent.html -->
< h1 >
I am a parent where SomeComponent gets rendered
</ h1 >
<!-- Pass a value to the aNumber variable -->
< some-component [aNumber] =" 48 " > </ some-component >
@Output()
Daten können auch vom Kind mit dem Dekorateur @Output()
vom Kind an eine übergeordnete Komponente emittiert werden. Dies ist keine Richtungsbindung, sondern ein Ereignisemitter, der vordefinierte Zeiten abfeuert. Ein typischer Anwendungsfall würde den Elternteil benachrichtigen, wenn ein Wert im Kind geändert wird.
// someComponent.ts
// ...
import { Input , Output , EventEmitter } from '@angular/core'
// ...
export class SomeComponent {
@ Input ( ) aNumber : number ;
// Emits an event (of type `number`) to the parent
@ Output ( ) numberChanged : EventEmitter < number > = new EventEmitter < number > ( ) ;
// ...
// Event emitters need to be triggered manually
// Any object can be emitted
emitValueChanged ( ) : void {
this . numberChanged . emit ( this . aNumber ) ;
}
}
<!-- someComponentParent.html -->
< h1 >
I am a parent where SomeComponent gets rendered
</ h1 >
<!-- Pass a value to the aNumber variable -->
< some-component [aNumber] =" 48 " (valueChanged) =" aNumberChanged($event) " > </ some-component >
// someComponentParent.ts
export class SomeParentComponent {
// ...
aNumberChanged ( updatedNumber : number ) : void {
console . log ( `aNumber changed to ${ updatedNumber } ` ) ;
}
// ...
}
Nutzung von Diensten
Es gibt viele Möglichkeiten, Dienste zum Übergeben von Daten zwischen Komponenten zu verwenden. Die Details liegen außerhalb des Rahmens dieses Tutorials, aber es ist erwähnenswert, dass solche Techniken vorhanden sind, da es wahrscheinlich in einer relativ komplexen Anwendung erforderlich sein wird.
Das allgemeine Muster besteht darin, einen Observable
Stream im Dienst zu definieren, zu dem Komponenten Nachrichten verschieben oder sich über neue Nachrichten abonnieren können. Dies ist effektiv ein Eventbus.
Im allgemeinen Fall müssen die Nachrichten eingegeben werden, damit die Zuhörer erkennen können, welche anwendbar sind. Als etwas leichtfertiges Beispiel könnte der Dienst eine PersonNameChangedEvent
ausgeben, auf die die PersonComponent
reagieren könnte, während die LandingPageComponent
dieses Ereignis vollständig ignorieren könnte.
Angular bietet einen monolithischen und hochkommenden Rahmen für den Bau von Anwendungen. Dies bietet den Vorteil der Struktur - die Meinung des Frameworks hilft dem Benutzer, skalierbare Apps von Anfang an zu entwerfen, und ein Großteil der Komplexität ist dem Entwickler verborgen. Andererseits führt die Verwendung von Angular (und TypeScript) eine Menge Boilerplate -Code ein, die Sie verlangsamen könnten, wenn Sie eine kleine Anwendung erstellen. Daher lohnt es sich, überlegen zu können, wohin die App vor dem Eintauchen zu Angular fährt.
Die Winkel -CLI hat jedoch einen langen Weg zurückgelegt, und angesichts der Tatsache, dass sie in naher Zukunft wahrscheinlich für fast jedes Projekt Angular verwenden werde.