Materiały na warsztat #1 2020.11.12
Sprawdź wersje bibliotek
node -v
ng version
firebase -v
Zaczynamy
ng new Start-Shop
? Would you like to add Angular routing? Yes
? Which stylesheet format would you like to use? SCSS
cd Start-Shop
code .
ng serve --open
Style
Plik: index.html
<link
href="https://fonts.googleapis.com/icon?family=Material+Icons"
rel="stylesheet"
/>
Plik: styles.scss
app-header {
width: 100%;
height: 68px;
background-color: #1976d2;
padding: 16px;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
* {
font-family: 'Roboto', Arial, sans-serif;
color: #616161;
box-sizing: border-box;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
body {
margin: 0;
}
.container {
display: flex;
flex-direction: row;
}
router-outlet + * {
padding: 0 16px;
}
/* Button */
.button, button {
display: inline-flex;
align-items: center;
padding: 8px 16px;
border-radius: 2px;
font-size: 14px;
cursor: pointer;
background-color: #1976d2;
color: white;
border: none;
}
.button:hover, button:hover {
opacity: 0.8;
font-weight: normal;
}
.button:disabled, button:disabled {
opacity: 0.5;
cursor: auto;
}
a {
cursor: pointer;
color: #1976d2;
text-decoration: none;
}
a:hover {
opacity: 0.8;
}
Pierwszy komponent
ng generate component header
Plik: header.component.html
<a [routerLink]="['/']">
<h1>Sklep z antykami</h1>
</a>
<a class="button shopping-button"><i class="material-icons">shopping_cart</i>Koszyk</a>
Plik: app.component.html
<app-header></app-header>
<div class="container">
<router-outlet></router-outlet>
</div>
Plik: header.component.scss
h1 {
color: white;
margin: 0;
}
.shopping-button {
background-color: white;
color: #1976d2;
}
.shopping-button i.material-icons {
color: #1976d2;
padding-right: 4px;
}
Produkty do sklepu
Plik: antics.ts
export const antics = [
{
name: 'Claude Monet - Kobieta z parasolem',
price: 1450,
description: 'Madame Monet i jej syn, czasami znana jako Spacer, to obraz olejny na płótnie autorstwa Claude'a Moneta z 1875 roku.'
},
{
name: 'Claude Monet - Impresja, wschód słońca',
price: 5800,
description: 'Impresja, wschód słońca – obraz namalowany przez Claude\’a Moneta, od tytułu którego nazwano kierunek w malarstwie – impresjonizm. Datowany na 1872 rok'
},
{
name: 'Claude Monet - Maki',
price: 7600,
description: 'Maki, obraz olejny.'
}
];
Lista obrazów
ng g c antic-list
Plik: app-routing.module.ts
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { AnticListComponent } from './antic-list/antic-list.component';
const routes: Routes = [
{ path: '', component: AnticListComponent },
];
Plik: antic-list.component.ts
import { Component, OnInit } from '@angular/core';
import { antics } from '../antics';
@Component({
selector: 'app-antic-list',
templateUrl: './antic-list.component.html',
styleUrls: ['./antic-list.component.scss']
})
export class AnticListComponent implements OnInit {
antics = antics;
constructor() { }
ngOnInit(): void {
}
}
Plik: antic-list.component.html
<h2>Obrazy</h2>
<div *ngFor="let antic of antics">
<h3>
<a [title]="'Szczegóły' + antic.name ">
{{ antic.name }}
</a>
</h3>
<p *ngIf="antic.description">Opis: {{ antic.description }}</p>
</div>
Strona produktu
ng g c antic-details
Plik: app-routing.module.ts
import { AnticDetailsComponent } from './antic-details/antic-details.component';
import { AnticListComponent } from './antic-list/antic-list.component';
const routes: Routes = [
{ path: '', component: AnticListComponent },
{ path: 'antics/:anticId', component: AnticDetailsComponent },
];
Plik: antic-list.component.html
<div *ngFor="let antic of antics; index as anticId">
<h3>
<a [title]="antic.name + ' details'" [routerLink]="['/antics', anticId]">
Plik: antic-details.component.ts
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { antics } from '../antics';
@Component({
selector: 'app-antic-details',
templateUrl: './antic-details.component.html',
styleUrls: ['./antic-details.component.scss'],
})
export class AnticDetailsComponent implements OnInit {
antic;
constructor(private route: ActivatedRoute) {}
ngOnInit(): void {
this.route.paramMap.subscribe((params) => {
this.antic = antics[+params.get('anticId')];
});
}
}
Plik: antic-details.component.html
<h2>Opis obrazu</h2>
<div *ngIf="antic">
<h3>{{ antic.name }}</h3>
<h4>{{ antic.price | currency }}</h4>
<p>{{ antic.description }}</p>
</div>
Koszyk zakupów
ng g s cart
Plik: cart.service.ts
export class CartService {
items = [];
addToCart(antic) {
this.items.push(antic);
}
getItems() {
return this.items;
}
clearCart() {
this.items = [];
return this.items;
}
}
Plik: antic-details.component.ts
constructor(
private route: ActivatedRoute,
private cartService: CartService
) { }
addToCart(antic) {
this.cartService.addToCart(antic);
window.alert('Antyk został dodany do koszyka zakupów!');
}
Plik: antic-details.component.html
<button (click)="addToCart(antic)">Kup</button>
ng g c cart
Plik: app-routing.module.ts
const routes: Routes = [
{ path: '', component: AnticListComponent },
{ path: 'antics/:anticId', component: AnticDetailsComponent },
{ path: 'cart', component: CartComponent },
];
Plik: header.component.html
<a class="button shopping-button" routerLink="/cart">
<i class="material-icons">shopping_cart</i>
Koszyk
</a>
Plik: cart.component.ts
export class CartComponent implements OnInit {
items;
constructor(private cartService: CartService) { }
ngOnInit(): void {
this.items = this.cartService.getItems();
}
}
Plik: cart.component.html
<h3>Koszyk zakupów</h3>
<div class="cart-item" *ngFor="let item of items">
<span>{{ item.name }}</span>
<span>{{ item.price | currency }}</span>
</div>
Opcje dostawy
Plik: src/assets/shipping.json
[
{
"type": "Poczta",
"price": 9.9
},
{
"type": "Paczkomat",
"price": 11.0
},
{
"type": "Kurier",
"price": 14.0
}
]
Plik: app.module.ts
...
import { NgModule } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';
import { AppRoutingModule } from './app-routing.module';
....
imports: [
BrowserModule,
HttpClientModule,
AppRoutingModule
],
...
Plik: cart.service.ts
constructor(
private http: HttpClient
) { }
...
getShippingPrices() {
return this.http.get('/assets/shipping.json');
}
ng g c shipping
Plik: app-routing.module.ts
const routes: Routes = [
{ path: '', component: AnticListComponent },
{ path: 'antics/:anticId', component: AnticDetailsComponent },
{ path: 'cart', component: CartComponent },
{ path: 'shipping', component: ShippingComponent },
];
Plik: shipping.component.ts
import { Component, OnInit } from '@angular/core';
import { CartService } from '../cart.service';
@Component({
selector: 'app-shipping',
templateUrl: './shipping.component.html',
styleUrls: ['./shipping.component.scss'],
})
export class ShippingComponent implements OnInit {
shippingCosts;
constructor(private cartService: CartService) { }
ngOnInit(): void {
this.shippingCosts = this.cartService.getShippingPrices();
}
}
Plik: shipping.component.html
<h3>Koszty dostawy</h3>
<div class="shipping-item" *ngFor="let shipping of shippingCosts | async">
<span>{{ shipping.type }}</span>
<span>{{ shipping.price | currency }}</span>
</div>
Plik: cart.component.html
...
<p>
<a routerLink="/shipping">Koszty dostawy</a>
</p>
Adres dostawy
Plik: app.module.ts
import { ReactiveFormsModule } from '@angular/forms';
...
imports: [
BrowserModule,
HttpClientModule,
AppRoutingModule,
ReactiveFormsModule,
],
Plik: cart.component.ts
export class CartComponent implements OnInit {
items;
checkoutForm;
constructor(
private cartService: CartService,
private formBuilder: FormBuilder
) {
this.checkoutForm = this.formBuilder.group({
name: '',
address: '',
});
}
....
onSubmit(customerData) {
this.items = this.cartService.clearCart();
this.checkoutForm.reset();
alert(`Twoje zamówienie ${customerData.name} zostało wysłane do ${customerData.address}.`);
}
}
Plik: cart.component.html
...
<form [formGroup]="checkoutForm" (ngSubmit)="onSubmit(checkoutForm.value)">
<div>
<label for="name"> Nazwisko </label>
<input id="name" type="text" formControlName="name" />
</div>
<div>
<label for="address"> Adres </label>
<input id="address" type="text" formControlName="address" />
</div>
<button class="button" type="submit">Kup</button>
</form>
Publikacja
https://console.firebase.google.com
firebase projects:list
ng add @angular/fire
ng deploy
Idź do adresu „Hosting URL:”
Praca domowa
- Dodać komponent CartSummary i przenieść do niego przycisk „Kup”. Ma on wyświetlać podsumowanie zakupów i adres dostawy.
- Utwórz wybieranie sposoby dostawy. Można dodać do każdej opcji dostawy przycisk „wybierz” w komponencie shipping. Dane przesłać do cart.service.ts i pokazywać w CartSummary.
- Dopisać style dla klas shipping-item, cart-item.