Giugno 2018

Volume 33 Numero 6

Il presente articolo è stato tradotto automaticamente.

The Working Programmer - Come usare MEAN: Programmazione reattiva

Dal Ted Neward | 2018 giugno

Bentornato nuovamente, MEANers.

Nei due articoli precedenti (msdn.com/magazine/mt829391 e msdn.com/magazine/mt814413), è possibile parlato molteplici funzionalità si riferisce al angolare come "basate sul modello di form", che sono moduli descritto dai modelli Angular estesi e tramite l'utilizzo di codice per la convalida del controllo e altri tipi di logica. Ovvero ed efficace, ma un nuovo concetto su come visualizzare il flusso"" di informazioni, e si è verificato il controllo risultante nel codice, all'interno di un sito Web dell'applicazione sta avviando la requisizione imaginations degli sviluppatori.

Parlo, naturalmente, "reattivo" programmazione e uno per il turno ottimo tra AngularJS (vale a dire, Angular 1.0) e angolare (Angular 2.0 e versioni successive) è che angolare ora con supporto esplicito per uno stile reattivo della programmazione, almeno a livello di angolare. Tutto ciò di cui è ad esempio, angolare supporta l'utilizzo di reattivi stili di programmazione all'interno di angolare senza dover eseguire il commit a uno stile completamente reattivo dell'architettura di fuori di angolare.

Prima di passare ad, tuttavia, è utile per assicurarsi che tutti gli utenti bordo con cosa significa "reattivo" di seguito.

Effetti collaterali reattivi

Fondamentalmente, reattivi stili di programmazione sono facili da comprendere, purché si è disposti a completamente invertire il punto di vista della modalità tradizionali di programmazione dell'interfaccia utente di eseguire. (Sì, ovvero un battuta. Ma solo un piccolo).

Nell'approccio basata su MVC tradizionali per la creazione di interfacce utente, vengono creati gli elementi dell'interfaccia utente (pulsanti, i campi di testo e così via), quindi... Attendere. Il sistema elabora i messaggi dall'hardware e una combinazione di messaggi indica che l'utente ha eseguito delle operazioni, ovvero un pulsante, digitati in una casella di testo o qualsiasi altro, ovvero il codice associato per l'attivazione di controlli. Tale codice vengono modificati in genere il modello che si trova dietro l'interfaccia utente e l'applicazione torna in attesa.

Questo stile "basata sugli eventi" della programmazione è intrinsecamente asincrono, in quanto il codice che il programmatore scrive sempre dovuto quali l'utente non. In alcuni aspetti, sarebbe preferibile chiamarlo programmazione "saranno non deterministici", perché non è possibile mai sapere ciò che l'utente eseguirà successivamente. Angolare ricercato semplificare questa operazione creando associazione bidirezionale tra il modello di dati e dell'interfaccia utente, ma può comunque essere complessa per mantenere l'ordine delle operazioni semplici.

Lo stile reattivo, tuttavia, ha un approccio più unidirezionale. I controlli vengono creati nel codice (anziché nel modello) e si effettua la sottoscrizione a livello di programmazione per eventi generati da tali controlli per rispondere all'utente di suggerimenti allo scopo. Non è abbastanza React reattiva programmazione di tipo, ma è piuttosto chiudere e consente ancora lo stesso tipo di "modello di dati non modificabili" stile di programmazione che è enamored una percentuale del settore.

Costruzione reattiva

Per iniziare, si esaminerà la costruzione del componente SpeakerUI in modo reattivo, anziché in modo basato su modelli. (In questo caso, ho impostato da utilizzare con la convenzione Angular più tradizionale e chiamarlo SpeakerDetail, ma il nome è irrilevante per la discussione). In primo luogo, per contribuire a semplificare si lavora con, si utilizzerà la forma abbreviata del relatore e SpeakerService, come illustrato figura 1.

SpeakerService e degli altoparlanti figura 1

import { Injectable } from '@angular/core';

export class Speaker {
  id = 0
  firstName = ""
  lastName = ""
  age = 0
}

@Injectable()
export class SpeakerService {
  private speakers : Speaker[] = [
    {
      id: 1,
      firstName: 'Brian',
      lastName: 'Randell',
      age: 47,
    },
    {
      id: 2,
      firstName: 'Ted',
      lastName: 'Neward',
      age: 46,
    },
    {
      id: 3,
      firstName: 'Rachel',
      lastName: 'Appel',
      age: 39,
    }
  ]
    getSpeakers() : Promise<Array<Speaker>> {
    return Promise.resolve(this.speakers);
  }
  getSpeaker(id: number) : Promise<Speaker> {
    return Promise.resolve(this.speakers[id - 1 ]);
  }
}

