# Dodajanje Angular komponent ```ps1 npm install -g @angular/cli ``` > Nalozimo aplikacijo z npm globalno ```ps1 ng new App --skip-git=true --skip-tests=true --defaults=true --directory=app_public ``` > Inicializacija nove aplikacije. ```ps1 ng serve --open ``` > Aplikacijo zazenemo v razvojnem okolju Angular aplikacije in odpremo v oknu browserja ```ps1 ng build --output-path build ``` > Zgradi aplikacijo in ustvari .js datoteke v direktorjiju `./build`. <br /> <br /> # Glavni deli Angular aplikacije ## src/app.module.ts ```ts import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { AppComponent } from './app.component'; @NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule { } ``` > app.module.ts datoteka Nove komponente dodamo v `declarations` ? Enako naredimo in dodamo v `bootstrap`, da komponento nastavimo kot privzeto. ## src/index.html ```html <!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>EduGeoCache</title> <base href="/"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="icon" type="image/x-icon" href="favicon.ico"> </head> <body> <app-root></app-root> </body> </html> ``` > Definira nek "layout" nase aplikacije V `<app-root>` blok se nalozi nas AppComponent `<base href="/">` je pomembno ? <br /> <br /> # Komponente Vsaka komponenta je sestavljena iz treh delov: - ~.component.ts > Nastavitve in skripta te komponente - logika delovanja - ~.component.html > HTML postavitev te komponente - ~.component.css > Stil komponente ## Generiranje nove komponente ``` ng generate component ime-komponente ``` > Nam avtomatsko kreira vse datoteke za komponento in jo vkljuci v `app.module.ts` ## ~.component.ts ```ts import { Component } from '@angular/core'; @Component({ selector: 'app-ime-komponente', templateUrl: './ime-komponente.component.html', styleUrls: ['./ime-komponente.component.css'] }) export class ImeKomponenteComponent { title = 'EduGeoCache'; } ``` > `selector` => blok ki se bo v .html datoteki prevedel v to komponento (npr. tej komponenti pripada `<app-ime-komponente></app-ime-komponente>`) `templateUrl` => datoteka z .html kodo komponente `styleUrls` => datoteka z .css stilom komponente Spremenljivke v `export class ImeKomponenteComponent {...}` se uvozijo v .html datoteko komponento enako kot v handlebars (npr. v tem primeru bo v `{{ title }}` se prevedlo `EduGeoCache`) ### Definicija novih objektov V datoteki definiramo `export class Razred {...}` in s tem definiramo shemo objektov, ki jih bomo vecinoma uporabljali kot sheme pri mongoose. **Primer:** ```ts export class Lokacija { "_id": string; "naziv": string; "naslov": string; "ocena": number; "lastnosti": string[]; "razdalja": number; } ``` ## ~.component.html **Primer:** ```html <div class="row banner"> <div class="col-12"> <h1> {{ glavaStrani.naslov }} <small class="text-secondary">{{ glavaStrani.podnaslov }}</small> </h1> </div> </div> <div class="row"> <div class="col-12 col-md-8"> <div class="row"> <div class="col-12 col-xxl-6" *ngFor="let lokacija of lokacije"> <div class="card mt-4"> <div class="card-header bg-light"> <div class="d-flex justify-content-between align-items-center"> <div><h4><a href="/lokacija/{{lokacija._id}}" >{{ lokacija.naziv }}</a></h4></div> <div> <span class="ocena text-success"> {{ lokacija.ocena }} </span> </div> </div> </div> <div class="card-body"> <div> <span class="naslov">{{ lokacija.naslov }}</span> <span class="oddaljenost badge rounded-pill bg-secondary float-end"> {{ lokacija.razdalja }} </span> </div> </div> <div class="card-footer"> <div class="lastnosti"> <span class="badge bg-secondary" *ngFor="let lastnost of lokacija.lastnosti"> {{ lastnost }} </span> </div> </div> </div> </div> </div> </div> <div class="col-12 col-md-4 mt-4"> <small class="text-muted">{{ stranskaOrodnaVrstica }}</small> </div> </div> ``` ### Izrazi V .html datotekah lahko v brkih uporabljamo tudi razne izraze. **Primer:** ```html <small class="ocena text-success"> <i class="fa{{ lokacija.ocena < 1 ? 'r' : 's'}} fa-star"></i> <i class="fa{{ lokacija.ocena < 2 ? 'r' : 's'}} fa-star"></i> <i class="fa{{ lokacija.ocena < 3 ? 'r' : 's'}} fa-star"></i> <i class="fa{{ lokacija.ocena < 4 ? 'r' : 's'}} fa-star"></i> <i class="fa{{ lokacija.ocena < 5 ? 'r' : 's'}} fa-star"></i> ``` ### ng helpers V html gradnike lahko dodamo ng pomagace in si z njimi olajsamo delo z odvisnimi spremenljivkami, ki jih uvazamo iz .ts datoteke. Lahko bi rekli da nadomescajo handlebars helperje. #### ngFor **Primer:** ```html <div class="col-12 col-xxl-6" *ngFor="let lokacija of lokacije"> <h1>{{ lokacija.naziv }}</h1> </div> ``` > Za vsako lokacijo v array spremenljivki `lokacije`, nam bo samodejno ustvarilo vsaka svoji pripaden `div` blok v katerem bo njen naziv #### ngIf **Primer:** ```html <div *ngIf="naslov"> <h1>Vidis me, le ko imam naslov, ki pravi {{ naslov }}</h1> </div> ``` > `div` blok se bo pokazal samo ko bo spremenljivka naslov bila `true` oz. bo imela podano vrednost. #### ngSwitch **Primer:** ```html <div [ngSwitch]="var"> <h1 *ngSwitchCase="1">V spremenljivki 'var' je 1</h1> <h1 *ngSwitchCase="2">V spremenljivki 'var' je 2</h1> <h1 *ngSwitchDefault>V spremenljivki 'var' ni niti 1 niti 2 oz. je prazna</h1> </div> ``` > Switch glede na podano spremenljivko v `[ngSwitch]`. V parent bloku definiramo spremenljivko, ki nato v child blokih isce pripadajoco vrednost definirano v `*ngSwitchCase` in jo izrise. Ce jo ne najde, izpise child blok z `*ngSwitchDefault` oz. ce ga nimamo pusti prazno. ### Razni dodatki blokom v Angular aplikacijah #### \[hidden\] ```html ... <div class="alert alert-dark mt-4 p-2" [hidden]="sporocilo"> <i class="fas fa-exclamation-triangle pe-2"></i>{{ sporocilo }} </div> ... ``` > Ce je spremenljivka (v tem primeru `sporocilo`) `true` oz. ima vrednost bo vsebina tega bloka skrita. #### \[innerHTML\] ```html <div class="row"> <div [innerHTML]="vsebinaStrani.vsebina"></div> </div> ``` > V `<div>` bloku se bo generirala HTML vsebina ki je podana v spremenljivki `vsebinaStrani.vsebina`. > Uporabno, ko imamo neko besedilo, ki uporablja `\n` => slednje zamenjamo (s pomocjo cevi) v `<br>` in z `innerHTML` tako vsebino tudi prikazemo. #### (click) ```html <button (click)="spremenljivka = false">Gumb 1</button> <button (click)="nekaMetoda()">Gumb 2</button> ``` > Na event "click" damo neko funkcijo da se izvede, ali nastavljanje spremenljivk ali prozenje metod v export class pizdariji. > V oklepaju provzaprou lahko damo katerikoli event in se bo na njega to sprozilo (npr. change, mouseDown,...). <br /> <br /> # Cevi Z njimi formatiramo podatke, ki jih posredujemo s spremenljivkami iz .ts datoteke v .html datoteko. ## Kreiranje cevi ```ps1 ng generate pipe razdalja ``` > Kreira novo cev `razdalja.pipe.ts` in referenco doda v `app.module.ts` v `declarations` ## ~.pipe.ts ```ts import { Pipe, PipeTransform } from '@angular/core'; @Pipe({ name: 'razdalja' }) export class RazdaljaPipe implements PipeTransform { transform(razdalja: number): string { let enota = "km"; if (razdalja < 1) { razdalja = Math.round(razdalja * 1000); enota = "m"; } return ( razdalja.toLocaleString("sl-SI", { maximumFractionDigits: 1 }) + " " + enota ); return null; } } ``` > Metodi `transform` definiramo vhodne spremenljivke (in njihove tipe, ne pozabimo tudi na izhodni tip!) in v metodi oblikujemo podateki in ga returnamo. `name` => definira ime cevi, ki ga bomo uporabili v .html datotekah ## Uporaba cevi **Primer:** ```html <span class="oddaljenost badge rounded-pill bg-secondary float-end"> {{ lokacija.razdalja | razdalja }} </span> ``` > Cev uporabimo v .html datoteki komponente in jo dodamo spremenljivkam v brkih. Ime spremlja znak `|`. <br /> <br /> # Cev za izogib varnostnim tezavam Angularja Angular nekaj obravnava kot varnostno težavo, kjer bomo morali dodati izjemo. Uporabili bomo cev transformacije `dovoli-url`, kjer za podan URL naslov ne bomo upoštevali varnostnih zahtev! ```ts import { Pipe, PipeTransform } from '@angular/core'; import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser'; @Pipe({ name: 'dovoliUrl', }) export class DovoliUrlPipe implements PipeTransform { constructor(private sanitizer: DomSanitizer) {} transform(url: string): unknownSafeResourceUrl { return this.sanitizer.bypassSecurityTrustResourceUrl(url); } } ``` > Datoteka `dovoli-url.pipe.ts`. <br /> <br /> # Cev za sortiranje arraya ```ts import { Pipe, PipeTransform } from '@angular/core'; @Pipe({ name: 'najnovejsiNajprej', }) export class NajnovejsiNajprejPipe implements PipeTransform { transform(komentarji: any[]): any[] { if (komentarji && komentarji.length > 0) { return komentarji.sort((a, b) => { return a.datum > b.datum ? -1 : a.datum < b.datum ? 1 : 0; }); } return komentarji; } } ``` Slednje uporabimo v html na primeru: ```html <div *ngFor="let komentar of lokacija.komentarji | najnovejsiNajprej"> ... </div> ``` <br /> <br /> # Cev za formatiranje datuma ```html <h1> {{ spremenljivka.datum | date: "d. MMMM, yyyy" }} </h1> ``` Ker smo formatirali v obliko kjer se mesec izpise z imenom verjetno zelimo se da se bo izpisal z slovenskim imenom. To nardimo tko: 1. V `app.module.ts` uvozimo `registerLocaleData` in `localeSl` in registriramo, da bomo uporabljali slovenske lokalne besede. ```ts ... import { registerLocaleData } from '@angular/common'; import localeSl from '@angular/common/locales/sl'; registerLocaleData(localeSl); ... ``` 2. Klicu v cevi dodamo, da bomo uporabljali casovni pas CEST ter lokalne besede sl. ```html <h1> {{ spremenljivka.datum | date: "d. MMMM, yyyy":"CEST":"sl" }} </h1> ``` <br /> <br /> # Storitve Vse funkcionalnosti Angular aplikacije (kot so npr. pridobivanje podatkov z API) hranimo v storitvah. To nam omogoca, da iste funkcije uporabljamo v vec komponentah. ## Kreiranje storitve ``` ng generate service edugeocache-podatki ``` > Generiramo novo storitev `edugeocache-podatki.service.ts` ## ~.service.ts ```ts import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class EdugeocachePodatkiService { constructor() { } } ``` > `constructor` => v njem definiramo razne module ki jih bomo uporabili v storitvi (npr. http) ## Uporaba storitev v komponentah ```ts import { Component, OnInit } from '@angular/core'; import { HttpService } from '../http.service'; @Component({ selector: 'app-seznam-lokacij', templateUrl: './seznam-lokacij.component.html', styleUrls: ['./seznam-lokacij.component.css'] }) export class SeznamLokacijComponent implements OnInit { constructor(private httpStoritev: HttpService) { } public lokacije: Lokacija[] = []; private pridobiLokacije(): void { this.httpStoritev .pridobiLokacije() .subscribe( (najdeneLokacije) => (this.lokacije = najdeneLokacije) ); } public title = 'EduGeoCache'; ngOnInit() { this.pridobiLokacije(); } } ``` > Z `import` uvozimo novo storitev. V `constructor` naredimo novo instanco storitve. S klicem `this.instancaStoritev.metodaStoritve` klicemo storitve in jih aktiviramo. <br /> <br /> # Storitev za HTTP zahteve ## http.service.ts ```ts import { Injectable } from '@angular/core'; import { HttpClient, HttpErrorResponse } from '@angular/common/http'; import { Observable, throwError } from 'rxjs'; import { catchError, retry } from 'rxjs/operators'; import { Lokacija } from './seznam-lokacij/seznam-lokacij.component'; @Injectable({ providedIn: 'root' }) export class HttpService { constructor(private http: HttpClient) { } private apiUrl = 'http://localhost:3000/api'; public pridobiLokacije(lng: number, lat: number): Observable<Lokacija[]> { const maxRazdalja: number = 100; const url: string = `${this.apiUrl}/lokacije?lng=${lng}&lat=${lat}&maxRazdalja=${maxRazdalja}`; return this.http .get<Lokacija[]>(url) .pipe(retry(1), catchError(this.obdelajNapako)); } private obdelajNapako(napaka: HttpErrorResponse) { return throwError(() => `Prišlo je do napake '${napaka.status}' z opisom '${napaka.error.sporočilo || napaka.statusText}'` ); } } ``` > Uvozimo module `HttpClient`, `HttpErrorResponse`, `Observable`, `throwError`, `catchError` in `retry`. Uvozimo vse "sheme" za nase objekte, ki jih bomo pridobili z API (v tem primeru `Lokacija`). V konstruktorju kreiramo novo instanco HttpClient `http`. Definiramo metode, ki bodo pridobivale datoteke s sestavljenega URL-ja (npr. `pridobiLokacije`). Definiramo metodo za metanje napak. ## app.module.ts ```ts import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { HttpClientModule } from '@angular/common/http'; import { SeznamLokacijComponent } from './seznam-lokacij/seznam-lokacij.component'; @NgModule({ declarations: [ SeznamLokacijComponent, ], imports: [ BrowserModule, HttpClientModule ], providers: [], bootstrap: [SeznamLokacijComponent] }) export class AppModule { } ``` > Uvozimo `HttpClientModule`, da bo na voljo celotni aplikaciji. Modul tudi dodamo v `imports`. ## ~.component.ts ```ts ... constructor(private httpStoritev: HttpService) { } ... return this.http .get<Lokacija[]>(url) .pipe(retry(1), catchError(this.obdelajNapako)); ... ``` ## CORS napaka Da se izognemo CORS napaki moramo v `app.js` nasega node API-ja dodati naslednji blok kode: ```js app.use("/api", (req, res, next) => { res.header("Access-Control-Allow-Origin", "*"); res.header("Access-Control-Allow-Methods", "GET, PUT, POST, DELETE"); res.header( "Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept" ); next(); }); ``` <br /> <br /> # Storitev za Geolokacijo HTML5 nam omogoča geolociranje s pomočjo metode `navigator.geolocation.getCurrentPosition`. ## geolokacija.service.ts ```ts import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class GeolokacijaService { constructor() { } public pridobiLokacijo( pkUspesno: PositionCallback, pkNapaka: PositionErrorCallback, pkNiLokacije: any ): void { if (navigator.geolocation) { navigator.geolocation.getCurrentPosition(pkUspesno, pkNapaka); } else { pkNiLokacije(); } } } ``` > Metoda pricakuje tri callback metode (uspesno pridobljena, napaka, uporabnik ne dovoli dat lokacije). > V `pkUspesno` vrne objekt z koordinatami v obliki `objekt = { coords: { latitude: "", longitude: "" } }`. <br /> <br /> # Usmerjanje in ogrodje ## Prehod usmerjanja z Experess na Angular ![Prehod usmerjanja](https://i.imgur.com/tQrO7Nf.png) ## Ogrodje (oz. layout za vse strani) 1. Generiramo novo komponento za ogrodje ```ps1 ng generate component ogrodje ``` 2. V `src/index.html` vstavimo v `<body>` blok `<app-ogrodje></app-ogrodje>` ```html <!DOCTYPE html> <html lang="sl"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <link rel="stylesheet" href="/assets/stylesheets/bootstrap.sandstone.min.css" /> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css" /> <title>EduGeoCache</title> <base href="/" /> <link rel="icon" type="image/x-icon" href="favicon.ico" /> <link rel="stylesheet" href="/assets/stylesheets/style.css" /> </head> <body> <app-ogrodje></app-ogrodje> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.1/dist/js/bootstrap.bundle.min.js"></script> <script src="/assets/javascripts/preverjanje.js"></script> </body> </html> ``` 3. V `ogrodje.component.html` izdelamo layout, ki si ga bodo delili vsi pogledi (verjetno navbar in footer) in vmes dodamo blok `<router-outlet></router-outlet>`. 4. Ustvarimo **usmerjevalnik** ## Angular usmerjanje Usmerjanje implementiramo z uporabno **RouterModule**. Pri tem ne pozabimo, da tagge `href=""` ipd. zamenjamo z taggi `routerLink=""`. ### app.model.ts ```ts import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { RouterModule } from '@angular/router'; import { SeznamLokacijComponent } from './seznam-lokacij/seznam-lokacij.component'; import { InformacijeComponent } from './informacije/informacije.component'; @NgModule({ declarations: [SeznamLokacijComponent], imports: [ BrowserModule, HttpClientModule, RouterModule.forRoot([ { path: '', component: SeznamLokacijComponent }, { path: 'informacije', component: InformacijeComponent }, ]), ], providers: [], bootstrap: [SeznamLokacijComponent], }) export class AppModule {} ``` > Uvozimo modul `RouterModule`. V `imports` definiramo `RouterModule.forRoot` in mu podamo array objektov, ki vsebujejo atributa `path` in `component`, ki dolocata za kateri url se bo izrisala katera komponenta. > Ob kliku na gumb/link z `routerLink=""` nam bo izrisalo komponento *seznam-lokacij*, ob kliku na `routerLink="informacije"` pa komponento *informacije*. ## Usmerjanje s parametri 1. V `app.module.ts` nastavimo pot z nekimi parametri. ```ts ... RouterModule.forRoot([ ..., { path: 'lokacija/:idLokacije', component: StranSPodrobnostmiComponent }, ..., ]), ... ``` 2. V `~.component.ts` datoteki komponente, kamor kaze parametrizirana pot nastavimo naslednje: 1. Uvozimo `ActivatedRoute`, `ParamMap` in `switchMap`. ```ts ... import { ActivatedRoute, ParamMap } from '@angular/router'; import { switchMap } from 'rxjs/operators'; ... ``` 2. V konstruktorju inicializiramo `ActivatedRoute`. ```ts ... constructor( ... private pot: ActivatedRoute, ... ) {} ... ``` 3. V metodi `ngOnInit()` (metoda se izvede ob postavitvi strani) povemo naj dobi ta parameter in ga uporabi. V tem primeru klicemo metodo storitve HTTP, ki nam pridobi lokacijo s pripadajocim ID in te podatke nato shranimo v spremenljivke, ki se bodo posredovale .html pogledu. ```ts export class StranSPodrobnostmiComponent implements OnInit { ... ngOnInit(): void { this.pot.paramMap.pipe( switchMap((parametri: ParamMap) => { let idLokacije: string = (parametri.get('idLokacije') || '').toString(); return this.httpStoritev.pridobiPodrobnostiLokacije(idLokacije); })).subscribe((lokacija: Lokacija) => { this.spremenljivka.lokacije = lokacija; }); } ... } ``` <br /> <br /> # Modularna zasnovanost Angular aplikacij Dobra praksa gradnje Angular aplikacij je, da jo locimo na cimvec komponent, katere nato zdruzujemo in jih zlagamo v poglede (ki so sicer tudi komponente). Samo stran/pogled (ki je tudi komponenta po svoje) sestavimo tako, da v njem zgolj zlagamo prej definirane komponente, in v .html datoteki pisemo samo bootstrap postavitve in bloke, ki nas povezejo z uporabljenimi moduli/komponentami (npr. glava, seznam komentarjev, dodaj komentar, sidebar,...). ## Prenasanje spremenljivk v "child" oz. odvisne komponente 1. V `~.component.ts` "parent" komponente definiramo spremenljivke (tudi te, ki jih potrebuje "child" komponenta) ```ts ... export class GlavnaStranComponent implements OnInit { ... spremenljivke = { "glava": { "naslov": "Aplikacija" }, "komentarji": {...}, "sidebar": {...} } ... } ... ``` 2. V `~.component.html` "parent" komponente podamo bloku "child" komponente pripadajoce spremenljivke v naslednji obliki: ```html <app-glava-strani [vsebina]="spremenljivke.glava"></app-glava-strani> ``` > V oglatih oklepajih dolocimo ime spremenljivke na strani otroka. > Blokom lahko dodajamo tudi "classe" za npr. bootstrap. 3. V `~.component.ts` povemo, da pricakuje podane spremenljivke s strani starsa s pomocjo modula `Input`. ```ts import { Component, OnInit, Input } from '@angular/core'; @Component({ selector: 'app-glava-strani', templateUrl: './glava-strani.component.html', styleUrls: ['./glava-strani.component.css'] }) export class GlavaStraniComponent implements OnInit { @Input() vsebina: any; constructor() { } ngOnInit() { } } ``` > Lahko tudi nastavimo default vrednost (npr. `@Input() vsebina: any = { "naslov": "Neznan" }`). <br /> <br /> # Spletni obrazci in posiljanje podatkov 1. V `app.module.ts` uvozimo `FormsModule` in `ReactiveFormsModule` in jih dodamo v `imports`. ```ts ... import { FormsModule, ReactiveFormsModule } from '@angular/forms'; ... @NgModule({ ... imports: [ FormsModule, ReactiveFormsModule, ... ], ... }) ``` 2. Za obrazec kreiramo svojo shemo oz. razred. Primer: ```ts export class Komentar { 'ime': string; 'komentar': string; 'starost': number; } ``` 3. V datoteki `~.component.ts` pripadajoce komponente definiramo objekt. ```ts export class ObrazecComponent implements OnInit { public komentar: Komentar = { ime: '', komentar: '', ocena: 5 }; ... } ``` 4. Vnose za obrazec v .html povezemo s pomocjo atributa `[(ngModel)]` in dodamo eventhandler `(onSubmit)` na formo. ```html <form (onSubmit)="metodaZaHandleForme()"> <input type=text [(ngModel)]="komentar.ime" /> <input type=textbox [(ngModel)]="komentar.komentar"> <select [(ngModel)]="komentar.ocena"> <option [ngValue]="1">1</option> <option [ngValue]="2">2</option> <option [ngValue]="3">3</option> <option [ngValue]="4">4</option> <option [ngValue]="5">5</option> </select> <button type="submit">Shrani</button> </form> ``` > Posebnost pri `<select>` je, da vrednosti definiramo na `<option>` z uporabo `[ngValue]`. V metodi za handle submita se spodobi, da podatke nato tudi validiramo (ce niso valid izpisemo neko opozorilo or sumthen, predstavljaj si kukr validacija podatkov na kontrolerju serverja), jih z metodo http storitve posredujemo na API streznik, formo resertiramo in pocistimo (nastavimo objekt `komentar` v tem primeru na default vrednosti - prazni stringi itd.) in ce se nam teli objekti tudi izrisujejo na strani, ga se dodamo (npr. mamo spremenljivko arraya Komentarjev in nov komentar dodamo v ta array => `this.komentarji.unshift(this.komentar)`). <br /> <br /> # Izboljsava arhitekture Kot se spodobi za Lavbi skripto pove pravilno postavitev projekta sele na koncu tko da here we go :) ## Locimo usmerjanje 1. Kreiramo svoj modul za usmerjevalnik. ```ps1 ng generate module app-usmerjanje ``` > Ustvari nam novo datoteko `app-usmerjanje.module.ts`. 2. V datoteki `app.module.ts` odstranimo `RouterModule.forRoot` in te fore in uvozimo `AppUsmerjanjeModule`. ```ts import { AppUsmerjanjeModule } from './app-usmerjanje/app-usmerjanje.module'; ... @NgModule({ ... imports: [ AppUsmerjanjeModule, ... ], ... }) ``` 3. Dopisemo pizdarije v `app-usmerjanje.module.ts`. ```ts import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { RouterModule, Routes } from '@angular/router'; import { DomacaStranComponent } from '../domaca-stran/domaca-stran.component'; import { InformacijeComponent } from '../informacije/informacije.component'; import { StranSPodrobnostmiComponent } from '../stran-s-podrobnostmi/stran-s-podrobnostmi.component'; const poti: Routes = [ { path: '', component: DomacaStranComponent }, { path: 'informacije', component: InformacijeComponent }, { path: 'lokacija/:idLokacije', component: StranSPodrobnostmiComponent }, ]; @NgModule({ declarations: [], imports: [CommonModule, RouterModule.forRoot(poti)], exports: [RouterModule], }) export class AppUsmerjanjeModule {} ``` ## Nardimo svoje razrede za sheme oz. razrede Podobno kot pri mongoose nardimo svoje razrede za posamezne sheme, ki jih bomo uporabljali v aplikaciji. 1. Kreiramo svoj razred za vsako shemo in njegove odvisne sheme. ```ps1 ng generate class Lokacija ``` > Kreira datoteko `lokacija.ts` 2. Razrede iz komponent izrezemo in jih prilepimo v `lokacija.ts`. ```ts class DelovniCas { 'dnevi': string; 'odprtje': string; 'zaprtje': string; 'zaprto': boolean; } export class Komentar { 'naziv': string; 'ocena': number; 'komentar': string; } export class Lokacija { '_id': string; 'naziv': string; 'naslov': string; 'ocena': number; 'lastnosti': string[]; 'razdalja': number; 'koordinate': number[]; 'delovniCas': DelovniCas[]; 'komentarji': Komentar[]; } ``` 3. Popravimo vse poti v importih ## Organizacija po mapah ![Organizacija po mapah](https://i.imgur.com/pxX9KqQ.png) <br /> <br /> # Migracija na SPA aplikacijo ## Nastavitev globalnih spremenljivk V datotekah `src/environments/environment.ts` ter `src/environments/environment.prod.ts` nastavimo vse env globalne spremenljivke, ki jih bomo potrebovali (una z prod je za produkcijo, brez je za razvojno). Tu bi sle spremenljivke npr. za API streznik naslov (localhost za razvojno, heroku za produkcijo), gesla, usernejmi,... Ne smemo pozabit uvozit te datoteke na potrebna mesta, kjer se te spremenljivke pojavljajo! ```ts import { environment } from '../../../environments/environment'; ``` ## Preusmeritev na serverju V `app.js` zakomentiramo uporabo usmerjevalnika ter dodamo tolele ```js ... //var indexRouter = require("./app_server/routes/index"); //app.use(express.static(path.join(__dirname, "public"))); app.use(express.static(path.join(__dirname, "app_public", "build"))); ... //app.use("/", indexRouter); app.use("/api", indexApi); app.get("*", (req, res) => { res.sendFile(path.join(__dirname, "app_public", "build", "index.html")); }); ... ```