class: center, middle
https://angular.io/
--- web, mobile, desktop ---
class: center, middle
$ npm install @angular/cli -g
$ ng help
$ ng new libra-client -d
$ ng new libra-client --minimal --skip-install
--skip-tests --skip-git --prefix libra
- no routing
- scss/sass
$ cd libra-client
$ npm install
$ ng serve
→ http://localhost:4200/
package.json
angular.json
src/environments
könyvtársrc/assets
könyvtársrc/main.ts
srrc/app/app.module.ts
app/app.component.ts
- Modul (
NgModule
): összefüggő kódrészletek halmaza- deklarált entitások
- exportált entitások
- importált modulok
- publikált service-ek (
providers
) - bootstrap
- Komponens: a UI egy részéért felelős
selector
template
/templateUrl
styles
/stylesUrl
localhost:4200/books
→- hozzáférés a szerverhez, könyvek lekérdezése
- összes könyv megjelenítése
localhost:4200/books/<ISBN>
- hozzáférés a szerverhez és a könyv lekérdezése
- könyv adatainak megjelenítése
//libra-api.service.ts
import { Injectable } from '@angular/core';
@Injectable()
export class LibraApiService {
constructor() { }
}
//app.module.ts
import { LibraApiService } from './libra-api.service';
//...
providers: [LibraApiService],
//models.ts
export interface IBook {
title : string;
isbn : string;
}
//app.module.ts
import { HttpClientModule } from '@angular/common/http';
//...
imports: [
//...
HttpClientModule
],
//libra-api.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { IBook } from './models';
import { Observable } from 'rxjs';
@Injectable()
export class LibraApiService {
constructor(private http: HttpClient) { }
public getBooks(): Observable<IBook[]> {
return this.http.get<IBook[]>("http://localhost:3000/books");
}
public getBook(isbn: string): Observable<IBook> {
return this.http.get<IBook>(`http://localhost:3000/books/${isbn}`);
}
}
- Reaktív programozás: aszinkron programozási paradigma (
RxJS
) - Observable: típusos stream
- 1 → 2 → 4 → 6 ... (
Observable<number>
) - Aszinkron módon érkeznek az új értékek
- 1 → 2 → 4 → 6 ... (
- Hány eleme lesz?
- Használat:
let a: Observable<number>
a.subscribe(value => {
console.log(value);
});
Manuális leiratkozás
let subscription = a.subscribe(...);
subscription.unsubscribe();
complete esemény: observable vége → automatikus leíratkozás
$ ng g c --help
$ ng g c books --flat --skip-tests -m app
→ books.component.ts
→ books.component.scss
→ books.component.html
//app.module.ts
//...
declarations: [
AppComponent,
BooksComponent
],
//books.component.ts
@Component({
selector: 'libra-books',
templateUrl: './books.component.html',
styleUrls: ['./books.component.scss']
})
export class BooksComponent implements OnInit {
constructor(private apiSvc: LibraApiService) { }
ngOnInit() {
this.apiSvc.getBooks().subscribe(result => this.books = result);
}
books: IBook[]
}
<!-- books.component.html -->
<ul *ngIf="books">
<li *ngFor="let book of books">
{{book.title}} (ISBN: {{book.isbn}})
</li>
</ul>
//app.component.ts
//...
template: `<libra-books></libra-books>`,
- Kezdetben a
books
tagváltozó értékeundefined
ngOnInit
-ben aszinkron hívás → egyszer később megváltozik egy valós listára- Komponens osztály és HTML sablon összekötése
- angular change detection
- Változásértesítés
- Mit néz?
- Mikor fut le?
- Selector (pl.
libra-books
)- Bent marad a végső HTML-ben → mihez kezd vele a böngésző?
- Komponens osztály (
@Component(...)
)- tagváltozók
- metódusok
- Angular életciklus hook-ok (pl.
ngOnInit
)
- Angular HTML sablon
*ngIf
,*ngFor
{{}}
- Speciális jelentéssel bíró tagek (pl.
ng-container
) - események később
- Sablon és komponens osztály összekötése
- Például:
HttpClient
,LibraApiService
- Ki hozza létre a service-eket?
- Angular
- Injektálja minden helyre, ahol kérjük
- Miért?
- Életcilus management
- Függőség (dependency)
//book.component.ts
import { Component, OnInit } from '@angular/core';
import { IBook } from './models';
import { ActivatedRoute } from '@angular/router';
import { LibraApiService } from './libra-api.service';
@Component({
selector: 'libra-book',
templateUrl: './book.component.html',
styleUrls: ['./book.component.scss']
})
export class BookComponent implements OnInit {
constructor() { }
book : IBook;
ngOnInit() {
}
}
<!-- book.component.html -->
<ng-container *ngIf="book">
{{book.title}} (ISBN: {{book.isbn}})
</ng-container>
//app-routing.module.ts
import { NgModule } from "@angular/core";
import { Routes, RouterModule } from "@angular/router";
const routes: Routes = [];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
//app.module.ts
//...
imports: [
BrowserModule,
AppRoutingModule
],
//...
//app-routing.module.ts
const routes: Routes = [
{path: '', component: BooksComponent},
{path: 'books', component: BooksComponent},
{path: 'books/:isbn', component: BookComponent}
];
//app.component.ts
//...
template: `<router-outlet></router-outlet>`,
→ http://localhost:4200/
: BooksComponent
→ http://localhost:4200/books
: BooksComponent
→ http://localhost:4200/books/ISBN
: BookComponent
@Component({
selector: 'libra-book',
templateUrl: './book.component.html',
styleUrls: ['./book.component.scss']
})
export class BookComponent implements OnInit {
constructor(private route: ActivatedRoute,
private libraApiSvc : LibraApiService) { }
book : IBook;
ngOnInit() {
this.route.params.subscribe(parameters => {
this.libraApiSvc.getBook(parameters.isbn).subscribe(result =>
this.book = result);
});
}
}