SPAS menjadi trendi sebagai antitesis ke situs web yang ditampilkan di sisi server. Ada pro dan kontra, seperti biasa, tetapi spa dapat menciptakan pengalaman pengguna yang lancar yang sulit ditiru tanpa pendekatan seperti itu. Ini adalah bagian dari usaha aplikasi web ke wilayah yang secara tradisional ditempati oleh aplikasi desktop. Aplikasi web umumnya dikritik karena lamban dibandingkan dengan aplikasi desktop, tetapi kemajuan besar dalam teknologi web (terutama nodej dan mesin V8 Google, serta kerangka kerja seperti sudut dan reactjs) serta akses arus utama ke daya komputasi yang belum pernah terjadi sebelumnya berarti bahwa ini adalah banyaknya) lebih sedikit masalah daripada dulu.
Fungsi SPAS dengan memuat satu halaman HTML pada klien, dan kemudian memperbarui konten (dan DOM) secara dinamis - sebagai lawan mengambil halaman HTML yang diperbarui dari server setiap kali pengguna mengklik di mana saja.
NodeJS
dan npm
dengan mengikuti instruksi yang sesuai di sini.TypeScript
dari sini.npm install -g @angular/cli
ng new my-project
cd my-project && ng serve
localhost:4200
di browser web Anda. Jika Anda membuka my-project/src/app/app.component.ts
Anda harus disambut dengan sesuatu seperti berikut:
/** 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
}
Mari kita hancurkan sedikit:
Component
dari modul @angular
yang terletak di folder node_modules
.@Component
menandai kelas sebagai komponen sudut. Dekorator diparameterisasi dengan objek opsi, yang akan kami gunakan hanya beberapa parameter.selector
mendefinisikan apa tag HTML untuk komponen itu-misalnya, yang satu ini akan disuntikkan ke HTML menggunakan <app-root> … </app-root>
.templateUrl
mengambil argumen string yang menunjuk ke file HTML yang berfungsi sebagai bagian tampilan dari komponen. Anda juga dapat menggunakan parameter template
untuk menulis HTML secara langsung, sebagai lawan menunjuk ke file. Ini umumnya tidak disarankan, kecuali bagian tampilan hanyalah satu atau dua baris.styleUrls
mengambil daftar string, di mana setiap string adalah jalur ke file CSS.title
dapat dirujuk dari app.component.html
. Arahkan ke app.component.html
. Ini adalah titik masuk ke aplikasi kami, dan HTML tingkat tertinggi yang harus Anda edit. Semuanya akan diterjemahkan dalam konteks ini.
Kami sekarang akan menghapus konten file ini, dan menggantinya dengan yang berikut:
< 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 >
Balikkan kembali ke browser web Anda, dan Anda harus melihat bahwa halaman diperbarui secara otomatis. Besar.
Secara visual Anda mungkin akan kecewa pada tahap ini, tetapi ini adalah pekerjaan yang sedang berlangsung.
Bahan Angular adalah perpustakaan yang dikelola oleh tim dari Google untuk menyediakan komponen desain material yang mudah digunakan untuk aplikasi sudut. Gaya komponen -komponen ini dapat diubah hingga konten hati Anda, tetapi juga memberikan cara mudah untuk meningkatkan tampilan dan nuansa aplikasi prototipe dengan upaya minimal.
Mari kita instal pustaka yang diperlukan dengan npm install --save @angular/material @angular/cdk @angular/animations
. Ini mengunduh file yang diperlukan ke folder node_modules
Anda, dan memperbarui file packages.json
dengan tepat.
Anda juga harus memberi tahu Angular untuk memuat komponen yang relevan. Anda harus melakukan beberapa googling tentang cara kerjanya (ini adalah tutorial 101 lakban), tetapi pada dasarnya Anda hanya perlu memodifikasi file app.modules.ts
untuk memasukkan modul yang Anda butuhkan.
Pertama, tambahkan animasinya seperti itu:
import { BrowserAnimationsModule } from '@angular/platform-browser/animations' ;
@ NgModule ( {
...
imports : [ BrowserAnimationsModule ] ,
...
} )
Kemudian tambahkan impor modul yang kita butuhkan:
import { MatButtonModule , MatCardModule } from '@angular/material' ;
@ NgModule ( {
...
imports : [ MatButtonModule , MatCardModule ] ,
...
} )
Ketahuilah bahwa Anda perlu mengimpor komponen mana pun yang Anda gunakan di aplikasi Anda. Alasan untuk tidak memasukkan seluruh perpustakaan adalah untuk membantu webpack
melakukan pengocok pohon, yang pada dasarnya mensyaratkan meninggalkan potongan kode yang tidak digunakan ketika menggabungkan semua kode kami ke beberapa file .js
yang lebih banyak.
Setelah ini selesai, kami akan memiliki akses ke sekelompok komponen yang telah ditentukan, dan Anda dapat mengimpornya sesuai kebutuhan. Perlu juga dicatat bahwa tema prebuilt mudah digunakan.
Dalam sudut, komponen adalah modular. Setiap komponen memiliki file CSS sendiri, yang hanya berlaku untuk tampilan spesifik itu. Satu pengecualian adalah file styles.css
yang ditemukan di direktori src
yang berlaku secara global.
Styling bukanlah fokus dari tutorial ini, jadi kami akan mencoba menghindarinya sebanyak mungkin ke depan. Untuk merasa sedikit lebih baik tentang apa yang kami buat, berikut adalah beberapa CSS sederhana untuk disalin dan menempel ke file styles.css
(praktik yang lebih baik akan menambahkan bit yang relevan ke file CSS komponen yang sesuai, untuk referensi di masa mendatang):
// 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 ;
}
Perbarui juga HTML Anda untuk memasukkan kelas:
...
< 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 >
...
Jika Anda bingung tentang flex
, saya sangat merekomendasikan untuk memeriksa Flexbox Froggy.
Salah satu keuntungan menggunakan kerangka kerja seperti Angular adalah kami dapat menerapkan beberapa logika pemrograman secara langsung di HTML. Dalam kasus kami, for-loop akan membuat hidup lebih mudah.
Coba yang berikut:
...
< 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 >
...
Ini memperkenalkan berbagai konsep baru, dan harus menghasilkan sesuatu seperti berikut:
Konsep yang perlu diperhatikan:
{{ 'Some text = ' + a_number }}
Layanan digunakan untuk abstrak akses data yang jauh dari komponen. Ini memungkinkan komponen untuk tetap ramping dan fokus pada mendukung tampilan. Pengujian unit dan pemeliharaan kode disederhanakan dengan mempertahankan pemisahan tanggung jawab ini.
Untuk menghasilkan layanan menggunakan CLI, Anda dapat menggunakan ng generate service football-data
(atau ng gs football-data
untuk orang yang kekurangan waktu). Ini akan membuat dua file baru di Direktori project-dir/src/app
Anda: football-data.service.ts
dan football-data.service.spec.ts
. Ini mengikuti konvensi sudut dimana file uji dapatkan ekstensi .spec.ts
. Meskipun pengujian bermanfaat dan penting, itu berada di luar ruang lingkup langsung tutorial ini sehingga Anda dapat mengabaikannya untuk saat ini (maaf, @cornel).
Tambahkan baris berikut ke 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 ( ) { }
}
Layanan dijelaskan dengan @Injectable
, yang memberi tahu kompiler bahwa contoh layanan dapat disuntikkan ke dalam komponen. Anda juga perlu menentukan penyedia untuk setiap layanan. Penyedia secara efektif menyediakan singleton di level yang ditentukan.
Misalnya, Anda dapat menambahkan layanan Anda ke array penyedia di app.module.ts
, yang akan menghasilkan instance singleton dari layanan yang diekspos di seluruh aplikasi. Kalau tidak, Anda dapat menambahkannya ke daftar penyedia komponen, yang akan menghasilkan contoh singleton yang tersedia untuk komponen itu dan komponen apa pun dalam konteksnya.
PERINGATAN: Menjadi mudah untuk membuat ketergantungan melingkar antara layanan setelah aplikasi Anda tumbuh lebih besar. Berhati -hatilah dengan ini. Jika (kapan) Anda pernah mendapatkan pesan kesalahan yang terlihat seperti Cannot resolve all parameters for MyDataService(?)
, Ini mungkin terkait dengan masalah ketergantungan melingkar.
Kami akan memanfaatkan API yang fantastis yang tersedia secara bebas di sepak bola-Data.org. Anda harus mendapatkan kunci API sendiri, tetapi mudah dilakukan - cukup ikuti instruksi di situs. Ada lebih banyak dokumentasi mendalam yang tersedia, tetapi 99% dari apa yang Anda butuhkan dapat dilihat dalam contoh-contoh kecil yang tercantum di sini.
Untuk contoh ini, yang benar -benar ingin kami lakukan adalah mengambil info game untuk semua game di babak saat ini (alias "Game Week" atau "Match Day"). The /v1/competitions/{id}/fixtures
Endpoint Mengembalikan informasi ini, tetapi untuk semua putaran sebelumnya di musim saat ini. Untuk mendapatkan info untuk satu putaran, kita perlu mengatur parameter matchday
, misalnya /v1/competitions/{id}/fixtures?matchday=14
.
Untuk mendapatkan hari pertandingan saat ini, kita dapat meminta tabel liga, karena kembali untuk hari pertandingan saat ini secara default.
Pertama, kita perlu menyuntikkan layanan HttpClient
ke dalam FootballDataService
kami untuk memanfaatkan fungsi HTTP Angular:
import { HttpClient , HttpHeaders } from '@angular/common/http' ;
...
constructor ( private http : HttpClient ) { }
. . .
PENTING : Menambahkan variabel pribadi ke konstruktor layanan atau komponen sudut, bersama dengan deklarasi tipe TypeScript tertentu, adalah informasi yang cukup untuk sihir hitam Angular untuk bekerja. Kompiler sekarang akan menyuntikkan instance yang sesuai ke dalam layanan ini, sehingga Anda memiliki akses ke sana.
Mari kita tambahkan fungsi untuk mengambil tabel liga (dan hari pertandingan saat ini) dari server:
...
getTable ( ) {
return this . http . get ( this . COMPETITION_URL + this . PL_ID + '/leagueTable' ,
{ headers : this . HEADERS } ) ;
}
...
TypeScript akan membantu Anda dengan ini, tetapi tanda tangan metode untuk metode http.get
Angular terlihat sebagai berikut:
/**
* 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 > ;
Tanda pertanyaan menunjukkan bahwa headers
parameter, observe
, params
, reportProgress
, responseType
dan withCredentials
semuanya opsional sebagai bagian dari objek opsional untuk options
. Kami hanya akan memberikan nilai untuk url
dan options.headers
. Headers.
Anda mungkin bertanya -tanya apa fungsi getTable()
yang baru saja kami buat kembali. Nah, itu mengembalikan aliran Observable
. Pada dasarnya Observable
adalah, seperti yang dikatakan Luuk Gruijs, "koleksi malas dari banyak nilai dari waktu ke waktu". Yang kedengarannya gila, tetapi sebenarnya cukup mudah.
Singkatnya, aliran Observable
dianggap "dingin" sampai berlangganan - yaitu variabel hanya dimuat dengan malas setelah outputnya digunakan. Setelah aliran "panas", ia akan memperbarui semua pelanggan kapan pun nilainya berubah. Ini adalah alternatif untuk menggunakan Promise
untuk menangani situasi async di JavaScript.
Dalam hal ini, permintaan GET
hanya akan dipecat setelah variabel Observable
berlangganan karena antarmuka istirahat hanya akan mengembalikan satu nilai per panggilan.
Kita dapat menggunakan kekuatan pengetikan statis dalam TypeScript untuk membuat ini lebih eksplisit:
...
import { Observable } from 'rxjs/Observable' ;
...
getTable ( ) : Observable < any > {
return this . http . get ( this . COMPETITION_URL + this . PL_ID + '/leagueTable' ,
{ headers : this . HEADERS } ) ;
}
...
Faktanya, karena dokumentasi sepakbola-data.org memberi tahu kita apa yang diharapkan dari panggilan lainnya, kita dapat melangkah lebih jauh dan memodelkan objek juga, di src/app/models/leagueTable.ts
:
import { Team } from './team' ;
export class LeagueTable {
leagueCaption : string ;
matchday : number ;
standing : Team [ ] ;
}
Dan di 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 ;
}
Yang memungkinkan kami untuk memperbarui football-data.service.ts
ke:
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 ) ;
}
...
Ini akan membantu kita mempertahankan kewarasan kita dengan meminimalkan model mental yang kita butuhkan untuk tetap up to date saat bekerja dengan objek yang kompleks, karena IDE dapat memandu kita.
Catatan: Kata kunci as
hanya memberi tahu Typescript untuk mempercayai kami tentang jenis objek, daripada mencoba mencari tahu melalui semacam inspeksi. Berbahaya tapi berguna, seperti hal -hal paling menarik.
Oke, navigasikan kembali ke src/app/app.component.ts
, dan tambahkan baris berikut untuk menyuntikkan FootballDataService
ke dalam komponen:
import { FootballDataService } from './football-data.service' ;
...
export class AppComponent {
title = 'app' ;
constructor ( private footballData : FootballDataService ) { }
}
Sekarang kami juga akan menambahkan metode ngOnInit
ke komponen. Ini adalah kait siklus hidup standar yang disediakan oleh Angular yang menembak setelah semua sifat data yang terikat dari suatu komponen diinisialisasi. Ini pada dasarnya menembak inisialisasi objek, tetapi sedikit lebih lambat dari metode constructor
yang menembak sebelum semua input dan output ke komponen telah terdaftar.
Aturan praktis yang umum adalah selalu menempatkan kode yang ingin Anda bayar pada inisialisasi dalam metode ngOnInit
khusus ini, bukan konstruktor. Tambahkan ke komponen seperti itu:
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
}
...
Dalam kasus kami, kami ingin memuat meja liga, sehingga kami dapat menambahkan sesuatu seperti ini:
...
ngOnInit ( ) {
// Load league table from REST service
this . footballData . getTable ( )
. subscribe (
data => console . log ( data ) ,
error => console . log ( error )
) ;
}
...
Jika Anda membuka konsol di browser web Anda, Anda harus melihat sesuatu seperti ini:
Besar. Kami sekarang memiliki banyak data keren yang dapat kami lakukan di masa depan (tidak terkecuali tautan langsung ke gambar crest club), tetapi untuk saat ini kami benar -benar hanya tertarik pada hari pertandingan saat ini.
Sekarang mari kita tambahkan fungsi lain ke layanan data kami untuk mendapatkan informasi untuk putaran perlengkapan saat ini:
...
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 ) ;
}
...
dengan GameWeek
dan Fixture
didefinisikan sebagai berikut:
// 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 ; } ;
} ;
}
Dengan pengetahuan hari yang baru diperoleh kami, kami dapat meminta informasi server REST tentang putaran perlengkapan saat ini. Namun, kita perlu menunggu panggilan istirahat pertama untuk menyelesaikan terlebih dahulu sebelum melakukan yang kedua. Beberapa refactoring berarti bahwa kita dapat melakukannya dengan cukup mudah panggilan balik:
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 )
) ;
}
}
Sekarang kita akan mendapatkan di suatu tempat!
Karena kami telah menetapkan data sebagai variabel anggota pada komponen TypeScript kami, itu dapat secara langsung diakses oleh HTML terkait. Faktanya, jika Anda menggunakan kode Visual Studio, editor sumber terbuka Microsoft, Anda dapat menambahkan plugin layanan bahasa Angular untuk menyelesaikan penyelesaian kode JavaScript di HTML ! Luar biasa. Dan itu dipertahankan oleh tim sudut.
Mari ganti data boneka dari sebelumnya:
< 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 >
Perhatikan gameweek?.fixtures
sintaks: The ?
Simbol bertindak sebagai tangan pendek untuk if (gameweek != null) { return gameweek.fixtures } else { return null }
, dan itu sangat berguna ketika mengakses variabel yang hanya akan dihuni oleh panggilan istirahat asinkron.
Et voila!
Bagian selanjutnya ini tidak sepenuhnya diperlukan, tetapi itu menggambarkan cara sudut penting dalam melakukan sesuatu, dan pasti akan membantu menjaga kode kita tetap modular dan dapat dikenakan jika kita memutuskan untuk meneruskannya (lihat NativeScript sebagai cara untuk membuat a aplikasi seluler asli dengan sudut dan naskah).
Kami akan meredakan kartu skor fixture ke dalam komponennya sendiri. Mulailah dengan bantuan dari CLI: ng generate component score-card
(atau ng gc score-card
). Ini akan membuat file .ts
, .html
dan .css
di src/app/score-card
.
Buka score-card.component.ts
untuk disambut oleh dekorator yang akrab:
...
@ Component ( {
selector : 'app-score-card' , // Note this!
templateUrl : './score-card.component.html' ,
styleUrls : [ './score-card.component.css' ]
} )
...
Catatan Bidang selector
-Ini memberi tahu kami cara mengakses komponen (dalam hal ini menggunakan tag <app-score-card></app-score-card>
).
Refactor kode kami dengan memindahkan daging dari app.component.html
ke 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 >
Perhatikan bit [fixture]="fixture"
di dalam tag <app-score-card>
. Beginilah cara kami memberikan informasi antar komponen.
Dalam sintaks sudut, [...]
menunjukkan input, (…)
menunjukkan output, dan [(…)]
menunjukkan ikatan dua arah. [(…)]
juga disebut "sintaks kotak pisang", dan Anda akan sering menemukannya dalam bentuk [(ngModel)]="someVariable"
. Ini menyiratkan ikatan dua arah antara nilai variabel, dan nilai objek DOM. Ini adalah bagian penting dari menggunakan sudut.
Misalnya, kami dapat memetakan nilai tag input
langsung ke variabel yang ditampilkan di layar, dan DOM secara otomatis akan diperbarui setiap kali nilai elemen input
berubah:
< p >
What is your name?
< input type =" text " [(ngModel)] =" name " />
</ p >
< p >
Your name: {{ name }}
</ p >
Anda dapat memeriksa contoh Plunker di sini.
Kembali ke Sepak Bola: Untuk menerima nilai input ke dalam komponen, kita juga perlu memperbarui score-card.component.ts
sebagai berikut:
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 ( ) { }
}
Ada dua cara yang jelas untuk meneruskan data antar komponen: menggunakan @Input
/ @Output
, dan menggunakan layanan.
@Input()
Metode pertama berguna untuk menyampaikan data antara orang tua dan anak -anak, tetapi dapat membosankan jika data perlu melakukan perjalanan melalui lapisan bersarang. Data dapat diteruskan ke komponen anak menggunakan dekorator @Input
. Variabel input ini akan diteruskan dengan referensi jika itu adalah objek, atau diteruskan berdasarkan nilai jika itu primitif.
// 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()
Data juga dapat dipancarkan dari anak ke komponen induk menggunakan dekorator @Output()
. Ini bukan ikatan terarah, melainkan emitor peristiwa yang menembak pada waktu yang telah ditentukan. Kasus penggunaan yang khas akan memberi tahu orang tua ketika nilai diubah pada anak.
// 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 } ` ) ;
}
// ...
}
Menggunakan layanan
Ada banyak cara menggunakan layanan untuk melewati data antar komponen. Rinciannya di luar ruang lingkup tutorial ini, tetapi perlu dicatat keberadaan teknik tersebut, karena mungkin akan diperlukan dalam aplikasi yang relatif kompleks.
Pola umum adalah untuk mendefinisikan aliran Observable
dalam layanan, yang komponen dapat mendorong pesan, atau berlangganan untuk diberitahu tentang pesan baru. Ini secara efektif adalah bus acara.
Dalam kasus umum, pesan perlu diketik agar pendengar dapat membedakan mana yang berlaku. Sebagai contoh yang agak sembrono, layanan ini dapat memancarkan PersonNameChangedEvent
yang dapat bereaksi dengan PersonComponent
yang dapat diaktifkan sementara LandingPageComponent
mungkin memilih untuk mengabaikan peristiwa ini sepenuhnya.
Angular memberikan kerangka kerja monolitik dan sangat oportasi di dalam untuk membangun aplikasi. Ini memberikan keunggulan struktur - sifat kerangka kerja yang memiliki pendapat membantu pengguna untuk merancang aplikasi yang dapat diskalakan sejak awal, dan banyak kompleksitas disembunyikan dari pengembang. Di sisi lain, menggunakan Angular (dan naskah, dalam hal ini) memperkenalkan banyak kode boilerplate yang dapat memperlambat Anda jika Anda membuat aplikasi kecil, jadi ada baiknya mempertimbangkan ke mana aplikasi akan pergi sebelum datang ke Angular.
Namun, sudut CLI telah berjalan jauh, dan mengingat berapa banyak pengangkatan berat yang dilakukannya saya mungkin akan menggunakan Angular untuk hampir setiap proyek dalam waktu dekat.