Come creare e distribuire un'applicazione materiale angolare

Pubblicato: 2022-03-10
Riepilogo rapido ↬ Una procedura dettagliata per la creazione di un'applicazione Web Angular 8 e di un'app per la generazione di codici QR completamente basata su Angular mentre è ospitata su Netlify.

Angular è una delle scelte popolari durante la creazione di nuove applicazioni web. Inoltre, le specifiche "Material Design" sono diventate una scelta obbligata per creare un'esperienza minimale e coinvolgente oggi. Pertanto, qualsiasi nuovo progetto "Angular" utilizza principalmente la "Libreria di progettazione dei materiali angolari" per utilizzare i componenti che seguono le specifiche di progettazione dei materiali. Dalle animazioni fluide al feedback di interazione corretto, tutto questo è già disponibile come parte della libreria ufficiale di design dei materiali per angular.

Dopo aver sviluppato l'applicazione Web, il passaggio successivo consiste nel distribuirla. È qui che entra in gioco "Netlify". Con la sua interfaccia molto facile da usare, la distribuzione automatica, la suddivisione del traffico per i test A/B e varie altre funzionalità, Netlify è sicuramente un ottimo strumento.

L'articolo sarà una procedura dettagliata sulla creazione di un'applicazione Web Angular 8 utilizzando la libreria ufficiale di Angular Material Design. Creeremo un'applicazione web per la generazione di codici QR completamente basata su Angular mentre è ospitata su Netlify.

I file per questo tutorial possono essere trovati su GitHub e una versione demo è distribuita qui.

Iniziare

  1. Installa Angular 8,
  2. Crea un account GitHub,
  3. Installa Git sul tuo computer,
  4. Crea un account Netlify.

Nota : utilizzerò VSCode e Microsoft Windows come IDE e sistema operativo preferiti, anche se i passaggi sarebbero simili per qualsiasi altro IDE su qualsiasi altro sistema operativo.

Dopo che i prerequisiti di cui sopra sono stati completati, iniziamo!

Altro dopo il salto! Continua a leggere sotto ↓

Scherzi e pianificazione

Prima di iniziare a creare il progetto, sarebbe utile pianificare in anticipo: che tipo di interfaccia utente vorremmo nella nostra applicazione? Ci saranno pezzi riutilizzabili? Come interagirà l'applicazione con i servizi esterni?

Innanzitutto, controlla i mock dell'interfaccia utente.

Homepage (Anteprima grande)
Creazione di una pagina QR (anteprima grande)
Pagina Cronologia (anteprima grande)

Queste sono le tre diverse pagine che saranno contenute nell'applicazione. La homepage sarà il punto di partenza della nostra applicazione. La creazione di una pagina QR dovrebbe occuparsi della creazione di un nuovo codice QR. La pagina Cronologia mostrerà tutti i codici QR salvati.

I mockup non solo forniscono un'idea dell'aspetto grafico dell'applicazione, ma separano anche la responsabilità di ogni pagina.

Un'osservazione (dalle simulazioni) è che sembra che la barra di navigazione in alto sia comune a tutte le pagine. Pertanto, la barra di navigazione può essere creata come componente riutilizzabile e riutilizzata.

Ora che abbiamo una buona idea di come apparirà l'applicazione e cosa può essere riutilizzato, iniziamo.

Creazione di un nuovo progetto angolare

Avvia VSCode, quindi apri una finestra di terminale in VSCode per generare un nuovo progetto Angular.

Terminale in VSCode (Anteprima grande)

Il terminale si aprirà con un percorso predefinito come mostrato nel prompt. È possibile passare a una directory preferita prima di procedere; nel caso di Windows, userò il comando cd .

Navigazione verso il percorso preferito (Anteprima grande)

Andando avanti, angular-cli ha un comando per generare nuovi progetti ng new <project-name> . Basta usare qualsiasi nome di progetto di fantasia che ti piace e premere invio, ad esempio ng new qr .

Questo attiverà la magia del cli angolare; fornirà alcune opzioni per configurare alcuni aspetti del progetto, ad esempio aggiungendo il routing angolare. Quindi, in base alle opzioni selezionate, genererà l'intero scheletro del progetto che può essere eseguito senza alcuna modifica.

Per questo tutorial, immetti per il routing e seleziona CSS per lo stile. Questo genererà un nuovo progetto Angular:

Creazione di un nuovo progetto Angular (Anteprima grande)

Ora abbiamo un progetto Angular completamente funzionante. Per assicurarci che tutto funzioni correttamente, possiamo eseguire il progetto inserendo questo comando nel terminale: ng serve . Uh oh, ma aspetta, questo si traduce in un errore. Cosa può essere successo?

Errore di servizio ng (anteprima grande)

Non preoccuparti. Ogni volta che crei un nuovo progetto usando angular-cli, genera l'intero scheletro all'interno di una cartella che prende il nome dal nome del progetto specificato nel comando ng new qr . Qui, dovremo cambiare la directory di lavoro corrente in quella appena creata. In Windows, utilizzare il comando cd qr per cambiare directory.

Ora, prova a eseguire di nuovo il progetto con l'aiuto di ng serve :

Progetto in esecuzione (anteprima grande)

Apri un browser web, vai all'URL https://localhost:4200 per vedere il progetto in esecuzione. Il comando ng serve esegue l'applicazione sulla porta 4200 per impostazione predefinita.

SUGGERIMENTO : per eseguirlo su una porta diversa, utilizziamo il comando ng serve --port <any-port> per esempio, ng serve --port 3000 .

Ciò garantisce che il nostro progetto Angular di base sia attivo e funzionante. Andiamo avanti.

Dobbiamo aggiungere la cartella del progetto a VSCode. Vai al menu "File" e seleziona "Apri cartella" e seleziona la cartella del progetto. La cartella del progetto verrà ora mostrata nella vista Explorer a sinistra.

Aggiunta della libreria dei materiali angolari

Per installare la libreria dei materiali Angular, utilizzare il seguente comando nella finestra del terminale: ng add @angular/material . Questo (di nuovo) porrà alcune domande come quale tema desideri, se desideri animazioni predefinite, se è richiesto il supporto touch, tra gli altri. Selezioneremo semplicemente il tema Indigo/Pink predefinito, Yes per aggiungere la libreria HammerJS e le animazioni del browser.

