为什么ng-bind-html和$ sanitize产生不同的结果?

时间:2015-07-27 14:44:13

标签: angularjs ngsanitize

我试图清理某些文本区域的内容,但我无法使用ng-bind-html因为它违反了双向绑定(ng-model无法同时工作)

奇怪的是,当我将ng-bind-html应用于模型时,它会在指令中使用$sanitize$sce时产生不同的结果。

这是我编写的一个样本

http://plnkr.co/edit/iRvK4med8T9Xqs22BkOe?p=preview

第一个文本区域使用ng-bind-html,第二个文本区域使用$sanitize,第三个文本区域应该是我从AngularJS源代码中删除的ng-bind-html指令的代码。

"仅在使用ng-bind-html时更正为",在其他两个示例中更改为"

如何在我的指令中复制ng-bind-html的结果 - 同时保持双向绑定?



angular.module('sanitizeExample', ['ngSanitize'])
  .controller('ExampleController', ['$scope', '$sce',
    function($scope, $sce) {

      $scope.value = 'This in "quotes" for testing';
      $scope.model = 'This in "quotes" for testing';

    }
  ]).directive('sanitize', ['$sanitize', '$parse', '$sce',
    function($sanitize, $parse, $sce) {
      return {
        restrict: 'A',
        replace: true,
        scope: true,
        link: function(scope, element, attrs) {

          var process = function(input) {
            return $sanitize(input);
            //return $sce.getTrustedHtml(input);
          };

          var processed = process(scope.model);
          console.log(processed); // Output here = This in "quotes" for testing
          $parse(attrs.ngModel).assign(scope, processed);
          //element.html(processed);
        }
      };
    }
  ])
  .directive('sanitizeBindHtml', ['$parse', '$sce',
    function($parse, $sce) {
      return {
        restrict: 'A',
        replace: true,
        scope: true,
        link: function(scope, element, attrs) {

          var parsed = $parse(attrs.ngModel);

          function getStringValue() {
            var value = parsed(scope);
            getStringValue.$$unwatch = parsed.$$unwatch;
            return (value || '').toString();
          }

          scope.$watch(getStringValue, function ngBindHtmlWatchAction(value) {
            var processed = $sce.getTrustedHtml(parsed(scope)) || '';

            $parse(attrs.ngModel).assign(scope, processed)
          });
        }
      };
    }
  ]);

<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.4.3/angular.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.4.3/angular-sanitize.js"></script>

<!doctype html>
<html lang="en">


<body ng-app="sanitizeExample">

  <div ng-controller="ExampleController">
    <textarea ng-bind-html="value"></textarea>
    <br/>{{value}}
    <br/>
    <br/>
    <textarea sanitize ng-model="model"></textarea>
    <br/>
    <br/>
    <textarea sanitize-bind-html ng-model="model"></textarea>

  </div>
</body>
&#13;
&#13;
&#13;

1 个答案:

答案 0 :(得分:2)

事实证明,卫生服务正在回归相同的结果。在ngBindHtmlDirective内放置一个断点,我们可以介入,看看发生了什么。我们深入研究$SanitizeProvider内的值。将返回ngBindHtmlDirective的buf值为:

  

这个&##;引用&amp;#34;用于测试

与我们调用$ sanitize完全相同,那么真正的区别是什么?真正的区别在于文本框的innerHTML和值之间。查看此example plunker。您可以看到调用两种不同方法之间的区别,使用不同的方法来转义双引号。我没有去挖掘w3规范或浏览器代码,但我认为innerHTML赋值是在创建documentFragment,抓取它的textContent,然后将其分配给文本框的值的引擎下做额外的工作。显然,值只是抓住字符串并按原样插入。

那么你的指令有什么问题?我看到element.html(processed)在评论中,但取消注释它没有影响。嗯,事实是它确实工作了一瞬间!使用调试器逐步调试,文本框的值被正确设置,然后$ digest循环被触发并立即更改它!事实是ngModelDirective正在阻碍,特别是它是$render function of the baseInputType。我们可以在代码中看到它使用的是element.val方法。

我们如何在指令中解决这个问题?需要ngModelController并覆盖其$ render函数以改为使用element.html方法(example plunker)。

// Add require to get the controller
require: 'ngModel',

// Controller is passed in as the 4th argument
link: function(scope, element, attrs, ngModelCtrl) {

// modify the $render function to process it as HTML
ngModelCtrl.$render = function() {
    element.html(ngModelCtrl.$isEmpty(ngModelCtrl.$viewValue) ? '' : ngModelCtrl.$viewValue);
};