Skip to content

mirceahasegan/angular-travel-workshop-vscode

Repository files navigation

angular-travel-workshop

1. HTML is still HTML

  1. Gaseste fisierul app.component.html
  2. Editeaza-l astfel incat sa afiseze M-ai editat, deci se dezlantuie magia in loc de my app

Bonus

Gaseste fisierul HTML in care AppComponent este reprezentat printr-un tag HTML.

Hint: AppComponent defineste tag-ul HTML in decoratorul @Component


2. Interpolation

Afisarea unei variable in HTML

Angular ne ofera o sintaxa speciala pentru a include in template (in HTML) date definite in logica componentei (in fisierul .ts)

// Component Typescript code
myName = 'Angular Wiz Escu'

// Component template HTML code
<div> Numele meu este {{ myName }} </div>

// Result
Numele meu este Angular Wiz Escu

Task

  1. Deschide template-ul componentei AppComponent (app.component.html)
  2. Inlocuieste textul din task-ul anterior cu proprietatea name
  3. Deschide typescript-ul componentei AppComponent (app.component.ts)
  4. Schimba valoarea proprietatii name: observa ca se actualizeaza si pagina

Hint: Nu uita sa folosesti interpolarea ({{name}}). Altfel va fi afisat string-ul name in loc de valoarea lui


3. More Interpolation

Afisarea proprietatilor unui obiect

In componenta AppComponent am adaugat proprietatea destination ca obiect. Observati structura.

Task

  1. Deschide template-ul componentei AppComponent
  2. Inlocuieste campurile care definesc destinatia cu proprietatile obiectului destination folosind interpolare.
  3. Modifica informatii din obiectul destination si observa cum se actualizeaza in pagina.

Hint: {{destination.name}} acceseaza proprietatea name din obiectul destination


4. Directive Structurale

Din moment ce orice site de calatorii are mai mult de o destinatie, am adaugat un array de destinatii in AppComponent. Observati structura.

Proprietatea destination este primul element din array-ul destinations.

Dorim sa afisam toate destinatiile din array.

O varianta ar fi copy/paste al template-ului care defineste destinatia si folosirea unei variable pentru fiecare destinatie.

Angular ofera suport pentru modificarea structurii template-ului (in cazul acesta duplicarea unor elemente din template) cu ajutorul directivelor structurale.

4.1. *ngFor

*ngFor va repeta blocul HTML pe care este aplicat pentru fiecare element dintr-o colectie.

// Component Typescript code
elements = ['one', 'two', 'three']

// Component template HTML code
<div *ngFor="let element of elements"> Element: {{ element }} </div>

// Result
Element: one
Element: two
Element: three

Task

  1. Deschide template-ul componentei AppComponent
  2. Adauga directiva *ngFor astfel incat sa fie afisate toate destinatiile din array-ul destinations

Hint: Nu uita sa folosesti (*) in fata lui ngFor. Aceasta sintaxa indica faptul ca este o directiva structurala: <div class="destination" *ngFor="let destination of destinations">

4.2. *ngIf

*ngIf controleaza afisarea unui element HTML, in functie de o conditie.

// Component Typescript code
vreau = true;

// Component template HTML code
<p> Nu <span *ngIf="vreau">, </span> vreau sa invat Angular </p>

// Result
Nu, vreau sa invat Angular

Task

  1. Deschide template-ul componentei AppComponent si sterge comentariile pentru div-ul cu clasa display-as-list.
    • Hint: In HTML orice se afla intre <!-- si --> este comentat.
  2. Adauga directiva *ngIf astfel incat destinatiile sa fie afisate doar sub forma de lista. Variabila isList reprezinta conditia de afisare.

5. Pipes

In template ajunge, de multe ori, continut dinamic. Acesta, sau o parte din acesta, are nevoie de formatare.

De exemplu, vreau ca un text adaugat prin interpolare in template, sa inceapa intotdeauna cu prima litera mare, sau vreau sa fie tot textul uppercase, sau textul este un numar si vreau sa aiba maxim doua zecimale etc.

Pipe-urile sunt o metoda buna de a formata string-uri, sume valutare, date de calendar etc. Angular are pipe-uri predefinite (ex. titlecase) dar se pot crea si pipe-uri custom.

