8

一部のテキスト領域のコンテンツをサニタイズしようとしていますが、ng-bind-html双方向バインディングが壊れているため使用できませng-modelん (同時には機能しません)。

奇妙なことng-bind-htmlに、モデルに適用すると、ディレクティブを使用し$sanitizeたり、内部で使用したりすると、異なる結果が生成されます。$sce

これが私が作ったサンプルです

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

最初のテキスト領域は を使用しng-bind-html、2 番目は を使用$sanitizeし、3 番目は AngularJS ソース コードから切り取った ng-bind-html ディレクティブのコードである必要があります。

""ng-bind-html を使用する場合にのみ修正され、他の 2 つの例では次のように変更されます"

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>

4

1 に答える 1

2

予想通り、衛生サービスも同じ結果を返しています。ngBindHtmlDirective内にブレークポイントを配置すると、ステップインして何が起こっているかを確認できます。$SanitizeProvider内の値を詳しく調べます。bufngBindHtmlDirective に返される値は次のとおりです。

これは「引用符」にあります。テスト用

$sanitize を呼び出した場合とまったく同じですが、本当の違いは何でしょうか? 本当の違いは、テキスト ボックスの innerHTML と値の間です。このサンプル plunkerを表示します。二重引用符をエスケープする方法が異なるため、2 つの異なるメソッドの呼び出しの違いがわかります。私は w3 仕様やブラウザー コードを掘り下げませんでしたが、innerHTML の割り当ては、documentFragment を作成し、textContent を取得し、それをテキスト ボックスの値に割り当てるという内部で追加の作業を行っていると思います。明らかに値は、文字列を取得してそのまま挿入するだけです。


それで、あなたのディレクティブの問題は何ですか?コメントにあるようelement.html(processed)ですが、コメントを外しても影響はありません。真実は、それが一瞬で機能するということです! デバッガーでステップ実行すると、テキストボックスの値が正しく設定されますが、$digest サイクルが発生し、すぐに変更されます! 真実は、 ngModelDirective が邪魔をしていることです。具体的には、 baseInputType の $render 関数ですelement.valコードでメソッドを使用していることがわかります。

ディレクティブでこれをどのように修正できますか? ngModelController を要求し、element.html代わりにメソッドを使用するように $render 関数をオーバーライドします (例 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);
};
于 2016-02-13T06:14:28.243 に答える