Si noti che il SpeakerService utilizza il metodo Promise. Resolve per restituire una promessa che può essere risolto immediatamente. Si tratta di un modo semplice per simulare il servizio senza dover compilare un oggetto Promise nel modo più usando il costruttore Promise.

Successivamente, il componente SpeakerDetail è semplicemente un componente standard di angolare ("ng nuovo componente altoparlante-dettagli") e il costruttore deve inserire un'istanza SpeakerService come parametro costruttore privato. (Questa è stata descritta in dettaglio nella colonna my agosto 2017, "come essere medio: Riproduce Angular Fetch"[msdn.com/magazine/mt826349].) Mentre si scrive, utilizzare il costruttore chiamare getSpeakers metodo del SpeakerService per ottenere nuovamente la matrice e archiviare che localmente nel componente come una proprietà denominata "altoparlanti." Finora, questo sembra molto il componente basato sul modello descritto in precedenza. Il modello HTML per questo componente verrà visualizzato un elenco a discesa di tutti gli altoparlanti nel sistema (come ottenuto getSpeakers) e quindi come ognuno è selezionata, visualizzare i dettagli in un altro set di controlli di sotto di tale elenco a discesa. Di conseguenza, il modello è simile a figura 2.

Figura 2 modello di HTML

<h2>Select Speaker</h2>
<form [formGroup]="selectGroup">
<label>Speaker:
  <select formControlName="selectSpeaker">
    <option *ngFor="let speaker of speakers"
            [value]="speaker.lastName">{{speaker.lastName}}</option>
  </select>
</label>
</form>

<h2>Speaker Detail</h2>
<form [formGroup]="speakerForm" novalidate>
  <div>
    <label>First Name:
      <input formControlName="firstName">
    </label>
    <label>Last Name:
      <input formControlName="lastName">
    </label>
    <label>Age:
      <input formControlName="age">
    </label>
  </div>
</form>

Può sembrare strano che l'alternativa a un "basate su modello" Form utilizza modelli HTML. Che è in gran parte perché l'approccio reattivo form non serve a immediatamente con il modello, ma invece rimuove la maggior parte della logica di allontanarlo dal modello e nel componente. Si tratta in cui le cose iniziano a turno sinistro dalle tecniche esaminati nella precedente coppia di colonne. Il componente verrà effettivamente costrutto di codice un albero degli oggetti di controllo e la maggior parte delle (se non tutte) l'interazione con i controlli in questi due formati verrà eseguito interamente all'interno della base di codice. È possibile non inserire i gestori eventi nel modello. Al contrario, sarà unirle all'interno del codice di componente.

Tuttavia, è necessario prima costruire i controlli stessi. Queste saranno tutte istanze FormControl, importate dal modulo @angular/forms, ma è possibile ottenere un po' difficile da crearle ognuno (insieme a eventuali convalide necessarie) manualmente nel codice. Fortunatamente, angolare fornisce una classe FormBuilder che è progettato per semplificare un po' più conciso e compatta per costruire relativi a un intero modulo di controlli, in particolare per i moduli più lunghi (o nidificati).

