Yesterday, creating a document scanning program I was very surprised why angular does not update the view.
import { Component } from '@angular/core';
import { Observable, BehaviorSubject } from 'rxjs';
import { DocumentScanner, IDocumentScannerDevice } from 'document-scanner';
@Component({
selector: 'app-root',
template: `
<ul *ngIf="devices$ | async as devices">
<li *ngFor="let device of devices">{{ device | json }}</li>
</ul>
`
})
export class AppComponent {
devicesBehaviorSubject: BehaviorSubject<IDocumentScannerDevice[]> = new BehaviorSubject([]);
devices$: Observable<IDocumentScannerDevice[]>;
scanner: DocumentScanner;
constructor() {
this.devices$ = this.devicesBehaviorSubject.asObservable();
this.scanner = new DocumentScanner();
this.scanner.on('scannerDevices', (devices) => {
console.log('scannerDevices', devices);
this.devicesBehaviorSubject.next(devices);
});
}
scan() {
this.scanner.scan();
}
}
devicesBehaviorSubject
is updated correctly but unfortunately nothing appeared on the screen. :(
After several unsuccessful attempts, it turned out that angular does not see events from node.js EventEmitter
. The simplest solution to this problem is to add ngZone.run inside on
handler this.scanner.on('scannerDevices', (devices) => {...})
Working example:
import { Component, NgZone } from '@angular/core';
import { Observable, BehaviorSubject } from 'rxjs';
import { DocumentScanner, IDocumentScannerDevice } from 'document-scanner';
@Component({
selector: 'app-root',
template: `
<ul *ngIf="devices$ | async as devices">
<li *ngFor="let device of devices">{{ device | json }}</li>
</ul>
`
})
export class AppComponent {
devicesBehaviorSubject: BehaviorSubject<IDocumentScannerDevice[]> = new BehaviorSubject([]);
devices$: Observable<IDocumentScannerDevice[]>;
scanner: DocumentScanner;
constructor(private ngZone: NgZone) {
this.devices$ = this.devicesBehaviorSubject.asObservable();
this.scanner = new DocumentScanner();
this.scanner.on('scannerDevices', (devices) => {
console.log('scannerDevices', devices);
this.ngZone.run(() => {
this.devicesBehaviorSubject.next(devices);
});
});
}
scan() {
this.scanner.scan();
}
}
Now angular gets information about the new scannerDevices
event.