npm i -g @angular/cli
ng new warsawjs-workshop-29-movies
ng, np.
ng serve
start z package.json - dopisać opcję
--opennpm start
webpack-dev-server uruchamia apkę i reaguje na zmiany w
kodzietitle na
"WarsawJS-Movies"
AppComponent (plik app.component.ts),
można "osadzić" w HTML-u (app.component.html)title:
test = 'nowości';
{{test}} np. zamiast linijki z
imgonClick() { alert('Klik, klik!'); }
<h1>:
<h1 (click)="onClick()">
h1 { cursor: pointer; }
export class Movie {
id: number;
title: string;
description: string;
url: string;
}
import { Component, NgModule } from '@angular/core';
@NgModule({ /* opcje */ })
export class AppModule { }
@Component({ /* opcje */ })
export class AppComponent {
/* ... */
}
ng g component movie
<div style="text-align:center">
<h1 (click)="onClick()">
Witaj w {{ title }}!
</h1>
{{test}}
</div>
<app-movie></app-movie>
<wjs-movie>
zamiast <app-movie>MovieComponent dodać:
movie: Movie = {
id: 1,
title: 'Subiektywny przegląd sytuacji na froncie - meet.js Poznań',
description: '"Nowy dzień, nowy framework". Jak żyć?',
url: 'https://www.youtube.com/embed/Aybh_2pIi2I'
}
import { Movie } from './movie';
Movie
<h1>{{movie.title}}</h1>
<iframe width="560" height="315" src="{{movie.url}}" frameborder="0"
allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen>
</iframe>
<p>{{movie.description}}</p>
import { DomSanitizer } from '@angular/platform-browser';
private sanitizer: DomSanitizer;
constructor(sanitizer: DomSanitizer) {
this.sanitizer = sanitizer;
}
getWrappedMovieUrl:
getWrappedMovieUrl() {
return this.sanitizer.bypassSecurityTrustResourceUrl(this.movie.url);
}
[src]="getWrappedMovieUrl()"
private sanitizer: DomSanitizer;
constructor(sanitizer: DomSanitizer) {
this.sanitizer = sanitizer;
}
można:
constructor(private sanitizer: DomSanitizer) {}
get jest częstym tematem i
zamiast:
getWrappedMovieUrl() { /* ... */ }
można:
get wrappedMovieUrl() { /* ... */ }
[src]="wrappedMovieUrl"
ng add @angular/material
@import "@angular/material/prebuilt-themes/pink-bluegrey.css";
class="mat-app-background" do znacznika
<body> w index.html
import { MatCardModule } from '@angular/material/card';
import { MatButtonModule } from '@angular/material/button';
i użyć ich w opcji imports
<mat-card>
<mat-card-header>
<mat-card-title>{{movie.title}}</mat-card-title>
</mat-card-header>
<iframe mat-card-image height="315" [src]="wrappedMovieUrl" frameborder="0"
allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen>
</iframe>
<mat-card-content>
<p>{{movie.description}}</p>
</mat-card-content>
<mat-card-actions>
<button mat-button>LIKE</button>
</mat-card-actions>
</mat-card>
mat-card { width: 560px; }
<app-movie> (lub wjs-movie) do
app.component.htmlmovies:
ng g component movies
Movie w nowym komponencie:
import { Component, OnInit } from '@angular/core';
import { Movie } from '../movie/movie';
@Component({
selector: 'wjs-movies',
templateUrl: './movies.component.html',
styleUrls: ['./movies.component.css']
})
export class MoviesComponent implements OnInit {
movies: Movie[] = [{
id: 1,
title: 'Subiektywny przegląd sytuacji na froncie - meet.js Poznań',
description: '"Nowy dzień, nowy framework". Jak żyć?',
url: 'https://www.youtube.com/embed/Aybh_2pIi2I'
}, {
id: 2,
title: 'Mateusz Chrzonstowski - Subiektywny przegląd front-endów |#49 IT Akademia j-labs',
description: `"Nowy dzień, nowy framework". Słyszeliście o tym?
Mateusz jest jedną z osób śledzących front-endy i chce podzielić się z Wami swoimi obserwacjami.`,
url: 'https://www.youtube.com/embed/KDTP9Dfkh1Q'
}]
constructor() {}
ngOnInit() {}
}
Input z
'@angular/core'movie (usunąć stare przypisanie):
@Input() movie: Movie;
<wjs-movie *ngFor="let m of movies" [movie]="m"></wjs-movie>
:host {
display: flex;
justify-content: space-around;
}
movies używa w swoim HTML-u komponentu movie, więc
musi wstawić mu coś w @Input
<wjs-movie [movie]="currentMovie"></wjs-movie>
:host pozwala nadać styl komponentowi, bezpośrednio
ng g service movies --flat=false
import { Injectable } from '@angular/core';
import { Movie } from '../movie/movie';
@Injectable({
providedIn: 'root'
})
export class MoviesService {
constructor() { }
readMovies(): Promise<Movie[]> {
return Promise.resolve([{/* 1 */}, {/* 2 */}, {
id: 3,
title: 'Lessons from writing my own Angular utility lib',
description: `I had a dream.
I wanted to create a popular open-source solution on top of Angular 2+`,
url: 'https://www.youtube.com/embed/AKZ_GShIg48'
}])
}
}
import { MoviesService } from './movies.service';
MoviesService do MoviesComponent (tak jak
DomSanitizer w MovieComponent)
ngOnInit:
async ngOnInit() {
this.movies = await this.service.readMovies();
}
flex-wrap: wrap; do stylu :hosta w
movies.component.cssngOnInit - odpala się po konstruktorze, gdy Inputy
już znane; wołana razPromise - obietnica zwrócenia jakichś danychasync, await - czekanie aż obietnica będzie zawierać
dane
{
"id": 1,
"title": "Subiektywny przegląd sytuacji na froncie - meet.js Poznań",
"description": "\"Nowy dzień, nowy framework\". Jak żyć?",
"url": "https://www.youtube.com/embed/Aybh_2pIi2I"
}
moviesUrl: 'http://localhost:4200/assets/movies.json'
import { HttpClientModule } from '@angular/common/http';
HttpClientModule do imports
import { HttpClient } from '@angular/common/http';
import { environment } from '../../environments/environment';
HttpClient w konstruktorze MoviesService (tak
jak
DomSanitizer w MovieComponent)
readMovies na:
return this.http.get<Movie[]>(environment.moviesUrl).toPromise();
import { FormsModule } from '@angular/forms';
import { MatInputModule } from '@angular/material/input';
movies w movies.component.ts:
searchTitle = '';
private movies: Movie[] = [];
get filteredMovies() {
return this.movies
.filter(m => m.title.toLowerCase()
.includes(this.searchTitle.toLowerCase()));
}
<mat-form-field>
<input matInput type="search" placeholder="Szukaj" [(ngModel)]="searchTitle">
</mat-form-field>
<main>
<wjs-movie *ngFor="let m of filteredMovies" [movie]="m"></wjs-movie>
</main>
mat-form-field {
display: block;
width: 20em;
margin: 0 auto;
}
main {
display: flex;
flex-wrap: wrap;
justify-content: space-around;
}
*ngIf
DomSanitizera