Sintaxa: {{ elementToTransform | pipeName }}

Exemplu:

// Component Typescript code
name = 'darth vader'

// Component template HTML code
<p> The hero's name is {{ name | titlecase }} </p>

// Result
The hero's name is Darth Vader

Task

  1. Deschide template-ul componentei AppComponent
  2. Adauga pipe-ul currency: USD pentru destination.price si sterge currency-ul adaugat static ($)

Hint: Nu uita sa folosesti | dupa destination.price. Aceasta sintaxa indica faptul ca se foloseste un pipe.


6. Event Bindings

Un event binding este o metoda prin care putem executa cod Javascript atunci cand se declanseaza evenimentul.

Sintaxa: (event)="statement"

Exemplu:

// Component Typescript code
deleteProduct() {
  console.log('Product is being removed.');
}

// Component template HTML code
<button (click)="deleteProduct()">Delete product</button>

Ele reprezinta modul prin care actualizezi starea aplicatiei in urma unei actiuni.

Intre ghilimele se pune un template statement (cod javascript sau apel de functie).

Task

  1. Deschide template-ul componentei AppComponent
  2. Gaseste butonul cu textul "List/Cards"
  3. Conecteaza evenimentul click la metoda toggleDisplay pentru a schimba afisarea destinatiilor
    • Hint foloseste proprietatea isList in metoda toggleDisplay
  4. Folosind interpolarea, afiseaza butonul cu textul "List" atunci cand destinatiile sunt afisate sub forma de cards si cu textul "Card" atunci cand destinatiile sunt afisate sub forma de lista.
    • Hint Foloseste conditional (ternary) operator in interpolare
        // HTML
        <p>{{ isTrue ? 'Adevarat' : 'Fals' }} </p>
        
        // Rezultat cand isTrue === true
        <p> Adevarat </p>

!Info: Ce este un card?

Card-urile sunt blocuri mici, similare ca design, dar cu continut diferit. Un card poate avea orice tip de continut - imagini, text, link-uri etc.


7. Components

Componentele reprezinta modul in care Angular organizeaza si incapsuleaza (izoleaza) continutul.

  • HTML - structura si continut
  • CSS - stil
  • Typescript - logica

Task

In folderul src/app au fost create urmatoarele fisiere:

  • favorite-destination.component.css
  • favorite-destination.component.html
  • favorite-destination.component.ts
  1. Decomenteaza codul care ii spune lui Angular ca FavoriteDestinationComponent este o componenta.
    • Q: Care sunt informatiile specificate in decoratorul @Component si de ce sunt necesare?
    • Q: Sunt toate necesare?
  2. Afiseaza componenta FavoriteDestinationComponent ca si copil al lui AppComponent in locul indicat de comentariu.
    • Foloseste selectorul componentei FavoriteDestinationComponent ca un tag HTML (cum este folosit selectorul lui AppComponent in index.html)
    • Daca ai obtinut Eroarea 'app-favorite-destination' is not a known element inseamna ca ai reusit
    • Q: De ce avem aceasta eroare?
  3. Asculta indemnul erorii.
    • Hint: Exista vreo componenta pe care o putem folosi ca exemplu pentru a rezolva eroarea?
  4. Adauga o proprietate isFavorite in clasa FavoriteDestinationComponent si afiseaza o stea plina doar cand isFavorite este true.
    • Hint vezi conditional (ternary) operator de la task-ul din capitolul anterior
    • Q: de ce am folosit ghilimele pentru 'star' si 'star_outline'

7.1. Component @Input

Elementele HTML sunt configurate prin atribute HTML care se mapeaza pe proprietati din Javascript.

  // HTML
  <a title="Enteresant" href="#"> Un link interesant </a>

  // Javascript
  console.log(elementA.title)

  // Console output
  Enteresant

Trimiterea de date catre componente se face in acelasi mod, prin proprietati. Proprietatile marcate cu decoratorul @Input() vor putea fi folosite pentru a configura componente.

  // Typescript
  public class TheAnswerComponent {
    @Input() question;
  }

  // HTML
  <app-the-answer question="meaning of life"></app-the-answer>

Task

