Enum sono stati a lungo una caratteristica del linguaggio Java, ma sono stati aggiunti a TypeScript solo negli ultimi anni. È interessante notare che le enumerazioni sono una delle poche funzionalità di TypeScript che non è un’estensione a livello di tipo di JavaScript. Il loro scopo è definire un insieme di costanti denominate, semplificando la documentazione dell’intento e creando un insieme di casi distinti. Le enumerazioni TypeScript sono disponibili in due versioni: numerico e basato su stringhe. Questo articolo riguarda specificamente quest’ultimo; impareremo come utilizzare le enumerazioni di stringhe nelle nostre applicazioni Angular mentre eliminiamo alcuni dei loro trucchi più diffusi.
Esempio di enumerazioni dattiloscritte
Come insieme di costanti denominate, ogni membro di una stringa enum deve essere inizializzato con una stringa letterale o con un altro membro di stringa enum. Ecco l’enumerazione che useremo per impostare un menu a discesa delle scelte della lingua in un’applicazione Angular:
export enum SupportedLanguages { en = 'English', fr="français", es="Español" }
Per fare riferimento ai valori enum, li tratteremmo come attributi dell’oggetto e li accediamo usando il punto (.) notazione:
console.log(SupportedLanguages.en); // 'English' console.log( SupportedLanguages.fr); // 'français', console.log( SupportedLanguages.es); // 'Español'
Leggi: Scelta tra valori letterali di stringa TypeScript ed enumerazioni
Iterazione su una stringa enum in TypeScript
Osservando la struttura dell’enumerazione, dovrebbe essere evidente che le voci consistono in a chiave/valore combinazione. Ti aspetteresti che una tale configurazione sia l’ideale per popolare un menu a discesa. In verità, le enumerazioni di stringhe non sono facilmente ripetute come Matrici, che supportano lo standard per il ciclo. La struttura di un enum assomiglia più da vicino a quella di una mappa, quindi richiedono un approccio simile. In entrambi i casi, dobbiamo estrarre le chiavi dell’oggetto e scorrere su quelle. Questo perché l’enumerazione TypeScript viene transpilata in un oggetto JS vaniglia:
Object { en: "English", fr: "français", es: "Español" } en: "English" es: "Español" fr: "français"
Pertanto, tutto ciò che dobbiamo fare per recuperare le chiavi di un enum è passarlo allo statico Chiavi.oggetto() metodo. Possiamo quindi fare riferimento alle chiavi usando un getter pubblico:
private _supportedLanguages = Object.keys(SupportedLanguages); public get supportedLanguages(): Array<string> { return this._supportedLanguages; }
Ora possiamo usare un ciclo for…of per popolare il nostro menu a discesa. I valori enum sono accessibili utilizzando l’array associativo JS oggetto[key] sintassi:
<mat-form-field> <mat-label>{{ languageLabel }}</mat-label> <mat-select [(ngModel)]="selectedLanguage" (ngModelChange)="onSelectedLanguageChange($ event)" > <mat-option *ngFor="let language of supportedLanguages" [value]="language" >{{ languages[language] }} </mat-option> </mat-select> </mat-form-field>
Leggi: Divertirsi con JavaScript For Loop
Rispondere alle selezioni a discesa
Naturalmente, inserire i dati enum nelle opzioni è solo metà della battaglia. Dobbiamo ancora farci qualcosa. Quindi, usiamo i tasti enum per impostare la lingua della pagina. Questo è un approccio fai-da-te che ben si adatta alle semplici applicazioni a pagina singola (SPA). Per qualcosa di più elaborato, consiglierei di utilizzare il built-in di Angular Quadro di internazionalizzazione.
Il onSelectedLanguageChange() il metodo accetta il tipo enum perché, sebbene Chiavi.oggetto() converte le chiavi in stringhe, sappiamo che solo le chiavi enum valide verranno mai passate al metodo. La chiave viene convertita in un parametro di query e passata al router navigare() metodo per ricaricare la pagina con il parametro language:
public onSelectedLanguageChange( language: SupportedLanguages ) { const queryParams: Params = { lang: language }; this.router.navigate([], { relativeTo: this.activatedRoute, queryParams: queryParams }); }
Potremmo semplicemente aggiornare la lingua in atto, ma l’impostazione di un parametro di query consente alla pagina di mantenere la lingua corrente anche durante gli aggiornamenti della pagina.
Impostazione della lingua corrente
La prima volta che la pagina viene caricata, ci iscriviamo a ActivatedRoute queryParams Osservabile. Nei successivi caricamenti attivati dal menu a discesa, emetterà il nuovo parametro di query, rendendolo il luogo perfetto per aggiornare le etichette delle pagine, i titoli e qualsiasi altro contenuto:
public languages = SupportedLanguages; public selectedLanguage: string; public languageLabel: string; public title: string; private _supportedLanguages = Object.keys(SupportedLanguages); constructor( private router: Router, private activatedRoute: ActivatedRoute, private translationService: TranslationService ) {} ngOnInit(): void { this.activatedRoute. queryParams.subscribe( queryParams => { this.selectedLanguage = queryParams['lang'] || this.supportedLanguages[0]; this.title = this.getTranslation('title'); this.languageLabel = this.getTranslation('language' ); }); }
Recupero delle traduzioni
L’AppComponent getTranslation() Il metodo delega semplicemente il recupero della traduzione a un servizio, passando il file Lingua selezionata. Il servizio non sa quale sia la lingua corrente, e questo è in base alla progettazione. L’AppComponent deve mantenere il Lingua selezionata perché è legato alla lingua SELEZIONA modello. È meglio evitare che sia il componente che il servizio mantengano la lingua corrente perché tale configurazione è soggetta a problemi di sincronizzazione. Forse hai familiarità con il concetto di Single Source of Truth (SSOT). È la pratica di strutturare i modelli in modo tale che ogni elemento di dati sia mantenuto in un solo posto. Pertanto, dovremmo rendere pubblico il servizio stesso o passare i dati ad esso, come ho fatto qui:
private getTranslation(key: string) { return this.translationService .getTranslation( key, <SupportedLanguages>this.selectedLanguage ); }
Il Servizio di traduzione tuttavia memorizza le traduzioni stesse. Qui stiamo usando le mappe nidificate in cui si accede alle voci della mappa esterna tramite le chiavi enum mentre quelle interne contengono le chiavi per tutte le stringhe in quella lingua:
import { Injectable } from '@angular/core'; export enum SupportedLanguages { en = 'English', fr="français", es="Español" } @Injectable() export class TranslationService { private readonly translations = new Map<string, Map<string, string>>([ ['en', new Map<string, string>([ ["language", "Language"], ["title", "Convert Map Enum to Array Demo"] ])], ['fr', new Map<string, string>([ ["language", "Langue"], ["title", "Démo Convertir Enum en Array"] ])], ['es', new Map<string, string>([ ["language", "Idioma"], ["title", "Demostración Para Convertir Enum a Array"] ])] ]); public getTranslation( key: string, language: SupportedLanguages = SupportedLanguages.en ) { return this.translations.get(language).get(key); } }
Puoi vedere il risultato dell’impostazione della lingua sul francese qui:
È disponibile una demo dell’app della lingua stackblitz.
Conclusione
Ogni volta che è necessario definire un insieme di costanti con nome in TypeScript o Angular, considerare l’utilizzo di un Enum. Funzionano molto bene una volta che ti abitui alla loro modesta serie di idiosincrasie.