Angular变量无法绑定到视图

3

我有一个使用Angular/Onsen开发的应用程序,其中有一张图片被放置在HTML5画布标签中,我正在通过hover来选择所在像素的颜色。

视图非常简单:

  <ons-template id="live.html">
    <ons-page ng-controller="LiveController">
      <ons-toolbar>
        <div class="left">
          <ons-toolbar-button ng-click="menu.toggle()">
            <ons-icon icon="ion-navicon" size="28px" fixed-width="false"></ons-icon>
          </ons-toolbar-button>
        </div>
        <div class="center">Live Camera</div>
      </ons-toolbar>



      <canvas id="canvas" width="100" height="100"></canvas>

      <p>#{{hex}}</p>

    </ons-page>
  </ons-template>

你可以看到,<p>标签应该显示$scope.hex的值(像素rgb通道计算出的十六进制值),但实际上并没有。尽管从我的控制器中正确地记录了该值。
这是我的控制器
  module.controller('LiveController', function($scope, $data) {

      $scope.hex = '00FFFF';
      var pictureSource;
      var destinationType;

      document.addEventListener("deviceready", onDeviceReady, true);

      function onDeviceReady() {
        console.log('onDeviceReady');
        pictureSource = navigator.camera.PictureSourceType;
        destinationType = navigator.camera.DestinationType;
        capturePhoto();

      }

      function capturePhoto() {
        console.log('capturePhoto');
        navigator.camera.getPicture(onSuccess, onFail, {
          quality: 50,
          destinationType: destinationType.DATA_URL
        });
      }

      function onSuccess(imageData) {
        console.log('onSuccess');
        var largeImage = document.getElementById('largeImage');
        largeImage.style.display = 'block';
        largeImage.src = "data:image/jpeg;base64," + imageData;
        setupImage(imageData);
      }

      function onFail(message) {
        console.log('Failed because: ' + message);
      }

      function getMousePos(canvas, evt) {
        var rect = canvas.getBoundingClientRect();
        return {
          x: evt.clientX - rect.left,
          y: evt.clientY - rect.top
        };
      }

      function init(imageObj) {
        console.log('init');

        var padding = 10;
        var mouseDown = false;

        var canvas = document.getElementById('canvas');
        var context = canvas.getContext('2d');
        context.strokeStyle = '#444';
        context.lineWidth = 2;
        context.canvas.width  = window.innerWidth;
        context.canvas.height = window.innerWidth;

        canvas.addEventListener('mousedown', function() {
          mouseDown = true;
        }, false);

        canvas.addEventListener('mouseup', function() {
          mouseDown = false;
        }, false);

        canvas.addEventListener('mousemove', function(evt) {
          console.log('mousemove');

          var mousePos = getMousePos(canvas, evt);
          var color = undefined;

          if (mouseDown && mousePos !== null && mousePos.x > padding && mousePos.x < padding + imageObj.width && mousePos.y > padding && mousePos.y < padding + imageObj.height) {
            var imageData = context.getImageData(padding, padding, imageObj.width, imageObj.width);
            var data = imageData.data;
            var x = mousePos.x - padding;
            var y = mousePos.y - padding;
            var red = data[((imageObj.width * y) + x) * 4];
            var green = data[((imageObj.width * y) + x) * 4 + 1];
            var blue = data[((imageObj.width * y) + x) * 4 + 2];
            var color = 'rgb(' + red + ',' + green + ',' + blue + ')';
            console.log('picked color is ' + color);
            updateColor(red, green, blue);
          }
        }, false);

        context.drawImage(imageObj, padding, padding);
      }

      function updateColor(R, G, B) {
        $scope.hex = rgbToHex(R, G, B);
        console.log($scope.hex);
      }

      function rgbToHex(R, G, B) {
        return toHex(R) + toHex(G) + toHex(B)
      }

      function toHex(n) {
        n = parseInt(n, 10);
        if (isNaN(n)) {
          return "00";
        }
        n = Math.max(0, Math.min(n, 255));
        return "0123456789ABCDEF".charAt((n - n % 16) / 16) + "0123456789ABCDEF".charAt(n % 16);
      }

      function setupImage(_data) {
        console.log('setupImage');

        var imageObj = new Image();
        imageObj.onload = function() {
          init(this);
        };
        imageObj.src = "data:image/jpeg;base64," + _data;
      }

  });

重要的部分从mousemove事件监听器之后开始。我已经成功获取了RGB值并将其转换为十六进制。这一切都很好地记录了下来-记录了RGB和HEX。但是$scope.hex似乎从未绑定/更新视图。请指导出了什么问题。
2个回答

4
尝试将您的updateColor()函数修改为以下内容。
function updateColor(R, G, B) {
  $scope.hex = rgbToHex(R, G, B);
  console.log($scope.hex);
  $scope.$apply();
}

这应该可以解决问题。你可能遇到的问题是更新了hex的值,但Angular可能没有识别到这个变化。$scope.$apply()应该强制绑定更新,从而解决你的问题。


那个有效 - 干杯。几分钟后会接受。我从来不确定何时使用apply(),有时会出现错误,所以我倾向于避免...应该尝试更好地理解它。 - jesses.co.tt
1
仅供参考:https://github.com/angular/angular.js/wiki/When-to-use-$scope.$apply() - brute_force
@jesses.co.tt 谢谢!我认为最好的方法是,每当您执行一些不通过某个 Angular 帮助程序或服务完成的异步操作时,应使用 $scope.$apply()。 - Haseeb Ahmed

2

我认为在您的情况下,由于它是异步运行的,当您使用鼠标移动事件时,angular不知道发生了什么变化。

将“updateColor(red, green, blue);”方法的调用包装在$scope.$apply中可以解决这个问题。

所以您需要:

$scope.$apply(function () {
    updateColor(red, green, blue);
});

不仅仅是:

updateColor(red, green, blue);

你也可以使用 $scope.$apply() 方法,但是请查看这里 http://jimhoskins.com/2012/12/17/angularjs-and-apply.html,他们解释了为什么前一种方法更受欢迎。


好的回答...只是太慢了!:D - jesses.co.tt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接