Just I tried my first app with Angular2 RC3 (Using Angular-CLI) and I'm lost with this...
I have a problem with "Change detection" of variable word
. I update the word
variable inside the subscribe
method of Observable, but no changes detected.
app.component.ts
import { Component, Inject, OnInit } from '@angular/core';
import { VoiceRecognitionService } from './voice-recognition.service';
@Component({
moduleId: module.id,
selector: 'app-root',
template: `<h1>{{word}}</h1>`, // => No prints any update
providers: [VoiceRecognitionService],
styleUrls: ['app.component.css']
})
export class AppComponent implements OnInit {
private voice: VoiceRecognitionService;
public word: string = '';
constructor( @Inject(VoiceRecognitionService) voiceRecognition: VoiceRecognitionService) {
this.voice = voiceRecognition;
}
ngOnInit() {
this.voice.record('ca')
.subscribe(word => {
console.log(word); // => Is printing well the new word
this.word = `${word}...`; // => No changes detected
});
}
}
I remember in Angular 1 the use of $scope.$apply
for similar cases and I search the same for Angular2 and I found NgZone.run
, I tried to execute inside NgZone.run
, but nothing.
What I'm doing wrong?
Thank you so much.
I share my service with the Observable:
voice-recognition.service.ts
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Rx';
export interface IWindow extends Window {
webkitSpeechRecognition: any;
}
@Injectable()
export class VoiceRecognitionService {
constructor() {
/* void */
}
/**
* Record
* @param {string} language - Language of the voice recognition
* @returns {Observable<string>} - Observable of voice converted to string
*/
record(language: string): Observable<string> {
return Observable.create((observer) => {
const { webkitSpeechRecognition }: IWindow = <IWindow>window;
const recognition = new webkitSpeechRecognition();
recognition.onresult = (e) => observer.next(e.results.item(e.results.length - 1).item(0).transcript);
recognition.onerror = observer.error;
recognition.onend = observer.completed;
recognition.continuous = true;
recognition.interimResults = true;
recognition.lang = language;
recognition.start();
});
}
}
I assume the webkitSpeechRecognition
API is not patched by Angulars zone.
To work around use zone.run(...)
to force the execution back into Angulars zone explicitely:
@Injectable()
export class VoiceRecognitionService {
constructor(private zone:NgZone) {
/* void */
}
/**
* Record
* @param {string} language - Language of the voice recognition
* @returns {Observable<string>} - Observable of voice converted to string
*/
record(language: string): Observable<string> {
return Observable.create((observer) => {
const { webkitSpeechRecognition }: IWindow = <IWindow>window;
const recognition = new webkitSpeechRecognition();
recognition.onresult = (e) => this.zone.run(() => observer.next(e.results.item(e.results.length - 1).item(0).transcript));
recognition.onerror = (e) => this.zone.run(() => observer.error(e));
recognition.onend = (e) => this.zone.run(() => observer.completed(e));
recognition.continuous = true;
recognition.interimResults = true;
recognition.lang = language;
recognition.start();
});
}
}
If the callbacks need a different number of parameters ((e)
) please adjust the code accordingly. I just assumed one parameter for each.
The advantage of this approach is that the users of this service don't have to take additional measures.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With