Nel Rispondi alle modifiche DOM con gli osservatori di mutazione articolo, abbiamo appreso Osservatori di mutazioni DOM, che ha sostituito il goffo Eventi di mutazione DOM. Sia gli eventi di mutazione che gli osservatori di mutazione sono stati progettati per informare lo script delle modifiche alla struttura del DOM. Questi includono:
- l’aggiunta o la rimozione di elementi
- modifiche agli attributi di un elemento
- modifiche ai dati del personaggio (ovvero, modifiche a un nodo di testo)
Osservando l’elenco sopra, diventa subito evidente che Mutation Observers può anche aiutare gli sviluppatori Angular a rispondere a eventi DOM che altrimenti rimarrebbero sfuggenti. In questo tutorial, vedremo quanto è facile sfruttare la potenza del Osservatore di mutazioni API Web per ricevere aggiornamenti ogni volta che gli elementi figlio di un componente cambiano.
Presentazione dell’app Console di gestione del catalogo dei single
Ecco un’app Angular per gestire la copertina di un catalogo di singoli di musica digitale:
È un’app molto semplice che ci consente di aggiungere e rimuovere elementi da un elenco non ordinato. Non sorprende che non sia necessario molto markup HTML per farlo funzionare:
<h1>Singles Catalog</h1> <ul> <li *ngFor="let artwork of singlesArtwork"> <img [src]="artwork" /><button (click)="removeArtwork(artwork)">Remove</button> </li> </ul> <button *ngIf="showAddButton; else showMessage" (click)="addArtwork()">Add Next Single</button> <ng-template #showMessage>No more singles to add.</ng-template>
Leggi: Dichiara e rispondi a un evento Dom Element Ready
Creazione di un AppService in Angular
Le immagini sono fornite da un servizio tramite il pubblico fetchSinglesArtwork() metodo. Rimuove gli elementi dall’inizio dell’elenco e li emette come RxJS Observable. Un ritardo di 500 millisecondi viene aggiunto per emulare una chiamata di rete che verrebbe utilizzata per recuperare gli URL delle immagini da un archivio dati esterno. Ha anche un metodo per rimuovere le immagini che sostituisce gli elementi precedentemente rimossi:
import { Injectable } from '@angular/core'; import * as Rx from 'rxjs/Rx'; const ROOT = 'https://i1.sndcdn.com/artworks-'; @Injectable() export class AppService { private singlesArtwork = [ ROOT + 'nOmzKy8phBjdHggR-B4aC8Q- t200x200.jpg', ROOT + 'b5jyk6LpdxWVWWz5-jGpxXw- t200x200.jpg', ROOT + 'OCRwxXbSBQwex4mM-LY2qWg- t200x200.jpg', ROOT + '2n1JKCcFA6Gg6UH7-GsP3HA- t200x200.jpg', ROOT + 'NXjocVbpYjLOCwSx-9VELtA- t200x200.jpg' ]; public fetchSinglesArtwork(howMany: number = 1): Rx.Observable<string[]> { return Rx.Observable .of(this.singlesArtwork. splice(0, howMany)) .delay(500); } public removeSinglesArtwork(artwork: string): void { this.singlesArtwork.push( artwork); } }
Recupero dell’elenco iniziale
All’avvio, la nostra app mostra le prime tre immagini. Per prenderli, il AppComponent inietta il nostro servizio nel costruttore e lo invoca fetchSinglesArtwork() metodo. Nella funzione di richiamata dell’abbonamento, gli URL delle singole opere d’arte sono archiviati nel pubblico singleArtwork variabile a cui si fa riferimento dal modello. È un Set piuttosto che un normale array in modo da poter garantire che l’elenco non contenga mai duplicati. Naturalmente, se il servizio è codificato correttamente, ciò non dovrebbe mai accadere.
@Component({ selector: 'my-app', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { private singlesArtwork: Set<string>; public showAddButton = true; constructor(private appService: AppService) { appService.fetchSinglesArtwork(3) .subscribe(singlesArtwork => this.singlesArtwork = new Set<string>(singlesArtwork)); } // more code... }
Leggi: RXJS Observables Primer in angolare
Aggiunta di un elemento all’elenco
Facendo clic su Aggiungi prossimo singolo il pulsante richiama il addArtwork() metodo, che a sua volta chiama fetchSinglesArtwork(). Nel addArtwork() funzione di callback dell’abbonamento, l’artwork viene aggiunto fintanto che sono rimasti elementi nell’array; in caso contrario, il Aggiungere il pulsante è sostituito da un messaggio che indica che non ci sono più singoli da aggiungere:
public addArtwork(): void { this.appService .fetchSinglesArtwork() .subscribe(singlesArtwork => { if (singlesArtwork.length > 0) { this.singlesArtwork = this.singlesArtwork.add(singlesArtwork[0]); } else { this.showAddButton = false; } }); }
Rimozione di un elemento dall’elenco
Accanto a ogni immagine, c’è un pulsante per rimuoverla dall’elenco che richiama il metodo removeArtwork(). A sua volta, chiama il metodo removeSinglesArtwork() del servizio, passando l’URL dell’immagine in modo che i dati mancanti possano essere sostituiti nel singleArtwork Vettore:
public removeArtwork(artwork: string): void { this.singlesArtwork.delete(artwork); this.appService. removeSinglesArtwork(artwork); this.showAddButton = true; }
La Direttiva DomChange in Angular
Nelle applicazioni angolari, il Osservatore di mutazioni L’API è probabilmente implementata al meglio come direttiva. Il ElementoRif viene inserito come parametro del costruttore in modo che possiamo accedere direttamente all’elemento del nodo. Quindi ogni modifica DOM emette un evento personalizzato che passa la modifica stessa come argomento:
import { Directive, ElementRef, EventEmitter, OnDestroy, Output } from '@angular/core'; @Directive({ selector: '[domChange]' }) export class DomChangeDirective implements OnDestroy { private changes: MutationObserver; @Output() public domChange = new EventEmitter(); constructor(private elementRef: ElementRef) { const element = this.elementRef.nativeElement; this.changes = new MutationObserver((mutations: MutationRecord[]) => { mutations.forEach((mutation: MutationRecord) => this.domChange.emit(mutation)); } ); this.changes.observe(element, { attributes: true, childList: true, characterData: true }); } ngOnDestroy(): void { this.changes.disconnect(); } }
Possiamo ora vincolare la direttiva al onDomChange() gestore nel modello come segue:
<ul (domChange)="onDomChange($event)">
In questo caso, il $ evento sarà un ElementoRif al
- elemento.
- elementi e invia il primo alla console:
public onDomChange(mutationRecord: MutationRecord): void { const addedNodes = mutationRecord.addedNodes; const removedNodes = mutationRecord.removedNodes; if ( addedNodes.length > 0 && (addedNodes.item(0) as HTMLElement).tagName === 'LI') { console.log('Added nodes: ', addedNodes.item(0)); } else if (removedNodes.length > 0 && (removedNodes.item(0) as HTMLElement).tagName === 'LI') { console.log('Removed nodes: ', removedNodes.item(0)); } }
Si noti che entrambi i nodi aggiunti e nodi rimossi gli elementi sono Nodo oggetti in TypeScript, quindi dobbiamo lanciarli come an Elemento HTML per accedere ai suoi attributi e metodi. Possiamo vedere alcuni esempi di output qui:
Troverai l’applicazione Catalogo Singles su stackblitz.
Conclusione
Grazie al Osservatore di mutazioni API Web, possiamo fare cose nelle nostre app Angular che altrimenti sarebbero molto difficili. Fai solo attenzione a rispettare la gerarchia dei componenti ed evita di ascoltare i cambiamenti all’interno di altri componenti. Ad esempio, se devi rispondere alle modifiche DOM all’interno di un componente figlio, aggiungi la direttiva al suo modello e quindi passa i dati necessari al genitore tramite un Emettitore di eventi.
In AppComponent onDomChange() gestore, possiamo rispondere alle modifiche DOM in qualsiasi modo desideriamo. A scopo dimostrativo, cercheremo solo l’aggiunta e la rimozione di