Tematyka zajęć 9

Witryny typu Single Page Application - Angular

  1. Strony SPA. Co to jest i kiedy się stosuje?
  2. Frameworki Angular i Node.js.
  3. Język JavaScript - dlaczego jest tak popularny?
  4. Angular CLI, TypeScript, React, Bootstrap - co to za technologie?
  5. SPA a aplikacje desktopowe.

Przebieg zajęć

  1. Wprowadzenie do tematyki zajęć, udostępnienie materiałów dydaktycznych.
  2. Krótkie omówienie technologii związanych z zajęciami (SPA, JS, Angular, Node.js).
  3. Przygotowanie środowiska do konstruowania stron typu SPA.
  4. Wygenerowanie własnej strony typu SPA i zapoznanie się z jej strukturą.
  5. Wzbogacenie SPA o podstawowe funkcjonalności (aplikacja typu “Lista Zadań”).
  6. Walidacja strony w przeglądarkach internetowych.
  7. Dodanie kilku bardziej (implementacyjnie) wymagających funkcji.

Materiały do zajęć

Zadania do realizacji na zajęciach

Zadanie 1 - Przygotowanie środowiska i generacja strony SPA (1pkt)

  1. Będziemy używać menedżera pakietów npm dla node.js. Specyfiką ekosystemu node.js jest bardzo duże rozdrobnienie pakietów, co skutkuje koniecznością ściągnięcia i zapisania bardzo wielu niewielkich plików na dysku (zarówno w katalogu domowych jak i w katalogu tworzonego projektu). Na naszych wydziałowych komputerach katalog domowy jest na dysku sieciowym, co powoduje, że tego rodzaju operacje są dość powolne. Z tego powodu zalecam wykonanie poniższego polecenia:

    $ npm config set cache /tmp/npm-cache
  2. Polecenie npx pozwala tymczasowo zainstalować pakiet i wywołać dostarczany przezeń plik wykonywalny (skrypt). Dzięki temu mamy zawsze najnowszą wersję pliku wykonywalnego. Wadą jest ewentualnie stosunkowo długie działanie (bo pakiet musi zostać pobrany i zainstalowany). Zaletą jest zawsze najnowsza wersja polecenia.

    Przejdź do katalogu w którym chcesz utworzyć naszą stronę SPA. Z powodów opisanych wyżej najlepszy byłby katalog nie znajdujący się na dysku sieciowym (np. /tmp), jednak wtedy tracimy możliwość dostania się do stworzonego projektu z domu. W wybranym przez siebie katalogu wykonaj:

    $ npx -p @angular/cli ng new XYZ

    W powyższym poleceniu @angular/cli to nazwa pakietu, a ng to program ułatwiający pracę z Angularem.

  3. Przetestuj działanie wygenerowanej aplikacji poprzez przejście do utworzonego katalogu i uruchomienie serwera:

    $ cd XYZ
    $ npx ng serve

    Zauważ, że tym razem wywoływana jest wersja Angular CLI zainstalowana przy tworzeniu naszej aplikacji (nie będzie pobierana za każdym razem).

    Jaką rolę pełni webpack?

    Uruchom przeglądarkę internetową na odpowiednim porcie (zazwyczaj jest to localhost:4200) i zapoznaj się z wygenerowaną stroną SPA.

  4. Włącz tryb inspektora w przeglądarce. Czy inspekcja jest zgodna ze źródłem strony?

