Ishan Khare
Ishan Khare

Reputation: 1763

Using WebSpeech API through AngularJS

I have been trying to use the WebSpeech Api through angularjs. Everything seems to work but the model doesn't get updated at once.

If I start the recognition again, the model updates. Seems like some inner loop/other construct is holding angular to see the changes.

Here is the codepen that I made.

Steps to reproduce:
1. Click start, and speak
2. After recognition detects end of speech hit start once again to start another recognition.
3. As soon as the second recognition is started, the model is updated with previous transcript.

Note: If a do console.log as below then it shows correct transcript, means the recognition part is working fine.

if(event.results[i].isFinal) {
  self.final = self.final.concat(event.results[i][0].transcript);
  console.log(event.results[i][0].transcript);
}

Upvotes: 1

Views: 2496

Answers (1)

Shankar Gurav
Shankar Gurav

Reputation: 1067

Everything seems perfect, except you forgot to call $scope.$apply(); when you modified values to get it effect on view. So it should be like this,

angular.module('speech',[]);

angular.module('speech').controller('speechController', function($scope) {
  this.rec = new webkitSpeechRecognition();
  this.interim = [];
  this.final = '';
  var self = this;

  this.rec.continuous = false;
  this.rec.lang = 'en-US';
  this.rec.interimResults = true;
  this.rec.onerror = function(event) {
    console.log('error!');
  };

  this.start = function() {
    self.rec.start();
  };

  this.rec.onresult = function(event) {
    for(var i = event.resultIndex; i < event.results.length; i++) {
      if(event.results[i].isFinal) {
        self.final = self.final.concat(event.results[i][0].transcript);
        console.log(event.results[i][0].transcript);
        $scope.$apply();

      } else {
        self.interim.push(event.results[i][0].transcript);
      }
    }
  };

});

I have updated your codepen with working solution.

AngularJs creates a "watch" internally for the all data-bindings created in view and call $scope.$digest() which inturns iterate thorugh all watches and checks if any of the watched variables have changed. When you call $scope.$apply() it internally calls $scope.$digest() so data-binding gets refreshed.

Listener directives, such as ng-click, register a listener with the DOM. When the DOM listener fires, the directive executes the associated expression and updates the view using the $apply() method.

When an external event (such as a user action, timer or XHR) is received, the associated expression must be applied to the scope through the $apply() method so that all listeners are updated correctly (ref).

So in your case view gets update when you click next start button again (ng-click) and not when recording event occurs.

Also would be usefult to read this

Upvotes: 2

Related Questions