Nel caso del modulo del relatore, in cui si desidera avere un elenco a discesa servono come meccanismo di selezione per scegliere quali altoparlante nell'elenco per lavorare, è necessario eseguire operazioni qualcosa di diverso. Desidero hanno due formati: uno per il controllo del relatore selezione a discesa e l'altro contenente i dettagli per ogni utente. (In genere si tratterà di due componenti separati in un tipo master-dettagli dell'accordo, ma non ho ancora routing). Di conseguenza, sono necessarie due forme e nella figura 3 illustrato come creare, con la FormBuilder e senza.

Figura 3 costruzione di form

export class SpeakerDetailComponent implements OnInit {
  selectGroup : FormGroup
  speakerForm : FormGroup
  speakers : Speaker[]

  constructor(private formBuilder : FormBuilder,
              private speakerService : SpeakerService) {
    speakerService.getSpeakers().then( (res) => { this.speakers = res; });
    this.createForm();
  }

  createForm() {
    this.selectGroup = new FormGroup({
      selectSpeaker : new FormControl()
    });

    this.speakerForm = this.formBuilder.group({
      firstName: ['', Validators.required],
      lastName: ['', Validators.required],
      age: [0]
    });
  }
  // ...
}

Si tratta, tuttavia, solo un estratto della classe, ovvero non esiste un paio di elementi è necessario aggiungere prima che sia pronto per spedire, ma accuratamente questo codice illustra due modi per creare un modulo. "selectGroup" è FormGroup contenente uno FormControl per il controllo HTML < select >, e si usa il SpeakerService per popolare una matrice di istanze altoparlante locale in modo < select > possibile popolare se stesso. (Si tratta in realtà sul modello, non nel codice del componente. Se non esiste un modo per popolare l'elenco a discesa dal codice del componente, è possibile quest'ultimo non viene individuato, ancora Angular 5.)

La seconda forma, chiamata speakerForm, verrà popolata utilizzando FormBuilder, ovvero un linguaggio DSL simile a quello minimo piccoli per la creazione di controlli. Si noti come è possibile chiamare "group" per indicare che sta costruzione di un gruppo di controlli, ovvero le coppie nome-valore in modo efficace. Il nome è il nome del controllo (che deve corrispondere alla proprietà formControlName nel modello per ogni controllo) e il valore è un valore iniziale o un valore iniziale seguito da una matrice delle funzioni di convalida (due matrici, se si desidera includere la convalida esecuzione delle funzioni eseguite in modo asincrono) per la convalida di tipo di valore degli utenti al controllo.

Ciò crea le due forme, ma la selezione di un elemento nell'elenco a discesa non esegue alcuna operazione. È necessario rispondere all'evento, l'elenco a discesa verrà trasmesso e a tale scopo, è possibile è possibile associare una funzione al metodo "valueChanges" di FormControl, come illustrato di seguito:

export class SpeakerDetailComponent implements OnInit {
  // ...
  ngOnInit() {
    const speakerSelect = this.selectGroup.get('selectSpeaker');
    speakerSelect.valueChanges.forEach(
      (value:string) => {
        const speaker = this.speakers.find( (s) => s.lastName === value);
        this.populate(speaker);
      }
    );
  }
  // ...
}

Si noti che la proprietà valueChanges è effettivamente un flusso di eventi. Pertanto, è possibile utilizzare forEach per indicare che per ogni evento arriva, desidera accettare il valore a cui viene modificato (il parametro per l'espressione lambda) e usarla per trovare che l'altoparlante in base al cognome nella matrice restituita dal SpeakerService. È possibile quindi di rimuovere l'altoparlante istanza e passarlo al metodo popola, illustrato di seguito:

export class SpeakerDetailComponent implements OnInit {
  // ...
  populate(speaker) {
    const firstName = this.speakerForm.get('firstName');
    const lastName = this.speakerForm.get('lastName');
    const age = this.speakerForm.get('age');
    firstName.setValue(speaker.firstName);
    lastName.setValue(speaker.lastName);
    age.setValue(speaker.age);
  }
  // ...
}

Il metodo popola semplicemente acquisisce il riferimento di FormControls dal gruppo speakerForm e utilizza il metodo setValue per popolare l'appropriato valore compreso tra l'altoparlante e il controllo appropriato.

Analisi reattivo

Porre una domanda equo a questo punto è come questo è migliore del form basati su modello illustrato in precedenza. Onestamente, non è una questione di rapporto migliore, è una questione di rapporto diverso. (I documenti Angular anche sostengono questo definitive nella pagina della documentazione ufficiale su form reattivo in angular.io/guide/reactive-forms.) Acquisizione la maggior parte della logica nel codice del componente (invece che nel modello) possono raggiungere alcuni sviluppatori come più logico o coesiva, ma anche i form reattivo presentano il vantaggio che sono essenzialmente un reattivo "ciclo": Poiché i controlli non eseguito il mapping diretto per l'oggetto modello sottostante. Lo sviluppatore mantiene il controllo completo su ciò che accade quando, che consente di semplificare numerosi scenari estremamente.

Il team Angular non ritiene che un approccio a un form è intrinsecamente migliore rispetto all'altro, in realtà esplicitamente che entrambi gli stili possano essere utilizzati all'interno della stessa applicazione. (Si non tenta di utilizzare sia all'interno del componente stesso, tuttavia, se non si comprensione angolare effettivamente eccessivamente.) La chiave qui è che angolare supporta due diversi stili di raccogliere l'input dell'utente e sono entrambi valido e affidabile per un numero sufficiente di scenari. Ma cosa accade se si dispone di un numero elevato di forme che devono essere visualizzati o il modulo che deve essere visualizzata dipende l'oggetto modello sottostante, che può cambiare? Offerte Angular ancora un'altra opzione, verrà visualizzato nella colonna successiva. Buona codifica!


Ted Neward è un consulente polytechnology basate su Seattle, altoparlante e mentor, lavorando come direttore del reparto tecnico e applicazioni l'IM per sviluppatori in Smartsheet.com. Egli ha scritto una considerevole quantità di articoli, creati o libri una dozzina e si parla in tutto il mondo. È possibile contattarlo in ted@tedneward.com o leggere il suo blog all'indirizzo blogs.tedneward.com.