Componenta FavoriteDestinationComponent are proprietatea isFavorite.

  1. Marcheaza proprietatea ca Input
    • Hint: Decoratorul Input face parte din @angular/core
  2. Din app.component.html, configureaza proprietatea cu true, apoi cu false
    • Q: Se modifica afisarea din componenta copil? Dar daca folosim sintaxa de binding [isFavorite]?
  3. Folosind data binding, legati proprietatea isFavorite de destination.isFavorite

7.2. Component @Output

Elementele HTML emit evenimente. Mai devreme ne-am abonat la evenimentul (click) al butonului 'Display as' cu functia toggleDisplay().

Componentele Angular pot face acelasi lucru: sa emita evenimente si ne abonam la aceste evenimente folosind aceeasi sintaxa.

Task

Vom modifica componenta FavoriteDestinationComponent astfel incat sa emita evenimentul favClick cand este clickaita stelutza.

  1. Adauga proprietatea favClick de tip @Output in componenta FavoriteDestinationComponent
    • Hint: @Output() favClick = new EventEmitter();
    • Q: all good? Poate ar trebui sa importam directiva Output de undeva?
    • Q: now? Developer tools ce zice? (Hit F12)
  2. Emite evenimentul favClick atunci cand se face click pe steluta
    • Hint: (click)="favClick.emit()"
  3. In AppComponent aboneaza-te la evenimentul favClick al componentei FavoriteDestinationComponent. Schimba valoarea proprietatii destination.isFavorite de fiecare data cand se emite favClick.
    • Hint: destination.isFavorite = !destination.isFavorite

7.3. More Components

Task 1

Creaza o componenta care sa incapsuleze afisarea destinatiei ca si card.

  1. ng generate component destination-details
  2. Muta HTML-ul care afiseaza destinatia ca si card in template-ul noii componente
    • Hint: Urmareste comentariile din app.component.html
  3. Adauga selectorul componentei DestinationDetailsComponent in template-ul lui AppComponent, in locul unde era inainte cardul
    • Hint: <app-destination-details *ngIf="!isList"></app-destination-details>
    • Q: Ce se intampla daca nu folosesc directiva *ngIf?
    • Q: Observa si explica eroarea din developer tools (F12) TypeError: Cannot read property 'name' of undefined
  4. Adauga o proprietate de tip @Input in componenta DestinationDetailsComponent
    • Hint: @Input() destination;
  5. Din template-ul lui AppComponent transmite destination catre app-destination-details folosind property binding:
    • Hint: <app-destination-details [destination]="destination" *ngIf="!isList"></app-destination-details>
    • Q: De ce nu s-a aplicat stilizarea configurata in app.component.css in componenta copil DestinationDetailsComponent?
  6. Muta stilizarea din app.component.css in destination-details.component.css
    • Hint: Urmareste comentariile din app.component.css

Task 2

Folosind pasii de mai sus, extrage codul pentru afisarea destinatiei ca lista intr-o componenta denumita destination-summary


8. Servicii

Spre deosebire de componente, serviciile sunt create o singura data si sunt disponibile pe toata durata de viata a aplicatiei.

Un exemplu ar fi starea aplicatiei. Destinatiile disponibile ar putea fi luate de pe server si stocate intr-un serviciu. Orice componenta care are nevoie de destinatii poate sa le acceseze prin serviciu, fara sa ceara din nou de la server destinatiile.

In Angular, un serviciu este disponibila pentru orice parte din aplicatie folosind sistemul Dependency Injection al Angular-ului.

Pentru aplicatia de calatorii, destinations.service.ts este locul unde "stocam" datele pentru destinatii.

  • Observatie: toate fisierele de tip serviciu au in denumirea 'service'; ex: nume-serviciu.service.ts
  import { Injectable } from '@angular/core';

  // dependency injection decorator
  @Injectable({
    providedIn: 'root' // singleton
  })
  export class DestinationsService {

    constructor() { }

  }

Task

  1. Muta destinations din AppComponent in DestinationsService
  2. Injecteaza serviciul in AppComponent:
    • Hint: Decomenteaza din constructorul lui AppComponent destinationsService: DestinationsService.
  3. Foloseste datele din serviciu pentru a popula aplicatia cu destinatiile de calatorie

9. Rutare

Single Page Application (SPA)

Ce este?

Daca vrem sa afisam continut in functie de URL, putem sa folosim functionalitatile de rutare Angular (Angular router).