Aggiunta di materiale angolare (anteprima grande)

Il comando precedente configura anche l'intero progetto per abilitare il supporto per i componenti del materiale.

  1. Aggiunge le dipendenze del progetto a package.json ,
  2. Aggiunge il carattere Roboto al file index.html ,
  3. Aggiunge il carattere dell'icona Material Design al tuo index.html ,
  4. Aggiunge anche alcuni stili CSS globali a:
    • Rimuovere i margini dal corpo,
    • Imposta height: 100% nell'HTML e nel corpo,
    • Imposta Roboto come carattere predefinito dell'applicazione.

Solo per essere sicuro che tutto sia a posto, a questo punto puoi eseguire di nuovo il progetto, anche se non noterai nulla di nuovo.

Aggiunta della pagina iniziale

Il nostro scheletro di progetto è ora pronto. Iniziamo aggiungendo la home page.

(Grande anteprima)

Vogliamo mantenere la nostra homepage semplice, proprio come l'immagine sopra. Questa home page utilizza alcuni componenti di materiale angolare. Sezioniamo.

  1. La barra in alto è un semplice elemento di nav HTML che contiene un pulsante di stile materiale, mat-button , con un'immagine e un testo come figlio. Il colore della barra è lo stesso del colore principale che è stato selezionato durante l'aggiunta della libreria di materiali Angular;
  2. Un'immagine centrata;
  3. Un altro, mat-button , con solo un testo come figlio. Questo pulsante consentirà agli utenti di navigare alla pagina della cronologia;
  4. Un badge di conteggio, matBadge , allegato al pulsante sopra, che mostra il numero di codici QR salvati dall'utente;
  5. Un pulsante di azione mobile, mat-fab , nell'angolo in basso a destra con il colore dell'accento dal tema selezionato.

Divagando un po', aggiungiamo prima altri componenti e servizi richiesti.

Aggiunta di intestazione

Come previsto in precedenza, la barra di navigazione andrebbe riutilizzata, creiamola come componente angolare separato. Aprire il terminale in VSCode e digitare ng gc header (abbreviazione di ng generate component header) e premere Invio. Questo creerà una nuova cartella denominata "header" che conterrà quattro file:

  • header.component.css : usato per fornire uno stile per questo componente;
  • header.component.html : per aggiungere elementi HTML;
  • header.component.spec.ts : per scrivere casi di test;
  • header.component.ts : per aggiungere la logica basata su Typescript.
Componente intestazione (anteprima grande)

Per far sembrare l'intestazione come nei mock, aggiungi il codice HTML sottostante in header.component.html :

 <nav class="navbar" [class.mat-elevation-z8]=true> <div> <button *ngIf="showBackButton" aria-hidden=false mat-icon-button routerLink="/"> <mat-icon> <i class="material-icons md-32">arrow_back</i> </mat-icon> </button> <span>{{currentTitle}}</span> </div> <button *ngIf="!showBackButton" aria-hidden=false mat-button class="button"> <img src="../../assets/qr-icon-white.png"> <span>QR Generator</span> </button> <button *ngIf="showHistoryNav" aria-hidden=false mat-button class="button" routerLink="/history"> <span>History</span> </button> </nav>

SUGGERIMENTO : per aggiungere l'elevazione per qualsiasi componente materiale, utilizzare [class.mat-elevation-z8]=true , il valore dell'elevazione può essere modificato modificando il valore z , in questo caso è z8 . Ad esempio, per modificare l'elevazione su 16, utilizzare [class.mat-elevation-z16]=true .

Nello snippet HTML sopra, sono utilizzati due elementi di materiale angolari: mat-icon e mat-button/mat-icon-button . Il loro utilizzo è molto semplice; per prima cosa, dobbiamo aggiungere questi due come moduli nel nostro app.module.ts come mostrato di seguito:

Importazione modulo per mat-icon e mat-button (anteprima grande)

Questo ci consentirà di utilizzare questi due elementi di materiale angolari ovunque in qualsiasi componente.

Per aggiungere pulsanti materiale, viene utilizzato il seguente snippet HTML:

 <button mat-button> Material Button </button>

Sono disponibili diversi tipi di elementi del pulsante materiale nella libreria dei materiali angolari come mat-raised-button , mat-flat-button , mat-fab e altri; basta sostituire il mat-button nello snippet di codice sopra con qualsiasi altro tipo.

Tipi di pulsanti materiale (Anteprima grande)

L'altro elemento è mat-icon che viene utilizzato per mostrare le icone disponibili nella libreria delle icone dei materiali. Quando all'inizio è stata aggiunta la libreria dei materiali Angular, è stato aggiunto anche un riferimento alla libreria delle icone dei materiali, che ci ha permesso di utilizzare le icone dalla vasta gamma di icone.

L'utilizzo è semplice come:

 <mat-icon> <i class="material-icons md-32">arrow_back</i> </mat-icon>

Il tag nidificato <i> può essere utilizzato per modificare la dimensione dell'icona (qui è md-32 ) che renderà la dimensione dell'icona 32px in altezza e larghezza. Questo valore può essere md-24 , md-48 e così via. Il valore del tag <i> annidato è il nome dell'icona. (Il nome può essere trovato qui per qualsiasi altra icona.)

Accessibilità

Ogni volta che vengono utilizzate icone o immagini, è indispensabile che forniscano informazioni sufficienti per scopi di accessibilità o per un utente di screen reader. ARIA (Accessible Rich Internet Applications) definisce un modo per rendere i contenuti web e le applicazioni web più accessibili alle persone con disabilità.

Un punto da notare è che gli elementi HTML che hanno la loro semantica nativa (es. nav ) non hanno bisogno di attributi ARIA; lo screen reader saprebbe già che nav è un elemento di navigazione e lo leggerebbe come tale.

Le specifiche ARIA sono suddivise in tre categorie: ruoli, stati e proprietà. Diciamo che un div viene utilizzato per creare una barra di avanzamento nel codice HTML. Non ha semantica nativa; Il ruolo ARIA può descrivere questo widget come una barra di avanzamento, la proprietà ARIA può denotare la sua caratteristica in quanto può essere trascinata. Lo stato ARIA descriverà il suo stato corrente come il valore corrente della barra di avanzamento. Vedi lo snippet qui sotto:

 <div role="progressbar" aria-valuenow="75" aria-valuemin="0" aria-valuemax="100"> </div>

