Search code examples
javascriptangularjsgetusermedia

How can I update angular bindings with data from a getUserMedia stream?


I'm using getUserMedia to get an audio stream. The audio stream is only available in the callback from getUserMedia. However, when I try to update the bindings from inside the callback, angular doesn't detect the changes and doesn't update the bindings. I've tried to use $scope.$apply as suggested by many articles, but it doesn't seem to do anything.

Here is a fiddle that shows what I've tried. http://jsfiddle.net/poptart911/a00koc8r/1/

    angular.module('test', [])
    .controller('mainController', function ($scope) {
    this.deviceStatus = "Angular works.";
    this.deviceStatus = "We can update a binding.";
    navigator.mediaDevices.getUserMedia({
        audio: true,
        video: false
    }).then(function (stream) {
        this.deviceStatus = "Angular doesn't detect this change.";
        $scope.$apply(function (stream) {
            this.deviceStatus = "I even tried scope.apply!";
            alert("But I know this code is executing");
        });
    });
});

Solution

  • $scope.$apply is working as expected. However, the scope of this refers to the scope of the inner lambda function, not the scope of the outer function where deviceStatus is first declared. As a result, the getUserMedia callback creates a new deviceStatus variable instead of altering the original variable (to which the UI is bound). Try storing a reference to the original this and use it when referencing deviceStatus in your inner lambda function:

    angular.module('test', [])
        .controller('mainController', function ($scope) {
            var that = this;
            that.deviceStatus = "Angular works.";
            that.deviceStatus = "We can update a binding.";
            navigator.mediaDevices.getUserMedia({
                audio: true,
                video: false
            }).then(function (stream) {
                that.deviceStatus = "*Now* angular detects this change.";
                $scope.$apply(function (stream) {
                    that.deviceStatus = "I even tried scope.apply!";
                    alert("But I know this code is executing");
                });
           });
    });
    

    Here's a working jsfiddle as a demonstration. The getUserMedia function has been replaced with a setTimeout since that function didn't seem to be working for me.