在角JS字符串通过$ sce.trustAsHtml添加数据绑定 [英] Binding data in Angular js in string added via $sce.trustAsHtml

查看:476
本文介绍了在角JS字符串通过$ sce.trustAsHtml添加数据绑定的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我实施遗留系统的Web界面,所以从服务器上的数据是固定的。这个服务器的数据指定的各种控制,以显示给用户,例如组合框,按钮等我已经解析服务器的数据,并通过$ sce.trustAsHtml()。

添加了控件的HTML

的问题是,在控制不绑定到模型中。如果我把在NG-change事件处理,那就不叫有用户编辑。

我读这是很有帮助的帖子:<一href=\"http://stackoverflow.com/questions/20297638/call-function-inside-sce-trustashtml-string-in-angular-js\">call $ sce.trustAsHtml()字符串中的角JS里面功能指示:


  

NG-绑定-HTML将只需插入普通的旧html和
  懒得编译它(在这样任何指示
  的HTML不会因角进行处理。


所以,这似乎是我的问题。但我不明白的角度不够好,理解上述职位所提供的解决方案。

我在下面的HTML

显示动态文本

 &LT;跨度NG重复=我在范围(0,item.Data.DisplayText.JSArray.length-1)&GT;
  &LT;跨度NG绑定-HTML =item.Data.DisplayText.JSArray [我] | trusted_html&GT;&LT; / SPAN&GT;
  &LT;跨度NG-秀= GT$啦!;&LT; BR&GT;&LT; / SPAN&GT;
&LT; / SPAN&GT;

下面是范围()的定义:

  $ scope.range =功能(最小值,最大值){
  无功输入= [];
  为(变量I =分钟; I&下; =最大值; i ++在)input.push(ⅰ);
  返回输入;
};

这里是定义过滤器:

  app.filter('trusted_html',['$ SCE',函数($ SCE){
    复位功能(文本){
        返回$ sce.trustAsHtml(文本);
    };
}]);

我有帮助设置的这个部分组成,并从这里堆栈溢出收集解决方案。我很抱歉不能给链接到这些原始的解决方案。

我想我需要做的是延长我的trusted_html过滤器,使其$编译文本。但我不知道是否这将编译整个DOM(可能慢)或只是文本参数。

任何帮助将AP preciated。


附录:

我AP preciate @Simeon奇斯曼的响应。他表示,指令会比一个过滤器更好,因为我最初想。我一直在研究的文档和阅读的帖子,看来他是100%正确。 DOM操作应该发生的指令。但是,我不喜欢有一个指令的想法(例如编译模板从上面的链接的例子)另定指令的不足之处(NG-绑定-HTML)。这似乎表现欠佳给我。我怎么知道,之前编译模板指令是NG-绑定HTML的指令会被执行?而如果执行顺序是相反的,会发生什么?

所以我要考虑是否可以把它们合并成一个功能。我会想起大声这里下文。如果有人看到一个问题,请让我知道。

首先,我看着从angular.js的NG-绑定-HTML指令这里找到:的的https://$c$c.angularjs.org/1.2.9/angular.js 并在这个文件中,我搜索ngBindHTML

  VAR ngBindHtmlDirective = ['$ SCE,$解析',函数($ SCE,$解析){
  返回功能(范围,元素,属性){
    element.addClass('NG结合)的数据('$结合,attr.ngBindHtml)。    VAR分析= $解析(attr.ngBindHtml);
    功能向GetStringValue(){回报(解析(范围)||'')的ToString(); }    范围。$表(向GetStringValue,功能ngBindHtmlWatchAction(值){
      element.html($ sce.getTrustedHtml(解析(范围))||'');
    });
 };

}];

以上是不是在app.directive(形式),并且它不返回{链接:好玩()}对象。所以我不完全肯定这是否直接适用于比较下面的编译模板指令。然而,我发现,在线2025以下。所以我觉得我在正确的道路上:

  ngBindHtml:ngBindHtmlDirective,

所以这ngBindHtmlDirective以某种方式作为ngBindHtml。

我要挑分开code以上,改革它。而仅供参考,我是比较新的JavaScript和匿名函数和闭包仍然是一个有点新的我。所以我试图消除匿名函数为我的清晰度。我会添加一些意见,从信息,我拿起角上的网站等。

  VAR DirectiveFnFactory =功能($ SCE,$解析){  VAR DirectiveHandlerFn =功能(范围,元素,属性){
    //输入:=范围的角度范围,对象
    //元=的jqLit​​e包裹的元素,这条指令比赛
    // ATTR =与规范化属性的键 - 值对的哈希对象
    //名称和它们相应的属性值
    //关闭范围输入:$编译对象
    // $解析对象
    //结果:无    element.addClass('NG结合');
    // .addClass是jQuery的:http://api.jquery.com/addclass/
    //添加类元素
    element.data('$结合,attr.ngBindHtml);
    //增加价值的'$结合键;    VAR分析= $解析(attr.ngBindHtml);
    //输入:attr.ngBindHtml应该要绑定的HTML。
    //结果:$解析()返回重新presents的功能
    //编译输入前pression。
    //这个函数都会有这样的签名:
    //功能(背景下,当地人)
    //背景 - {}对象 - 一个对象针对的任何前pressions
    //嵌入在字符串针对评估
    //(通常是范围对象)。
    //当地人 - {对象=} - 局部变量上下文对象,有用
    //在上下文中压倒一切的价值观。
    //返回的功能还具有下列性能:
    //字面 - {}布尔 - 无论是前pression的顶级节点是一个
    // JavaScript的文字。
    //恒 - {}布尔 - 无论是前pression制成
    //完全的JavaScript常量文字的。
    //分配 - {?功能(背景下,值)} - 如果EX pression是分配的,
    //这将被设置为一个函数来改变其值
    //在给定的范围内。    功能向GetStringValue(){回报(解析(范围)||'')的ToString(); }
    //首先,这是在执行由解析)返回(功能,
    //传递范围这是给DirectiveHandlerFn()
    //下一个转变FN()输出字符串。
    //在结合HTML的情况。我认为,它的输出是HTML    VAR watchListener =功能ngBindHtmlWatchAction(值){
      element.html($ sce.getTrustedHtml(解析(范围))||'');
      //.html是jQuery的:http://api.jquery.com/html/
      //获取第一个元素的HTML内容的匹配的元素
      //或者设置每个匹配的元素的HTML内容。
    }    。范围$表(向GetStringValue,watchListener);
    // $表签名:
    // $腕表(watchEx pression,听众,[objectEquality]);
    //这个注册一个侦听器回调要执行的时
    // watchEx pression()的变化
    //监听器()有这个签名(举例,不是API文件确定!):
    //监听器(为newValue,属性oldValue);
    //监听器是由角的值更改时自动地调用。
  }  返回DirectiveHandlerFn;
}VAR ngBindHtmlDirective = ['$ SCE,$解析,DirectiveFnFactory]

好了,现在我会先引用compileTemplate指令,(从这里开始:<一href=\"http://stackoverflow.com/questions/20297638/call-function-inside-sce-trustashtml-string-in-angular-js\">call

:$ sce.trustAsHtml()字符串中的角JS )的内部函数

  .directive('compileTemplate',函数($编译,$解析){
    返回{
        链接:功能(范围,元素,阿塔尔){
            VAR分析= $解析(attr.ngBindHtml);
            功能向GetStringValue(){回报(解析(范围)||'')的ToString(); }            //重新编译如果模板修改
            范围。$表(向GetStringValue,函数(){
                $编译(元素,空,-9999)(范围);
               //该-9999使得它跳过指令,以便我们
               //不要自己编译
            });
        }
    }
});

而现在采摘它拆开,让评论:

  VAR DirectiveObjFactory =功能($编译,$解析){
    //输入:$编译对象
    // $解析对象    VAR DirectiveHandlerFn =功能(范围,元素,属性){
        //输入:=范围的角度范围,对象
        //元=的jqLit​​e包裹的元素,这条指令比赛
        // ATTR =与规范化属性的键 - 值对的哈希对象
        //名称和它们相应的属性值
        //关闭范围瓦尔:$编译对象
        // $解析对象
        //结果:无        VAR分析= $解析(attr.ngBindHtml);
        //输入:attr.ngBindHtml应该要绑定的HTML。
        //结果:$解析()返回重新presents的功能
        //编译输入前pression。
        //这导致功能都会有这样的签名:
        //功能(背景下,当地人)
        //背景 - {}对象 - 一个对象针对的任何前pressions
        //嵌入在字符串针对评估
        //(通常是范围对象)。
        //当地人 - {对象=} - 局部变量上下文对象,有用
        //在上下文中压倒一切的价值观。
        //返回的功能还具有下列性能:
        //字面 - {}布尔 - 无论是前pression的顶级节点是一个
        // JavaScript的文字。
        //恒 - {}布尔 - 无论是前pression制成
        //完全的JavaScript常量文字的。
        //分配 - {?功能(背景下,值)} - 如果expr是分配的,
        //这将被设置为一个函数来改变其值
        //在给定的范围内。       功能向GetStringValue(){回报(解析(范围)||'')的ToString(); }
        //首先,这是在执行由解析)返回(功能,
        //传递范围这是给DirectiveHandlerFn()
        //下一个转变FN()输出字符串。
        //在结合HTML的情况。我认为,它的输出
        //将是HTML        VAR watchListener =功能ngBindHtmlWatchAction(值){
          //输入:值 - 实际设置为newValue。 (属性oldValue这里不接受)
          //局部范围使用瓦尔 - 元素,范围          // - 添加下面是ngbindHtml ------------
          element.html($ sce.getTrustedHtml(解析(范围))||'');
          //.html是jQuery的:http://api.jquery.com/html/
          //获取集合中的第一个元素的HTML内容的匹配
          //元素或设置每个匹配的元素的HTML内容。
          // - 完此外------------          VAR compFn = $编译(元素,空,-9999);
          //注:我无法找到正式文件为$编译参数()
          //下面是从找到的例子...
          //输入:元素 - HTML元素编译
          // transcludeFunction - 空在这里。
          // maxPriority - 大-9999使得它跳过指令,以便我们
          //不重新编译自己
          // $编译()编译的HTML字符串或DOM成一个模板,并
          //产生模板函数,那么它可以用来链接范围
          //和模板在一起。
          //返回函数接受范围的变量,对其中code
          //进行评估。
          compFn(范围); //执行返回的功能,传递范围
        } //结束watchListener        。范围$表(向GetStringValue,watchListener);
        // $手表()函数签名:
        // $腕表(watchEx pression,听众,[objectEquality]);
        //这个注册一个侦听器回调要执行的时
        // watchEx pression变化
        //提供的监听器()应该有这样的签名:
        //监听器(为newValue,属性oldValue);
        //监听器是由角的值更改时自动地调用。    } //结束DirectiveHandlerFn    返回{链接:DirectiveHandlerFn}} //结束DirectiveObjFactoryapp.directive('compileTemplate',DirectiveObjFactory);

我觉得我几乎没有。让我尝试把所有这一切重新走到一起......

  .directive('bindAndWatchHtml',['$ SCE',函数($编译,$解析){
    返回{
        链接:功能(范围,元素,属性){
            VAR分析= $解析(attr.ngBindHtml);
            功能向GetStringValue(){回报(解析(范围)||'')的ToString(); }            //重新编译如果模板修改
            范围。$表(向GetStringValue,函数(){
                element.html($ sce.getTrustedHtml(解析(范围))||'');
                $编译(元素,空,-9999)(范围);
                //该-9999使得它跳过指令,以便我们不会重新编译自己
            });
        }
    }
}]);

希望这将绑定并编译HTML,并在同一时间信任HTML。

现在测试...

附录:

不工作..就行了:

  element.html($ sce.getTrustedHtml(解析(范围))||'');

它抱怨的$ SCE没有定义。

...

我改变了以下行,并允许定义$ SCE。

  app.directive('bindAndWatchTrustedHtml0',['$编译,$解析,$ SCE,
                                       功能($编译,解析$,$ SCE){...

接下来,我得到一个错误约试图在不安全的位置,使用安全的文字....

...

这只是时间太长。我对这个放弃。我用这个,按照在最高层的原始链接,和它的作品。

 &LT;跨度NG绑定-HTML =item.Data.DisplayText.JSArray [我] | trusted_html编译模板&GT;
&LT; / SPAN&GT;


解决方案

请参阅的的https://$c$c.angularjs.org/1.2.19/docs/api/ng/service/ $编译如何编译

基本上,你会打电话 compiledHtml = $编译('&LT; D​​IV&GT;'+文字+'&LT; / DIV&GT;')($范围)的.html()

我想你会得到更好又比使用过滤器但正如你所需要的 $范围变量编译创建一个指令。

也许你可以利用 ngBindTemplate ngInclude

I am implementing a web interface for a legacy system, so data from server is fixed. This server data specifies various controls to be shown to the user, e.g. combo-boxes, buttons etc. I have parsed the server data and added the HTML for the controls via $sce.trustAsHtml().

The problem is that the controls are not bound to the model. And if I put in an ng-change event handler, it is not called with user edits.

I read this helpful post: call function inside $sce.trustAsHtml() string in Angular js that indicates:

ng-bind-html will simply insert plain old html and not bother compiling it (so any directives in the html will not be processed by angular.

So this seems to be my problem. But I don't understand Angular well enough to understand the solution offered by the above post.

I am displaying the dynamic text in the following HTML

<span ng-repeat="i in range(0, item.Data.DisplayText.JSArray.length-1)">
  <span ng-bind-html="item.Data.DisplayText.JSArray[i] | trusted_html"></span>
  <span ng-show="!$last"><br></span>
</span>

Here is the definition for range():

$scope.range = function(min, max){
  var input = [];
  for (var i=min; i<=max; i++) input.push(i);
  return input;
};

And here is the definition for the filter:

app.filter('trusted_html', ['$sce', function($sce){
    return function(text) {
        return $sce.trustAsHtml(text);
    };
}]);

I have had help setting parts of this up, and have gleaned solutions from here on stack-overflow. I apologize that can't give links to these original solutions.

What I think I need to do is to extend my trusted_html filter such that it $compiles the text. But I don't know if that would compile the entire DOM (potentially slow) or just the text parameter.

Any help will be appreciated.


ADDENDUM:

I appreciate @Simeon Cheeseman's response. He indicated that a directive would be better than a filter, as I initially wanted. I have been studying the documentation and reading posts, and it seems he is 100% correct. DOM manipulation should occur in directives. However, I don't like the idea of having one directive (e.g. 'compile-template' from the example in the link above) fix the short-comings of another directive (ng-bind-html). It seems poor form to me. How do I know that the ng-bind-html directive will be executed before the compile-template directive is? And what happens if the execution order is reversed?

So I am going to consider if they could be combined into one function. I will think out loud here below. If anyone sees a problem, please let me know.

First, I looked at the ng-bind-html directive from angular.js found here: https://code.angularjs.org/1.2.9/angular.js and in this file, I searched for 'ngBindHTML'.

var ngBindHtmlDirective = ['$sce', '$parse', function($sce, $parse) {
  return function(scope, element, attr) {
    element.addClass('ng-binding').data('$binding', attr.ngBindHtml);

    var parsed = $parse(attr.ngBindHtml);
    function getStringValue() { return (parsed(scope) || '').toString(); }

    scope.$watch(getStringValue, function ngBindHtmlWatchAction(value) {
      element.html($sce.getTrustedHtml(parsed(scope)) || '');
    });
 };

}];

The above is not in the form of app.directive(), and it doesn't return a {link: fun()} object. So I am not exactly sure if this directly applicable to compare to the compile-template directive below. However, I did find, on line 2025, the following. So I think I am on the right path:

ngBindHtml: ngBindHtmlDirective,

So this ngBindHtmlDirective is somehow acting as ngBindHtml.

I am going to pick apart the code above, and reform it. And FYI, I am relatively new to javascript, and anonymous functions and closures are still a bit new to me. So I am trying to remove anonymous functions for my clarity. I'll add some comments from info I have picked up on Angular's website etc.

var DirectiveFnFactory = function($sce, $parse) {

  var DirectiveHandlerFn = function(scope, element, attr) {
    //Input:  scope = an Angular scope object 
    //        element = the jqLite-wrapped element that this directive matches
    //        attr = a hash object with key-value pairs of normalized attribute 
    //               names and their corresponding attribute values
    //closure scope input: $compile object
    //                     $parse object
    //Result: none

    element.addClass('ng-binding');
    // .addClass is jQuery:  http://api.jquery.com/addclass/
    //  adds class to element
    element.data('$binding', attr.ngBindHtml);
    //  adds value to key of '$binding';

    var parsed = $parse(attr.ngBindHtml); 
    //Input:  attr.ngBindHtml should be the HTML to be bound.
    //Result:  $parse() returns a function which represents the 
    //         compiled input expression.
    //  This function will have this signature: 
    //     function(context, locals)    
    //            context – {object} – an object against which any expressions 
    //                                 embedded in the strings are evaluated against 
    //                                 (typically a scope object).
    //            locals – {object=} – local variables context object, useful for 
    //                                 overriding values in context.
    //     The returned function also has the following properties:
    //       literal – {boolean} – whether the expression's top-level node is a 
    //                             JavaScript literal.
    //                           constant – {boolean} – whether the expression is made 
    //                             entirely of JavaScript constant literals.
    //        assign – {?function(context, value)} – if the expression is assignable, 
    //                             this will be set to a function to change its value 
    //                             on the given context.

    function getStringValue() { return (parsed(scope) || '').toString(); }
    //First, this is executing the function that was returned by parsed(), 
    //    passing scope that was given to DirectiveHandlerFn()
    //Next converting Fn() output to string. 
    //In the case of binding HTML. I would think that the output of this would be HTML

    var watchListener = function ngBindHtmlWatchAction(value) {
      element.html($sce.getTrustedHtml(parsed(scope)) || '');
      //.html is jquery: http://api.jquery.com/html/
      //  Get the HTML contents of the first element in the set of matched elements
      //    or set the HTML contents of every matched element.
    }

    scope.$watch(getStringValue, watchListener);
    //$watch signature: 
    //  $watch(watchExpression, listener, [objectEquality]);
    //  This registers a listener callback to be executed whenever the 
    //    watchExpression()  changes
    //  The listener() has this signature (determined by example, not API documents!):
    //     listener(newValue, oldValue);
    //  The listener is called automagically by Angular when the value changes.
  }

  return DirectiveHandlerFn;
}

var ngBindHtmlDirective = ['$sce', '$parse', DirectiveFnFactory];

OK, now I will first quote the compileTemplate directive, (from here: call function inside $sce.trustAsHtml() string in Angular js):

.directive('compileTemplate', function($compile, $parse){
    return {
        link: function(scope, element, attar){
            var parsed = $parse(attr.ngBindHtml);
            function getStringValue() { return (parsed(scope) || '').toString(); }

            //Recompile if the template changes
            scope.$watch(getStringValue, function() {
                $compile(element, null, -9999)(scope);  
               //The -9999 makes it skip directives so that we 
               //do not recompile ourselves
            });
        }         
    }
});

And now pick it apart to allow commenting:

var DirectiveObjFactory = function($compile, $parse){
    //input: $compile object
    //       $parse object

    var DirectiveHandlerFn = function(scope, element, attr) {
        //Input:  scope = an Angular scope object 
        //        element = the jqLite-wrapped element that this directive matches
        //        attr = a hash object with key-value pairs of normalized attribute 
        //               names and their corresponding attribute values
        //closure scope vars: $compile object
        //                    $parse object
        //Result: none

        var parsed = $parse(attr.ngBindHtml);
        //Input:  attr.ngBindHtml should be the HTML to be bound.
        //Result:  $parse() returns a function which represents the 
        //         compiled input expression.
        //  This resulted function will have this signature: 
        //     function(context, locals)    
        //            context – {object} – an object against which any expressions 
        //                             embedded in the strings are evaluated against 
        //                             (typically a scope object).
        //            locals – {object=} – local variables context object, useful for 
        //                             overriding values in context.
        //     The returned function also has the following properties:
        //       literal – {boolean} – whether the expression's top-level node is a 
        //                         JavaScript literal.
        //       constant – {boolean} – whether the expression is made 
        //                             entirely of JavaScript constant literals.
        //        assign – {?function(context, value)} – if the expr is assignable, 
        //                          this will be set to a function to change its value 
        //                             on the given context.

       function getStringValue() { return (parsed(scope) || '').toString(); }
        //First, this is executing the function that was returned by parsed(), 
        //    passing scope that was given to DirectiveHandlerFn()
        //Next converting Fn() output to string. 
        //In the case of binding HTML. I would think that the output of this 
        //  would be HTML

        var watchListener = function ngBindHtmlWatchAction(value) {
          //Input: value -- actual the newValue. (oldValue not accepted here)
          //Locally scoped vars used -- element, scope

          // -- Adding Below is from ngbindHtml ------------
          element.html($sce.getTrustedHtml(parsed(scope)) || '');
          //.html is jquery: http://api.jquery.com/html/
          //Gets the HTML contents of the first element in the set of matched 
          //    elements or set the HTML contents of every matched element.
          // -- End addition  ------------

          var compFn = $compile(element, null, -9999);
          //NOTE: I can't find formal documentation for the parameters for $compile()
          //      below is from examples found...
          //Input: element -- the HTML element to compile
          //       transcludeFunction -- null here.
          //       maxPriority -- "The -9999 makes it skip directives so that we 
          //                       do not recompile ourselves"
          //$compile() compiles an HTML string or DOM into a template and 
          //    produces a template function, which can then be used to link scope 
          //    and the template together.
          //  The returned function accepts a scope variable, against which the code
          //    is evaluated. 
          compFn(scope); // execute the returned function, passing scope  
        } // end watchListener

        scope.$watch(getStringValue, watchListener);
        //$watch() function signature: 
        //  $watch(watchExpression, listener, [objectEquality]);
        //  This registers a listener callback to be executed whenever the 
        //    watchExpression changes
        //  The supplied listener() should have this signature:
        //     listener(newValue, oldValue);
        //  The listener is called automagically by Angular when the value changes.

    } // end DirectiveHandlerFn

    return {link: DirectiveHandlerFn}         

} // end DirectiveObjFactory

app.directive('compileTemplate', DirectiveObjFactory);

I think I am almost there. Let me try to bring this all back together...

.directive('bindAndWatchHtml', ['$sce', function($compile, $parse){
    return {
        link: function(scope, element, attr){
            var parsed = $parse(attr.ngBindHtml);
            function getStringValue() { return (parsed(scope) || '').toString(); }

            //Recompile if the template changes
            scope.$watch(getStringValue, function() {
                element.html($sce.getTrustedHtml(parsed(scope)) || '');
                $compile(element, null, -9999)(scope);  
                //The -9999 makes it skip directives so that we do not recompile ourselves
            });
        }         
    }
}]);

Hopefully this will bind AND compile the html, and trust the HTML at the same time.

Now for testing...

ADDENDUM:

Doesn't work.. On the line:

element.html($sce.getTrustedHtml(parsed(scope)) || '');

it complains the $sce is not defined.

...

I changed the following line, and that allows $sce to be defined.

app.directive('bindAndWatchTrustedHtml0', ['$compile', '$parse', '$sce',
                                       function($compile, $parse, $sce){ ...

Next I get an error about trying to use a secure text in an insecure location....

....

This is just taking too long. I'm giving up on this. I used this, as per the original link at the very top, and it works.

<span ng-bind-html="item.Data.DisplayText.JSArray[i] | trusted_html" compile-template>
</span>

解决方案

See https://code.angularjs.org/1.2.19/docs/api/ng/service/$compile for how to compile.

Basically you'd call compiledHtml = $compile('<div>' + text + '</div>')($scope).html().

I think you're going to be better off creating a directive than using a filter though as you'll need the $scope variable to compile.

Maybe you could make use of ngBindTemplate or ngInclude

这篇关于在角JS字符串通过$ sce.trustAsHtml添加数据绑定的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