Zadanie 2 - Prosta aplikacja typu Angular i Material Design (1pkt)

  1. W odpowiednim pliku zmień tytuł strony (który aktualnie odpowiada XYZ) na swoje dane osobowe: imię, nazwisko, nr indeksu.

  2. W ramach rozwoju aplikacji SPA dodamy bibliotekę zgodną z Google Material. Będąc w katalogu XYZ wykonajmy polecenie:

    $ npm install --save @angular/material @angular/cdk

    Co ono robi? Jaki będzie efekt?

  3. Aby nowo zainstalowane moduły były widoczne w naszej aplikacji dodajmy w pliku src/app/app.module.ts importy:

    import { BrowserModule } from '@angular/platform-browser';
    import { NgModule } from '@angular/core';
    import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
    import { MatToolbarModule, MatInputModule, MatButtonModule, MatListModule } from '@angular/material';
    
    import { AppComponent } from './app.component';
    
    @NgModule({
      declarations: [
        AppComponent
      ],
      imports: [
        BrowserModule,
        BrowserAnimationsModule,
        MatToolbarModule,
        MatInputModule,
        MatButtonModule,
        MatListModule
      ],
      providers: [],
      bootstrap: [AppComponent]
    })
    export class AppModule { }

    Nie zapomnij dodać tych modułów do tablicy o nazwie imports. Od teraz możemy korzystać z komponentów i dyrektyw dostępnych w dołączonych modułach.

    Zapoznaj się dokładnie z plikiem src/app/app.module.ts.

  4. W pliku src/styles.css dodajmy definicje stylów:

    /* You can add global styles to this file, and also import other style files */
    @import '@angular/material/prebuilt-themes/deeppurple-amber.css';
    html, body { padding: 0; margin: 0; }

    Jaki będzie ich efekt?

  5. Aby nasza aplikacja lepiej się prezentowała dodajmy pasek tytułowy zmieniając plik src/app/app.component.html:

    <mat-toolbar color="primary" class="mat-elevation-z4">
      <span>{{title}}</span>
    </mat-toolbar>

    Jak teraz wygląda aplikacja?

  6. Czas na implementację naszej „Listy Zadań”. W nowym pliku src/app/task.ts wpiszmy:

    export interface Task {
      description: string;
    }

    W pliku src/app/app.component.ts do klasy AppComponent dodajmy zmienną, która przechowywać będzie nasze zadania (task) oraz metody odpowiedzialne za dodawanie i usuwanie zadań:

    import { Component } from '@angular/core';
    import { Task } from './task';
    
    @Component({
      selector: 'app-root',
      templateUrl: './app.component.html',
      styleUrls: ['./app.component.css']
    })
    export class AppComponent {
      title = 'app';
    
      tasks: Task[] = [];
    
      handleTaskAdd(description: string) {
        if (description && description.length > 0) {
          this.tasks.push({ description });
        }
      }
    
      handleTaskRemove(taskIdx: number) {
        this.tasks.splice(taskIdx, 1);
      }
    }

    Nie zapomnij odpowiednich importów.

  7. Żeby zadania móc umieszczać na liście to musimy mieć mechanizm ich wpisywania. Dodajmy go poprzez modyfikację pliku app.component.html:

    <mat-toolbar color="primary" class="mat-elevation-z4">
      <span>{{title}}</span>
    </mat-toolbar>
    <div style="padding: 10px;">
      <mat-form-field>
        <input #newTask matInput placeholder="Nowe zadanie">
      </mat-form-field>
      <button mat-button color="accent"
        (click)="handleTaskAdd(newTask.value);newTask.value=''"
        [disabled]="!newTask.value">
        DODAJ
      </button>
    </div>
  8. Mamy już podstawową funkcjonalność, ale brakuje nam modułu, który będzie to wszystko obsługiwał. W związku z tym wygenerujmy go (w katalogu XYZ):

    $ npx ng generate component task-list

    Sprawdź zawartość folderu src/app/task-list oraz pliku src/app/app.module.ts

    W pliku task-list.component.ts dodaj instrukcje oraz odpowiednie importy:

    import { Component, OnInit } from '@angular/core';
    import { Input, Output, EventEmitter } from '@angular/core';
    import { Task } from '../task';
    
    @Component({
      selector: 'app-task-list',
      templateUrl: './task-list.component.html',
      styleUrls: ['./task-list.component.css']
    })
    export class TaskListComponent implements OnInit {
    
      constructor() { }
    
      ngOnInit() {
      }
    
      @Input()
      tasks: Task[];
    
      @Output()
      remove = new EventEmitter<number>();
    
      removeTask(taskIdx: number) {
        this.remove.emit(taskIdx);
      }
    }
  9. Zmieńmy wygląd naszej strony poprzez zastąpienie zawartości pliku task-list.component.html następującą treścią:

    <mat-nav-list>
      <mat-list-item *ngFor="let task of tasks; let taskIdx = index">
        <span mat-line>{{task.description}}</span>
        <button mat-button color="warn" (click)="removeTask(taskIdx)">
          USUŃ
        </button>
      </mat-list-item>
    </mat-nav-list>
  10. Dodajmy nowy komponent do naszej aplikacji (plik src/app/app.component.html):

    <mat-toolbar color="primary" class="mat-elevation-z4">
      <span>{{title}}</span>
    </mat-toolbar>
    <div style="padding: 10px;">
      <mat-form-field>
        <input #newTask matInput placeholder="Nowe zadanie">
      </mat-form-field>
      <button mat-button color="accent"
        (click)="handleTaskAdd(newTask.value);newTask.value=''"
        [disabled]="!newTask.value">
        DODAJ
      </button>
    </div>
    <app-task-list
      [tasks]="tasks"
      (remove)="handleTaskRemove($event)">
    </app-task-list>

    Czy nasza strona działa poprawnie?

  11. Czy nasza strona tak samo się zachowuje w różnych przeglądarkach? Koniecznie przetestuj min. 3 przeglądarki.

  12. Gotową aplikację możesz obejrzeć tutaj.

Jedną z najbardziej popularnych bibliotek służącą do tworzenia interfejsów użytkownika w JavaScripcie jest React (stworzony przez Facebooka). W przeciwieństwie do Angulara React nie zawiera wielu funkcjonalności potrzebnych przy pisaniu pełnowymiarowych aplikacji (komunikacja sieciowa, testy itp.). Przykładową aplikację stworzoną z Reactem wyglądającą podobnie do tej stworzonej w czasie tych zajęć możesz obejrzeć tutaj.

Zadanie 3 - Złożona aplikacja typu Angular (5pkt)

  1. Dodaj funkcjonalność, która umożliwi dodanie zadania po naciśnięciu przycisku ENTER.

  2. Dodaj funkcjonalność, która sprawi że użytkownik po naciśnięciu przycisku USUŃ będzie pytany, czy na pewno chce usunąć dane zadanie.

Zadanie zaliczeniowe dodatkowe

Zadanie 4 - Jeszcze bardziej złożona aplikacja typu Angular (5pkt)

Do listy zadań dodaj drugi przycisk z etykietą ZROBIONE, którego funkcją będzie przekreślanie danego zadania wraz z opisem. Ponowne naciśnięcie przycisku usuwa wcześniejsze przekreślenie.