Allo stesso modo, viene utilizzato un attributo aria molto comunemente usato: aria-hidden=true/false . Il valore true rende quell'elemento invisibile agli screen reader.

Poiché la maggior parte degli elementi dell'interfaccia utente utilizzati in questa applicazione hanno un significato semantico nativo, gli unici attributi ARIA utilizzati sono per specificare gli stati di visibilità di ARIA. Per informazioni dettagliate, fare riferimento a questo.

header.component.html contiene una logica per nascondere e mostrare il pulsante indietro a seconda della pagina corrente. Inoltre, il pulsante Home contiene anche un'immagine/logo che dovrebbe essere aggiunto alla cartella /assets . Scarica l'immagine da qui e salvala nella cartella /assets .

Per lo stile della barra di navigazione, aggiungi il CSS sottostante in header.component.css :

 .navbar { position: fixed; top: 0; left: 0; right: 0; z-index: 2; background: #3f51b5; display: flex; flex-wrap: wrap; align-items: center; padding: 12px 16px; } .button { color: white; margin: 0px 10px; }

Poiché vogliamo mantenere il componente di intestazione riutilizzabile in altri componenti, quindi per decidere cosa deve essere mostrato, li richiederemo come parametri da altri componenti. Ciò richiede l'uso del decoratore @Input() che si legherà alle variabili che abbiamo usato in header.component.html .

Aggiungi queste righe nel file header.component.ts :

 // Add these three lines above the constructor entry. @Input() showBackButton: boolean; @Input() currentTitle: string; @Input() showHistoryNav: boolean; constructor() { }

I tre collegamenti precedenti verranno passati come parametro da altri componenti che utilizzerà il componente di intestazione. Il suo utilizzo sarà più chiaro una volta che andremo avanti.

Andando avanti, dobbiamo creare una homepage che possa essere rappresentata da un componente Angular. Quindi iniziamo creando un altro componente; digitare ng gc home nel terminale per generare automaticamente il componente home. Come in precedenza, verrà creata una nuova cartella denominata "home" contenente quattro file diversi. Prima di procedere alla modifica di quei file, aggiungiamo alcune informazioni di routing al modulo di routing angolare.

Aggiunta di instradamento

Angular fornisce un modo per mappare l'URL a un componente specifico. Ogni volta che avviene una certa navigazione, il framework Angular monitora l'URL e in base alle informazioni presenti nel file app-routing.module.ts ; inizializza il componente mappato. In questo modo i diversi componenti non devono assumersi la responsabilità di inizializzare altri componenti. Nel nostro caso l'applicazione dispone di tre pagine navigabili cliccando su pulsanti differenti. Raggiungiamo questo obiettivo sfruttando il supporto di routing fornito dal framework Angular.

Il componente home dovrebbe essere il punto di partenza dell'applicazione. Aggiungiamo queste informazioni al file app-routing.module.ts .

Componente Home Routing (Anteprima grande)

La proprietà path è impostata come una stringa vuota; questo ci consente di mappare l'URL dell'applicazione sul componente home page, qualcosa come google.com che mostra la home page di Google.

SUGGERIMENTO : il valore del percorso non inizia mai con un " / ", ma utilizza invece una stringa vuota anche se il percorso può essere come search/coffee .

Tornando al componente home page, sostituisci il contenuto di home.component.html con questo:

 <app-header [showBackButton]="false" [currentTitle]=""></app-header> <app-profile></app-profile> <!-- FAB Fixed --> <button mat-fab class="fab-bottom-right" routerLink="/create"> <mat-icon> <i class="material-icons md-48">add</i> </mat-icon> </button>

Ci sono tre parti del componente home:

  1. Il componente di intestazione riutilizzabile <app-header> ,
  2. Componente <app-profile> ,
  3. Il pulsante di azione mobile in basso a destra.

Lo snippet HTML sopra mostra come il componente di intestazione riutilizzabile viene utilizzato in altri componenti; usiamo semplicemente il selettore dei componenti e passiamo i parametri richiesti.

Il componente del profilo è stato creato per essere utilizzato come corpo per la home page: lo creeremo presto.

Il pulsante di azione mobile con l'icona + è una specie di pulsante materiale angolare di tipo mat-fab in basso a destra dello schermo. Ha la direttiva dell'attributo routerLink che utilizza le informazioni sul percorso fornite in app-routing.module.ts per la navigazione. In questo caso, il pulsante ha il valore del percorso come /create che verrà mappato per creare il componente.

Per far fluttuare il pulsante di creazione in basso a destra, aggiungi il codice CSS sottostante in home.component.css :

 .fab-bottom-right { position: fixed; left: auto; bottom: 5%; right: 10%; }

Poiché il componente del profilo dovrebbe gestire il corpo della home page, lasceremo home.component.ts intatto.

Aggiunta di un componente del profilo

Aprire il terminale, digitare ng gc profile e premere invio per generare il componente del profilo. Come pianificato in precedenza, questo componente gestirà il corpo principale della home page. Apri profile.component.html e sostituisci il suo contenuto con questo:

 <div class="center profile-child"> <img class="avatar" src="../../assets/avatar.png"> <div class="profile-actions"> <button mat-raised-button matBadge="{{historyCount}}" matBadgeOverlap="true" matBadgeSize="medium" matBadgeColor="accent" color="primary" routerLink="/history"> <span>History</span> </button> </div> </div>

Lo snippet HTML sopra mostra come utilizzare l'elemento matBadge della libreria dei materiali. Per poterlo utilizzare qui, dobbiamo seguire il solito esercizio di aggiunta di MatBadgeModule al file app.module.ts . I badge sono piccoli descrittori di stato pittorici per elementi dell'interfaccia utente come pulsanti, icone o testi. In questo caso, viene utilizzato con un pulsante per mostrare il conteggio dei QR salvati dall'utente. Il badge della libreria dei materiali angolare ha varie altre proprietà come l'impostazione della posizione del badge con matBadgePosition , matBadgeSize per specificare la dimensione e matBadgeColor per impostare il colore del badge.

È necessario aggiungere un'altra risorsa immagine alla cartella delle risorse: Download. Salva lo stesso nella cartella /assets del progetto.

Apri profile.component.css e aggiungi questo:

 .center { top: 50%; left: 50%; position: absolute; transform: translate(-50%, -50%); } .profile-child { display: flex; flex-direction: column; align-items: center; } .profile-actions { padding-top: 20px; } .avatar { border-radius: 50%; width: 180px; height: 180px; }

Il CSS di cui sopra realizzerà l'interfaccia utente come pianificato.

Andando avanti, abbiamo bisogno di una sorta di logica per aggiornare il valore del conteggio della cronologia poiché si rifletterà nel matBadge utilizzato in precedenza. Apri profile.component.ts e aggiungi il seguente snippet in modo appropriato:

 export class ProfileComponent implements OnInit { historyCount = 0; constructor(private storageUtilService: StorageutilService) { } ngOnInit() { this.updateHistoryCount(); } updateHistoryCount() { this.historyCount = this.storageUtilService.getHistoryCount(); } }

Abbiamo aggiunto StorageutilService ma fino ad ora non abbiamo creato un servizio del genere. Ignorando l'errore, abbiamo completato il nostro componente del profilo che completa anche il nostro componente della home page. Rivisiteremo questo componente del profilo dopo aver creato il nostro servizio di utilità di archiviazione. Va bene, allora facciamolo.

Memoria locale

HTML5 fornisce funzionalità di archiviazione web che possono essere utilizzate per archiviare i dati localmente. Ciò fornisce molto più spazio di archiviazione rispetto ai cookie: almeno 5 MB contro 4 KB. Esistono due tipi di archiviazione Web con ambito e durata diversi: Local e Session . Il primo può memorizzare i dati in modo permanente mentre il secondo è temporaneo e per una singola sessione. La decisione di selezionare il tipo può essere basata sul caso d'uso, nel nostro scenario vogliamo salvare tra le sessioni, quindi andremo con l'archiviazione locale .

Ciascun dato è memorizzato in una coppia chiave/valore. Utilizzeremo il testo per il quale viene generato il QR come chiave e l'immagine QR codificata come stringa base64 come valore. Crea una cartella di entità, all'interno della cartella crea un nuovo file qr-object.ts e aggiungi lo snippet di codice come mostrato:

Modello di entità QR (anteprima grande)

Il contenuto della classe:

 export class QR { text: string; imageBase64: string; constructor(text: string, imageBase64: string) { this.imageBase64 = imageBase64; this.text = text; } }

Ogni volta che l'utente salva il QR generato, creeremo un oggetto della classe sopra e salveremo quell'oggetto utilizzando il servizio di utilità di archiviazione.

Crea una nuova cartella dei servizi, creeremo molti servizi, è meglio raggrupparli insieme.

Cartella Servizi (Anteprima grande)

Cambia la directory di lavoro corrente in services, cd services , per creare un nuovo servizio usando ng gs <any name> . Questa è una scorciatoia per ng generate service <any name> , digita ng gs storageutil e premi invio

Questo creerà due file:

  • storageutil.service.ts
  • storageutil.service.spec.ts

Quest'ultimo serve per la scrittura di unit test. Apri storageutil.service.ts e aggiungi questo:

 private historyCount: number; constructor() { } saveHistory(key : string, item :string) { localStorage.setItem(key, item) this.historyCount = this.historyCount + 1; } readHistory(key : string) : string { return localStorage.getItem(key) } readAllHistory() : Array<QR> { const qrList = new Array<QR>(); for (let i = 0; i < localStorage.length; i++) { const key = localStorage.key(i); const value = localStorage.getItem(key); if (key && value) { const qr = new QR(key, value); qrList.push(qr); } } this.historyCount = qrList.length; return qrList; } getHistoryCount(): number { if (this.historyCount) { return this.historyCount; } this.readAllHistory(); return this.historyCount; } deleteHistory(key : string) { localStorage.removeItem(key) this.historyCount = this.historyCount - 1; }

Importa la classe qr-object per correggere eventuali errori. Per utilizzare la funzionalità di archiviazione locale, non è necessario importare nulla di nuovo, è sufficiente utilizzare la parola chiave localStorage per salvare o ottenere valore in base a una chiave.

Ora apri nuovamente il file profile.component.ts e importa la classe StorageutilService per completare correttamente il componente del profilo.

Eseguendo il progetto, possiamo vedere che la home page è attiva come previsto.

Aggiunta Crea pagina QR

Abbiamo la nostra homepage pronta, anche se il pulsante crea/aggiungi non fa nulla. Non preoccuparti, la logica vera e propria era già stata scritta. Abbiamo utilizzato una direttiva routerLink per modificare il percorso di base dell'URL in /create ma non è stata aggiunta alcuna mappatura al file app-routing.module.ts .

Creiamo un componente che si occuperà della creazione di nuovi codici QR, digita ng gc create-qr e premi invio per generare un nuovo componente.

Apri il file app-routing.module.ts e aggiungi la voce seguente all'array dei routes :

 { path: 'create', component: CreateQrComponent },

Questo mapperà il CreateQRComponent con l'URL /create .

Apri create-qr.components.html e sostituisci il contenuto con questo:

 <app-header [showBackButton]="showBackButton" [currentTitle]="title" [showHistoryNav]="showHistoryNav"></app-header> <mat-card class="qrCard" [class.mat-elevation-z12]=true> <div class="qrContent"> <!--Close button section--> <div class="closeBtn"> <button mat-icon-button color="accent" routerLink="/" matTooltip="Close"> <mat-icon> <i class="material-icons md-48">close</i> </mat-icon> </button> </div> <!--QR code image section--> <div class="qrImgDiv"> <img *ngIf="!showProgressSpinner" src={{qrCodeImage}} width="200px" height="200px"> <mat-spinner *ngIf="showProgressSpinner"></mat-spinner> <div class="actionButtons" *ngIf="!showProgressSpinner"> <button mat-icon-button color="accent" matTooltip="Share this QR"> <mat-icon> <i class="material-icons md-48">share</i> </mat-icon> </button> <button mat-icon-button color="accent" (click)="saveQR()" matTooltip="Save this QR"> <mat-icon> <i class="material-icons md-48">save</i> </mat-icon> </button> </div> </div> <!--Textarea to write any text or link--> <div class="qrTextAreaDiv"> <mat-form-field> <textarea matInput [(ngModel)]="qrText" cdkTextareaAutosize cdkAutosizeMinRows="4" cdkAutosizeMaxRows="4" placeholder="Enter a website link or any text..."></textarea> </mat-form-field> </div> <!--Create Button--> <div class="createBtnDiv"> <button class="createBtn" mat-raised-button color="accent" matTooltip="Create new QR code" matTooltipPosition="above" (click)="createQrCode()">Create</button> </div> </div> </mat-card>

Il frammento di cui sopra utilizza molti degli elementi della libreria dei materiali Angular. Come previsto, ha un riferimento al componente dell'intestazione in cui vengono passati i parametri richiesti. Il prossimo è il corpo principale della pagina di creazione; è costituito da una carta materiale angolare o una carta mat-card centrata ed elevata fino a 12px poiché viene utilizzato [class.mat-elevation-z12]=true .

La scheda materiale è solo un altro tipo di contenitore che può essere utilizzato come qualsiasi altro tag div . Sebbene la libreria dei materiali fornisca alcune proprietà per disporre informazioni ben definite in un mat-card come posizionamento dell'immagine, titolo, sottotitolo, descrizione e azione, come si può vedere di seguito.

Esempio di carta (Anteprima grande)

Nello snippet HTML sopra, abbiamo usato mat-card come qualsiasi altro contenitore. Un altro elemento della libreria dei materiali utilizzato è matTooltip ; è solo un altro suggerimento con facilità d'uso, visualizzato quando l'utente passa il mouse sopra o preme a lungo un elemento. Usa lo snippet qui sotto per mostrare il suggerimento:

 matTooltip="Any text you want to show"

Può essere utilizzato con pulsanti icona o qualsiasi altro elemento dell'interfaccia utente per trasmettere informazioni aggiuntive. Nel contesto dell'applicazione, vengono visualizzate informazioni sul pulsante dell'icona di chiusura. Per modificare la posizione della descrizione comando, viene utilizzato matTooltipPosition :

 matTooltip="Any text you want to show" matTooltipPosition="above"

Oltre a matTooltip , mat-spinner viene utilizzato per mostrare l'avanzamento del caricamento. Quando l'utente fa clic sul pulsante "Crea", viene effettuata una chiamata di rete. Questo è quando viene mostrato lo spinner di avanzamento. Quando la chiamata di rete ritorna con il risultato, nascondiamo semplicemente lo spinner. Può essere utilizzato semplicemente in questo modo:

 <mat-spinner *ngIf="showProgressSpinner"></mat-spinner>

showProgressSpinner è una variabile booleana che viene utilizzata per mostrare/nascondere lo spinner di avanzamento. La libreria fornisce anche altri parametri come [color]='accent' per cambiare colore, [mode]='indeterminate' per cambiare il tipo di spinner di avanzamento. Uno spinner di avanzamento indeterminato non mostrerà l'avanzamento dell'attività mentre uno determinato può avere valori diversi per riflettere l'avanzamento dell'attività. Qui viene utilizzato uno spinner indeterminato poiché non sappiamo quanto tempo impiegherà la chiamata di rete.

La libreria dei materiali fornisce una variante di textarea conforme alle linee guida sui materiali, ma può essere utilizzata solo come discendente di mat-form-field . L'utilizzo del materiale textarea è semplice quanto quello HTML predefinito, come di seguito:

 <mat-form-field> <textarea matInput placeholder="Hint text"></textarea> </mat-form-field>

matInput è una direttiva che consente al tag di input nativo di funzionare con mat-form-field . La proprietà placeholder consente di aggiungere qualsiasi testo di suggerimento per l'utente.

SUGGERIMENTO : utilizzare la proprietà textarea cdkTextareaAutosize per renderla ridimensionabile automaticamente. Usa cdkAutosizeMinRows e cdkAutosizeMaxRows per impostare righe e colonne e tutti e tre insieme per ridimensionare automaticamente textarea fino a raggiungere il limite massimo di righe e colonne impostato.

Per utilizzare tutti questi elementi della libreria dei materiali, dobbiamo aggiungerli nel file app.module.ts .

Creazione di importazioni di moduli QR (anteprima grande)

C'è un'immagine segnaposto utilizzata nell'HTML. Scaricalo e salvalo nella cartella /assets .

L'HTML sopra richiede anche uno stile CSS, quindi apri il file create-qr.component.ts e aggiungi quanto segue:

 .qrCard { display: flex; flex-direction: column; align-items: center; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 20%; height: 65%; padding: 50px 20px; } .qrContent { display: flex; flex-direction: column; align-items: center; width: 100%; } .qrTextAreaDiv { width: 100%; display: flex; flex-direction: row; justify-content: center; padding: 0px 0px; position: absolute; bottom: 10%; } .createBtn { left: 50%; transform: translate(-50%, 0px); width: 80%; } .createBtnDiv { position: absolute; bottom: 5%; width: 100%; } .closeBtn { display: flex; flex-direction: row-reverse; align-items: flex-end; width: 100%; margin-bottom: 20px; } .closeBtnFont { font-size: 32px; color: rgba(0,0,0,0.75); } .qrImgDiv { top: 20%; position: absolute; display: flex; flex-direction: column; align-items: center; justify-content: center; width: 100%; } .actionButtons { display: flex; flex-direction: row; padding-top: 20px; }

Connettiamo l'interfaccia utente con la logica. Apri il file create-qr.component.ts e aggiungi il codice seguente, lasciando quelle righe che sono già presenti:

 export class CreateQrComponent implements OnInit { qrCodeImage = '../../../assets/download.png'; showProgressSpinner = false; qrText: string; currentQR; showBackButton = true; title = 'Generate New QR Code'; showHistoryNav = true; constructor(private snackBar: MatSnackBar, private restutil: RestutilService, private storageService: StorageutilService) { } ngOnInit() { } createQrCode() { //Check if any value is given for the qr code text if (!!this.qrText) { //Make the http call to load qr code this.loadQRCodeImage(this.qrText); } else { //Show snackbar this.showSnackbar('Enter some text first') } } public loadQRCodeImage(text: string) { // Show progress spinner as the request is being made this.showProgressSpinner = true; // Trigger the API call this.restutil.getQRCode(text).subscribe(image =>{ // Received the result - as an image blob - require parsing this.createImageBlob(image); }, error => { console.log('Cannot fetch QR code from the url', error) // Hide the spinner - show a proper error message this.showProgressSpinner = false; }); } private createImageBlob(image: Blob) { // Create a file reader to read the image blob const reader = new FileReader(); // Add event listener for "load" - invoked once the blob reading is complete reader.addEventListener('load', () => { this.qrCodeImage = reader.result.toString(); //Hide the progress spinner this.showProgressSpinner = false; this.currentQR = reader.result.toString(); }, false); // Read image blob if it is not null or undefined if (image) { reader.readAsDataURL(image); } } saveQR() { if (!!this.qrText) { this.storageService.saveHistory(this.qrText, this.currentQR); this.showSnackbar('QR saved') } else { //Show snackbar this.showSnackbar('Enter some text first') } } showSnackbar(msg: string) { //Show snackbar this.snackBar.open(msg, '', { duration: 2000, }); } }

Per fornire agli utenti informazioni contestuali, utilizziamo anche MatSnackBar dalla libreria di progettazione dei materiali. Questo appare come un popup da sotto lo schermo e rimane per alcuni secondi prima di scomparire. Questo non è un elemento ma piuttosto un servizio che può essere invocato dal codice Typescript.

Lo snippet sopra con il nome del metodo showSnackbar mostra come aprire uno snackbar, ma prima che possa essere utilizzato, dobbiamo aggiungere la voce MatSnackBar nel file app.module.ts proprio come abbiamo fatto per altri elementi della libreria dei materiali.

SUGGERIMENTO : nelle recenti versioni della libreria di materiali Angular, non esiste un modo semplice per modificare lo stile dello snackbar. Invece, è necessario apportare due aggiunte al codice.

Innanzitutto, usa il CSS sottostante per modificare i colori di sfondo e di primo piano:

 ::ng-deep snack-bar-container.snackbarColor { background-color: rgba(63, 81, 181, 1); } ::ng-deep .snackbarColor .mat-simple-snackbar { color: white; }

In secondo luogo, usa una proprietà chiamata panelClass per impostare lo stile sulla classe CSS sopra:

 this.snackBar.open(msg, '', { duration: 2000, panelClass: ['snackbarColor'] });

Le due combinazioni di cui sopra consentiranno uno stile personalizzato al componente snackbar della libreria di design dei materiali.

Questo completa i passaggi su come creare una pagina QR, ma manca ancora un pezzo. Controllando il file create-qr.component.ts , mostrerà un errore relativo al pezzo mancante. Il pezzo mancante di questo puzzle è RestutilService , responsabile del recupero dell'immagine del codice QR dall'API di terze parti.

Nel terminale, cambia la directory corrente in servizi digitando ng gs restutil e premendo Invio. Questo creerà i file RestUtilService. Apri il file restutil.service.ts e aggiungi questo snippet:

 private edgeSize = '300'; private BASE_URL = 'https://api.qrserver.com/v1/create-qr-code/?data={data}!&size={edge}x{edge}'; constructor(private httpClient: HttpClient) { } public getQRCode(text: string): Observable { // Create the url with the provided data and other options let url = this.BASE_URL; url = url.replace("{data}", text).replace(/{edge}/g, this.edgeSize); // Make the http api call to the url return this.httpClient.get(url, { responseType: 'blob' }); } private edgeSize = '300'; private BASE_URL = 'https://api.qrserver.com/v1/create-qr-code/?data={data}!&size={edge}x{edge}'; constructor(private httpClient: HttpClient) { } public getQRCode(text: string): Observable { // Create the url with the provided data and other options let url = this.BASE_URL; url = url.replace("{data}", text).replace(/{edge}/g, this.edgeSize); // Make the http api call to the url return this.httpClient.get(url, { responseType: 'blob' }); }

Il servizio precedente recupera l'immagine QR dall'API di terze parti e poiché la risposta non è di tipo JSON, ma un'immagine, specifichiamo responseType come 'blob' nello snippet sopra.

Angular fornisce la classe HttpClient per comunicare con qualsiasi server che supporta HTTP. Fornisce molte funzionalità come il filtraggio della richiesta prima che venga attivata, il recupero della risposta, l'abilitazione dell'elaborazione della risposta tramite callback e altro. Per utilizzare lo stesso, aggiungi una voce per HttpClientModule nel file app.module.ts .

Infine, importa questo servizio nel file create-qr.component.ts per completare la creazione del codice QR.

Ma aspetta! C'è un problema con la logica di creazione QR sopra. Se l'utente utilizza lo stesso testo per generare il QR ancora e ancora, si verificherà una chiamata di rete. Un modo per rimediare a questo è memorizzare nella cache la richiesta, servendo così la risposta dalla cache se il testo della richiesta è lo stesso.

Richiesta di memorizzazione nella cache

Angular fornisce un modo semplificato per effettuare chiamate HTTP, HttpClient, insieme a HttpInterceptor per ispezionare e trasformare richieste o risposte HTTP da e verso i server. Può essere utilizzato per l'autenticazione o la memorizzazione nella cache e molte cose simili, più intercettori possono essere aggiunti e concatenati per ulteriori elaborazioni. In questo caso, stiamo intercettando le richieste e servendo la risposta dalla cache se il QR text è lo stesso.

Crea una cartella interceptor, quindi crea un file cache-interceptor.ts :

Intercettatore di cache (anteprima grande)

Aggiungi il seguente snippet di codice al file:

 import { Injectable } from '@angular/core'; import { HttpInterceptor, HttpResponse, HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http'; import { tap } from 'rxjs/operators'; import { of, Observable } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class RequestCachingService implements HttpInterceptor { private cacheMap = new Map<string, HttpResponse<any>>(); constructor() { } intercept(req: HttpRequest , next: HttpHandler): Observable<HttpEvent<any>> { const cachedResponse = this.cacheMap.get(req.urlWithParams); if (cachedResponse) { return of(cachedResponse); } return next.handle(req).pipe(tap(event => { if (event instanceof HttpResponse) { this.cacheMap.set(req.urlWithParams, event); } })) } } import { Injectable } from '@angular/core'; import { HttpInterceptor, HttpResponse, HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http'; import { tap } from 'rxjs/operators'; import { of, Observable } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class RequestCachingService implements HttpInterceptor { private cacheMap = new Map<string, HttpResponse<any>>(); constructor() { } intercept(req: HttpRequest , next: HttpHandler): Observable<HttpEvent<any>> { const cachedResponse = this.cacheMap.get(req.urlWithParams); if (cachedResponse) { return of(cachedResponse); } return next.handle(req).pipe(tap(event => { if (event instanceof HttpResponse) { this.cacheMap.set(req.urlWithParams, event); } })) } }

Nello snippet di codice sopra, abbiamo una mappa con la chiave che è l'URL della richiesta e la risposta come valore. Verifichiamo se l'URL corrente è presente nella mappa; if it is, then return the response (the rest is handled automatically). If the URL is not in the map, we add it.

We are not done yet. An entry to the app.module.ts is required for its proper functioning. Add the below snippet:

 import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'; import { CacheInterceptor } from './interceptor/cache-interceptor'; providers: [ { provide: HTTP_INTERCEPTORS, useClass: CacheInterceptor, multi: true } ],

This adds the caching feature to our application. Let's move on to the third page, the History page.

Adding The History Page

All the saved QR codes will be visible here. To create another component, open terminal type ng gc history and press Enter.

Open history.component.css and add the below code:

 .main-content { padding: 5% 10%; } .truncate { width: 90%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .center-img { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); display: flex; flex-direction: column; align-items: center; }

Open history.component.html and replace the content with this:

 <app-header [showBackButton]="showBackButton" [currentTitle]="title" [showHistoryNav]="showHistoryNav"></app-header> <div class="main-content"> <mat-grid-list cols="4" rowHeight="500px" *ngIf="historyList.length > 0"> <mat-grid-tile *ngFor="let qr of historyList"> <mat-card> <img mat-card-image src="{{qr.imageBase64}}"> <mat-card-content> <div class="truncate"> {{qr.text}} </div> </mat-card-content> <mat-card-actions> <button mat-button (click)="share(qr.text)">SHARE</button> <button mat-button color="accent" (click)="delete(qr.text)">DELETE</button> </mat-card-actions> </mat-card> </mat-grid-tile> </mat-grid-list> <div class="center-img" *ngIf="historyList.length == 0"> <img src="../../assets/no-see.png" width="256" height="256"> <span>Nothing to see here</span> </div> </div>

As usual, we have the header component at the top. Then, the rest of the body is a grid list that will show all the saved QR codes as individual mat-card . For the grid view, we are using mat-grid-list from the Angular material library. As per the drill, before we can use it, we have to first add it to the app.module.ts file.

Mat grid list funge da contenitore con più tile figlio chiamati mat-grid-tile . Nello snippet HTML sopra, ogni riquadro viene creato utilizzando mat-card utilizzando alcune delle sue proprietà per il posizionamento generico di altri elementi dell'interfaccia utente. Possiamo fornire il number of columns e rowHeight , che viene utilizzato per calcolare automaticamente la larghezza. Nello snippet sopra, forniamo sia il numero di colonne che il valore rowHeight .

Stiamo utilizzando un'immagine segnaposto quando la cronologia è vuota, scaricala e aggiungila alla cartella delle risorse.

Per implementare la logica per popolare tutte queste informazioni, apri il file history.component.ts e aggiungi lo snippet seguente nella classe HistoryComponent :

 showBackButton = true; title = 'History'; showHistoryNav = false; historyList; constructor(private storageService: StorageutilService, private snackbar: MatSnackBar ) { } ngOnInit() { this.populateHistory(); } private populateHistory() { this.historyList = this.storageService.readAllHistory(); } delete(text: string) { this.storageService.deleteHistory(text); this.populateHistory(); } share(text: string) { this.snackbar.open(text, '', {duration: 2000,}) }

La logica di cui sopra recupera tutto il QR salvato e popola la pagina con esso. Gli utenti possono eliminare il QR salvato che cancellerà la voce dalla memoria locale.

Quindi questo finisce la nostra componente storica... o no? Dobbiamo ancora aggiungere la mappatura del percorso per questo componente. Apri app-routing.module.ts e aggiungi anche una mappatura per la pagina della cronologia:

 { path: 'history', component: HistoryComponent },

L'intero array di route dovrebbe ora assomigliare a questo:

 const routes: Routes = [ { path: '', component: HomeComponent }, { path: 'create', component: CreateQrComponent }, { path: 'history', component: HistoryComponent }, ];

Ora è un buon momento per eseguire l'applicazione per controllare il flusso completo, quindi apri il terminale e digita ng serve e premi Invio. Quindi, vai su localhost:4200 per verificare il funzionamento dell'applicazione.

Aggiungi a GitHub

Prima di procedere alla fase di distribuzione, sarebbe opportuno aggiungere il progetto a un repository GitHub.

  1. Apri GitHub.
  2. Crea un nuovo repository.
  3. GitHub nuovo repository (anteprima grande)
  4. In VS Code, usa il terminale e segui la prima serie di comandi menzionati nella guida di avvio rapido per eseguire il push di tutti i file di progetto.
  5. Aggiunta di un progetto in GitHub (anteprima grande)

Basta aggiornare la pagina per verificare se tutti i file sono visibili. Da questo momento in poi, qualsiasi modifica a git (come commit, pull/push) si rifletterà in questo repository appena creato.

Netlify e distribuzione

La nostra applicazione viene eseguita nella nostra macchina locale, ma per consentire ad altri di accedervi, dovremmo distribuirla su una piattaforma cloud e registrarla su un nome di dominio. È qui che entra in gioco Netlify. Fornisce servizi di distribuzione continua, integrazione con GitHub e molte altre funzionalità da cui trarre vantaggio. In questo momento, vogliamo consentire l'accesso globale alla nostra applicazione. Iniziamo.

  1. Iscriviti su Netlify.
  2. Dalla dashboard, fai clic sul pulsante Nuovo sito da Git .
  3. Netlify nuovo sito (Anteprima grande)
  4. Fai clic su GitHub nella schermata successiva.
  5. Netlify seleziona il provider git (Anteprima grande)
  6. Autorizza Netlify ad accedere ai tuoi repository GitHub.
  7. Autorizzazione Netlify GitHub (Anteprima grande)
  8. Cerca e seleziona il repository qr appena creato.
  9. Selezione del repository GitHub di Netlify (Anteprima grande)
  10. Netlify, nel passaggio successivo, ci consente di scegliere il ramo del repository GitHub per le implementazioni. Normalmente si usa il ramo master , ma si può anche avere un ramo di release separato che contiene solo funzionalità relative al rilascio e stabili.
  11. Netlify build and deploy (Anteprima grande)

Poiché si tratta di un'applicazione Web angolare, aggiungi ng build --prod come comando build. Le directory pubblicate saranno dist/qr come indicato nel file angular.json .

Percorso di costruzione angolare (anteprima grande)

Ora fai clic sul pulsante Deploy site che attiverà una build del progetto con il comando ng build --prod e genererà il file in dist/qr .

Poiché abbiamo fornito le informazioni sul percorso a Netlify, raccoglierà automaticamente i file corretti per la manutenzione dell'applicazione web. Netlify aggiunge un dominio casuale alla nostra applicazione per impostazione predefinita.

Sito Netlify distribuito (anteprima grande)

È ora possibile fare clic sul collegamento fornito nella pagina precedente per accedere all'applicazione da qualsiasi luogo. Infine, l'applicazione è stata distribuita.

Dominio personalizzato

Nell'immagine sopra, viene mostrato l'URL della nostra applicazione mentre il sottodominio viene generato casualmente. Cambiamo quello.

Fai clic sul pulsante Domain settings quindi nella sezione Domini personalizzati fai clic sul menu a 3 punti e seleziona Edit site name .

Dominio personalizzato (anteprima grande)

Si aprirà un popup in cui è possibile inserire un nuovo nome del sito; questo nome dovrebbe essere univoco in tutto il dominio Netlify. Immettere qualsiasi nome di sito disponibile e fare clic su Salva .

Nome del sito (anteprima grande)

Ora il link alla nostra applicazione verrà aggiornato con il nuovo nome del sito.

Prova divisa

Un'altra caratteristica interessante offerta da Netlify è lo split testing. Consente la suddivisione del traffico in modo che diversi insiemi di utenti interagiscano con diverse distribuzioni di applicazioni. È possibile aggiungere nuove funzionalità a un ramo diverso e suddividere il traffico verso questa distribuzione di ramo, analizzare il traffico e quindi unire il ramo di funzionalità con il ramo di distribuzione principale. configuriamolo.

Il prerequisito per abilitare il test diviso è un repository GitHub con almeno due rami. Vai al repository dell'app in GitHub che è stato creato in precedenza e crea un nuovo ramo a .

Crea nuovo ramo (Anteprima grande)

Il repository avrà ora un ramo master e a ramo. Netlify deve essere configurato per eseguire distribuzioni in filiale, quindi apri la dashboard di Netlify e fai clic su Settings . Sul lato sinistro, fai clic su Build & Deploy , quindi Continuous Deployment , quindi sul lato destro nella sezione Deploy contexts , fai clic su Edit settings .

Distribuzioni di filiali (anteprima grande)

Nella sottosezione Branch deploys , seleziona l'opzione "Fammi aggiungere singole branch", inserisci i nomi delle branch e salvalo.

La distribuzione di brances è un'altra utile funzionalità fornita da Netlify; possiamo selezionare quali rami del repository GitHub distribuire e possiamo anche abilitare le anteprime per ogni richiesta pull al ramo master prima dell'unione. Questa è un'ottima funzionalità che consente agli sviluppatori di testare effettivamente le modifiche in tempo reale prima di aggiungere le modifiche al codice al ramo di distribuzione principale.

Ora, fai clic sull'opzione della scheda Split Testing nella parte superiore della pagina. Le configurazioni di test divisi verranno presentate qui.

Test diviso (anteprima grande)

Possiamo selezionare il ramo (diverso dal ramo di produzione) — in questo caso a . Possiamo anche giocare con le impostazioni di suddivisione del traffico. In base alla percentuale di traffico assegnata a ciascun ramo, Netlify reindirizzerà alcuni utenti all'applicazione distribuita utilizzando a ramo e altri al ramo master . Dopo la configurazione, fare clic sul pulsante Start test per abilitare la suddivisione del traffico.

SUGGERIMENTO : Netlify potrebbe non riconoscere che il repository GitHub connesso ha più di un ramo e potrebbe dare questo errore:

Errore di test diviso (anteprima grande)

Per risolvere questo problema, riconnettiti al repository dalle opzioni Build & Deploy .

Netlify offre anche molte altre funzionalità. Abbiamo appena esaminato alcune delle sue utili funzionalità per dimostrare la facilità di configurazione di diversi aspetti di Netlify.

Questo ci porta alla fine del nostro viaggio. Abbiamo creato con successo un design Angular Material basato su un'applicazione web e lo abbiamo distribuito su Netlify.

Conclusione

Angular è un ottimo e popolare framework per lo sviluppo di applicazioni web. Con la libreria ufficiale di progettazione dei materiali Angular, è molto più facile creare applicazioni che aderiscono alle specifiche di progettazione dei materiali per un'interazione molto naturale con gli utenti. Inoltre, l'applicazione sviluppata con un ottimo framework dovrebbe utilizzare un'ottima piattaforma per la distribuzione e Netlify è proprio questo. Con una costante evoluzione, un ottimo supporto e con una miriade di funzionalità, è sicuramente un'ottima piattaforma per portare applicazioni Web o siti statici alle masse. Si spera che questo articolo fornisca aiuto per iniziare con un nuovo progetto Angular dal solo pensiero alla distribuzione.

Ulteriori letture

  • Architettura angolare
  • Componenti di materiale più angolari
  • Maggiori informazioni sulle funzionalità di Netlify