Angular router te ajuta sa afisezi componentele in functie de locul in care acesta se afla in aplicatie (URL).

Router-ul permite navigarea dintr-un view (pagina/componenta) catre alt view pe baza actiunilor utilizatorului:

  • scrierea unui URL in bara de adrese
  • click pe link-uri din pagina
  • click pe butoanele browser-ului Inainte si Inapoi

Sintaxa pentru a defini rutele din aplicatie: RouterModule.forRoot([...]). Modulul de rutare (router) trebuie importat in modulul care il foloseste (in cazul nostru app.module.ts):

  import { RouterModule } from '@angular/router';

  @NgModule({
    imports: [ 
      ...
      RouterModule.forRoot([
          { path: 'dashboard', component: DashboardComponent },
          // for 'klm-training' in URL the KlmTrainingComponent will be loaded; 
          // eg: https://address/klm-training
          { path: 'klm-training', component: KlmTrainingComponent },
          // for empty pathname you will be redirected to '/dashboard' wich will load DashboardComponent
          { path: '', redirectTo: '/dashboard', pathMatch: 'full' }
        ])
      ...
    ]

Pe langa modulul de rutare avem nevoie ca elementele din HTML sa solicite router-ului incarcarea unui URL: <a routerLink="dashboard"> Dashboard </a>.

Task

Aplicatia are acum urmatoarea structura:

  • AppComponent este componenta parinte si afiseaza
    • Bara de navigare
    • DestinationsComponent
  • DestinationsComponent afiseaza destinatiile ca si card-uri sau lista infunctie de butonul Display as
  • ContactComponent nu este afisata momentan

La finalul task-ului AppComponent:

  • Afiseaza intotdeauna bara de navigare
  • Afiseaza DestinationsComponent sau ContactComponent in functie de URL folosind Angular routing

Steps:

  1. Decomenteaza, modulul de rutare in app.module.ts
  2. Adauga inca o ruta catre pagina contact
  3. Adauga routerLink catre cele doua componente anchor (<a>) in bara de navigare a aplicatiei
    • Hint: <a routerLink="destinations">
    • Q: Apasa butoanele Destinations si Contact din bara de navigare. Ce se intampla? Dar in bara de adrese se modifica ceva?
    • Q: De ce nu se modifica continutul paginii?
  4. Afiseaza in template-ul lui AppComponent view-urile rutate de router
    • Hint: Tag-ul <router-outlet> (directiva importata odata cu RouterModule) spune router-ului unde sa afiseze view-urile rutate.
    • Hint: Template-ul lui AppComponent nu mai are nevoie sa afiseze DestinationsComponent folosind tag-ul <app-destinations> deoarece aplicatia va afisa aceasta componenta doar atunci cand user-ul va naviga catre ea
    • Q: Ce se intampla daca folosim butoanele Back si Forward ale browser-ului?
  5. Adauga routerLinkActive in tag-urile de navigare <a>:
    • <a routerLink="destinations" routerLinkActive="active">
    • acelasi lucru si pentru contact
    • Q: ce s-a schimbat in afisare? Cum?
    • Q: Deschide devtools (F12) si observa elementele <a>. Click pe link-uri. Ce se intampla?

10. Two way binding

Angular ne pune la dispozitie mai multe metode de a comunica cu componentele:

  1. @Input: datele sunt trimise catre componenta
  2. @Output: datele sunt trimise dinspre componenta (ca evenimente)
  3. Two way binding: datele sunt tinute in-sync (ngModel)

10.1. [(ngModel)]

ngModel ne ajuta sa sincronizam valoarea unui input din HTML cu o proprietate din logica componentei.

// Typescript
name = 'Zorro';
// HTML
<input [(ngModel)]="name"> // Banana in a box syntax

Task 1

Componenta Contact are doua input-uri folosite la adaugarea unui nou testimonial.

  1. Gaseste input-urile
  2. Adauga banane in cutie ca sa poti pune un nou testimonial
  3. Observa sincronizarea live

Task 2 (pentru FB cu stelutza)

  1. Navigheaza in pagina Destinatii, apoi revino in pagina Contact
  2. Ce s-a schimbat? De ce?
  3. Cum oprim schimbarea? :)

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published