Materiały na warsztat #4 2020-12-03
Na dzisiejszych warsztatach zapoznamy się z upiększaniem Twojej aplikacji. Do styli użyjemy biblioteki Angular Material plus Flex Layout.
Zaczynajmy.
Instalacja Angular Material
ng new zrobmy-quizz ? Would you like to add Angular routing? Yes ? Which stylesheet format would you like to use? SCSS
cd zrobmy-quizz code .
https://material.angular.io/guide/getting-started
ng add @angular/material ? Choose a prebuilt theme name, or "custom" for a custom theme: Deep Purple/Amber ? Set up global Angular Material typography styles? Yes ? Set up browser animations for Angular Material? Yes ✔ Packages installed successfully. UPDATE src/app/app.module.ts UPDATE angular.json UPDATE src/index.html UPDATE src/styles.scss
app.module.ts
import { MatSliderModule } from '@angular/material/slider'; .... imports: [ .... BrowserAnimationsModule, MatSliderModule ],
app.component.html
<mat-slider min="1" max="100" step="1" value="1"></mat-slider> <router-outlet></router-outlet>
ng serve -o
Kontrolki (Komponenty UI)
https://material.angular.io/components/categories
app.component.html
<mat-card class="example-card"> <mat-card-header> <div mat-card-avatar class="example-header-image"></div> <mat-card-title>Shiba Inu</mat-card-title> <mat-card-subtitle>Dog Breed</mat-card-subtitle> </mat-card-header> <img mat-card-image src="https://material.angular.io/assets/img/examples/shiba2.jpg" alt="Photo of a Shiba Inu"> <mat-card-content> <p> The Shiba Inu is the smallest of the six original and distinct spitz breeds of dog from Japan. A small, agile dog that copes very well with mountainous terrain, the Shiba Inu was originally bred for hunting. </p> </mat-card-content> <mat-card-actions> <button mat-button>LIKE</button> <button mat-button>SHARE</button> </mat-card-actions> </mat-card>
app.component.scss
.example-card { max-width: 400px; } .example-header-image { background-image: url('https://material.angular.io/assets/img/examples/shiba1.jpg'); background-size: cover; }
Tworzenie modułu
cd src/app ng g m material
material.module.ts
import { MatSliderModule } from '@angular/material/slider'; import { MatCardModule } from '@angular/material/card'; @NgModule({ declarations: [], imports: [ CommonModule, MatSliderModule, MatCardModule, ], exports: [ MatSliderModule, MatCardModule, ] })
app.module.ts
import { MaterialModule } from './material/material.module'; @NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, AppRoutingModule, BrowserAnimationsModule, MaterialModule ],
Inne kontrolki
material.module.ts
import { MatCardModule } from '@angular/material/card'; import { MatDatepickerModule } from '@angular/material/datepicker'; import { MatFormFieldModule } from '@angular/material/form-field'; import { MatInputModule } from '@angular/material/input'; import { MatNativeDateModule } from '@angular/material/core'; @NgModule({ declarations: [], imports: [ CommonModule, MatCardModule, MatDatepickerModule, MatNativeDateModule, MatFormFieldModule, MatInputModule, ], exports: [ MatCardModule, MatDatepickerModule, MatNativeDateModule, MatFormFieldModule, MatInputModule, ] })
app.component.html
<mat-form-field appearance="fill"> <mat-label>Choose a date</mat-label> <input matInput [matDatepicker]="picker"> <mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle> <mat-datepicker #picker></mat-datepicker> </mat-form-field> <router-outlet></router-outlet>
Materiał Schematics
https://material.angular.io/guide/schematics
ng generate @angular/material:navigation navigation
material.module.ts
import { MatCardModule } from '@angular/material/card'; import { MatDatepickerModule } from '@angular/material/datepicker'; import { MatFormFieldModule } from '@angular/material/form-field'; import { MatInputModule } from '@angular/material/input'; import { MatNativeDateModule } from '@angular/material/core'; import { LayoutModule } from '@angular/cdk/layout'; import { MatToolbarModule } from '@angular/material/toolbar'; import { MatButtonModule } from '@angular/material/button'; import { MatSidenavModule } from '@angular/material/sidenav'; import { MatIconModule } from '@angular/material/icon'; import { MatListModule } from '@angular/material/list'; @NgModule({ declarations: [], imports: [ CommonModule, MatCardModule, MatDatepickerModule, MatNativeDateModule, MatFormFieldModule, MatInputModule, LayoutModule, MatToolbarModule, MatButtonModule, MatSidenavModule, MatIconModule, MatListModule ], exports: [ MatCardModule, MatDatepickerModule, MatNativeDateModule, MatFormFieldModule, MatInputModule, LayoutModule, MatToolbarModule, MatButtonModule, MatSidenavModule, MatIconModule, MatListModule ] })
app.module.ts
import { MaterialModule } from './material/material.module'; import { NavigationComponent } from './navigation/navigation.component'; @NgModule({ declarations: [ AppComponent, NavigationComponent ], imports: [ BrowserModule, AppRoutingModule, BrowserAnimationsModule, MaterialModule, ], providers: [], bootstrap: [AppComponent] })
app.component.html
<app-navigation></app-navigation>
navigation.component.html
..... <span>Zróbmy quiz</span> </mat-toolbar> <router-outlet></router-outlet> </mat-sidenav-content> </mat-sidenav-container>
Let’s do the quiz
ng g c quiz1
app-routing.module.ts
const routes: Routes = [ { path: '', component: Quiz1Component }, { path: 'quiz1', component: Quiz1Component }, ];
navigation.component.html
<mat-nav-list> <a mat-list-item [routerLink]="['/quiz1']">Quiz 1</a> <a mat-list-item href="#">Link 2</a> <a mat-list-item href="#">Link 3</a> </mat-nav-list>
https://material.angular.io/components/stepper/api
material.module.ts
import { MatStepperModule } from '@angular/material/stepper'; import { MatRadioModule } from '@angular/material/radio';
app.module.ts
import { ReactiveFormsModule } from '@angular/forms'; ... imports: [ BrowserModule, AppRoutingModule, BrowserAnimationsModule, MaterialModule, ReactiveFormsModule, ],
quiz1.component.ts
import { Component, OnInit } from '@angular/core'; import { FormBuilder, FormGroup, Validators } from '@angular/forms'; @Component({ selector: 'app-quiz1', templateUrl: './quiz1.component.html', styleUrls: ['./quiz1.component.scss'] }) export class Quiz1Component implements OnInit { isLinear = false; pytania = [ { pytanie: 'Jakie mleko daje czarna krowa w kropki bordo?', mozliwosci: ['Białe', 'Czarne', 'Bordowe'], odpowiedz: '' }, { pytanie: 'Jakiego koloru są biedroneczki w kropeczki?', mozliwosci: ['Czerwone', 'Czarne', 'Czarne w czerwone kropki', 'Czerwone w czarne kropki'], odpowiedz: '' }, ]; constructor(private _formBuilder: FormBuilder) { } ngOnInit(): void { } }
quiz1.component.html
<mat-vertical-stepper [linear]="isLinear" #stepper> <ng-container *ngFor="let pytanie of pytania; let i = index"> <mat-step [stepControl]="i"> <!-- <form [formGroup]="i"> --> <ng-template matStepLabel>{{ pytanie.pytanie }}</ng-template> <!-- <mat-form-field> --> <mat-radio-group> <mat-radio-button *ngFor="let mozliwosc of pytanie.mozliwosci" [value]="mozliwosc"> {{ mozliwosc }} </mat-radio-button> </mat-radio-group> <!-- </mat-form-field> --> <div> <button mat-button matStepperNext>Następne pytanie</button> </div> <!-- </form> --> </mat-step> </ng-container> <mat-step> <ng-template matStepLabel>Wynik</ng-template> <p>Skończone.</p> <div> <button mat-button matStepperPrevious>Cofnij</button> <button mat-button (click)="stepper.reset()">Od nowa</button> </div> </mat-step> </mat-vertical-stepper>
quiz1.component.scss
.mat-stepper-horizontal { margin-top: 8px; } .mat-form-field { margin-top: 16px; } mat-radio-group { display: flex; flex-direction: column; margin: 15px 0; } mat-radio-button { margin: 5px; }
Instalacja Flex Layout
https://github.com/angular/flex-layout
ng g c quiz2 npm i -s @angular/flex-layout
app.module.ts
import { FlexLayoutModule } from '@angular/flex-layout'; ... @NgModule({ ... imports: [ FlexLayoutModule ], ... });
app-routing.module.ts
const routes: Routes = [ { path: '', component: Quiz1Component }, { path: 'quiz1', component: Quiz1Component }, { path: 'quiz2', component: Quiz2Component }, ];
navigation.component.html
<mat-nav-list> <a mat-list-item [routerLink]="['/quiz1']">Quiz 1</a> <a mat-list-item [routerLink]="['/quiz2']">Quiz 2</a> <a mat-list-item href="#">Link 3</a> </mat-nav-list>
quiz2.component.html
<div class="zakres"> <div class="content" fxLayout="row" fxLayout.xs="column" fxFlexFill> <div fxFlex="15" class="pierwszy" fxFlex.xs="55">Pierwszy</div> <div fxFlex="30" class="drugi">Drugi</div> <div fxFlex="55" class="trzeci" fxFlex.xs="15">Trzeci</div> </div> </div>
quiz2.component.scss
/* Add application styles & imports to this file! */ .zakres { background-color: #ddd; height: 500px; } .pierwszy { background: red; color: white; text-transform: uppercase; } .drugi { background: yellow; color: blue; } .trzeci { background: blue; color: white; text-transform: uppercase; } .pierwszy, .drugi, .trzeci { padding-top: 20px; text-align: center; } .content { min-width: 300px; /*height: 400px;*/ }
https://tburleson-layouts-demos.firebaseapp.com/#/docs
Rozmiary punktów responsywności https://github.com/angular/flex-layout/wiki/Responsive-API