Angular:我能完全禁用过滤吗?

19

是否可以完全禁用HTML的净化?

我想要实现的是在我的控制器中:

$scope.greeting = '<h2>Hello World</h2>'

在我看来

{{greeting}}

我不能(也不想)使用ng-bind-html等,我想完全禁用它们的过滤。

为了提供更多背景信息-我正在为开发特定系统的模板准备简单的“框架封装”。

当您为此系统开发模板时,它们有预定义的代码片段,您可以通过编写“{{something}}”将其放置在页面上,但它并不是在Angular上运行(可能是Mustache或其他内容)。

现在,模板只能在线开发,这是非常不友好的过程。因此,我在Angular中设置了一个简单的项目,并相应地设置了路由等,以便每个人都可以在自己的机器上开发模板,然后将其简单地复制到该系统中。

这就是为什么在模板文件中不应该注意到它是在Angular中完成的,它应该尽可能接近他们的系统。

最后注意一点-我确实尝试过:

myApp.config(['$sceProvider',function($sceProvider){
    $sceProvider.enabled(false);
}]);

对我没有任何作用


@Donal 这有什么帮助吗? - Tomas
你需要升级你的Angular版本才能使用这个功能。你应该拥有Angular 1.3+版本。 - Pankaj Parkar
@pankajparkar 我正在使用1.3.15版本。 - Tomas
4个回答

9

是的,你可以关闭SCE,但这不会导致你的字符串被插入到HTML中

根据您的情况:

  $scope.movie = {title:"<h1>Egghead.io AngularJS, Binding</h1>",
 src:"http://www.youtube.com/embed/Lx7ycjC8qjE"};

直接插入标题而不使用ng-bind-html="movie.title"进行插值

<p>{{movie.title}}</p>

将会生成这个

<h1>Egghead.io AngularJS Binding</h1>

直接插值似乎是经过消毒的,但实际上没有编译。

带有HTML的插值字符串被视为字符串,除非在指令中编译。

其他框架往往是“基于字符串”的(它们直接向浏览器提供数据),而AngularJS是“基于DOM”的,它会编译您的HTML并使用作用域和监控事件进行积极管理。马丁·福勒将此称为模板 查看与转换视图

可以在指令中编译HTML,但只能在标记和控制器中插值


我创建了2个 Plunker 尝试访问“不安全的url”,这意味着我在ng-src中插值了一个 url 而没有使用$sce.trustAs

演示1:Plunker 1SCE 在配置期间被禁用

标记插值“不安全的url”:

    <p>{{movie.title}}</p>
    <iframe class="youtube-player" type="text/html" width="640" height="385" ng-src="{{movie.src}}" allowfullscreen frameborder="0">
</iframe>

应用程序禁用了$sceProvider

var app = angular.module('plunker', ['ngSanitize']);
app.config(['$sceProvider',function($sceProvider){
    $sceProvider.enabled(false);
}]);
app.controller('MainCtrl', function($scope, $sce) {

  $scope.movie = {src:"http://www.youtube.com/embed/Lx7ycjC8qjE", title:"Egghead.io AngularJS Binding"};
});

“不安全”的URL被插值而不出错。视频被显示。


展示2:Plunker 2 app.config已被注释掉,因此使用默认的SCE设置。

var app = angular.module('plunker', ['ngSanitize']);
//app.config(['$sceProvider',function($sceProvider){
//    $sceProvider.enabled(false);
//}]);
app.controller('MainCtrl', function($scope, $sce) {

  $scope.movie = {src:"http://www.youtube.com/embed/Lx7ycjC8qjE", title:"Egghead.io AngularJS Binding"};
});

错误:

错误: [$interpolate:interr] 无法插值: {{movie.src}} 错误: [$sce:insecurl] 因不在 $sceDelegate 策略允许的 URL 中,阻止从 url 加载资源。 URL:http://www.youtube.com/embed/Lx7ycjC8qjE


@Tom,请尝试使用仅src="{{movie.src}}"的新Plunker,并告诉我导致SCE错误的HTML的详细信息。http://plnkr.co/edit/GFRpFqysxiuGHH9i2QHb?p=preview - Dave Alperovich
但我并不想对src做任何操作...只需将您的电影标题包装在<h1>标签中:$scope.movie = {title: '<h1>Whatever</h1>'},您会发现在页面上打印出标签,而不是呈现的HTML。 - Tomas
@Tom,对不起,我应该意识到你想要什么。我的回答从回顾来看是错误的。我太过于字面理解了你关于SCE的问题,而没有看到显而易见的事实。直接插值始终是经过净化的。更准确地说,插值不会导致编译。将字符串编译成HTML只能在指令上完成。这与SCE无关,因为策略指令和服务SCE,会因$interpolateservice或指令的不当使用而引发错误。您需要使用ng-bind-html、$interpolate或$compile来插值HTML。我已经修改了我的答案以更好地解释。 - Dave Alperovich
很酷,那么我的问题是:这真的不可能吗?还是有绕过去的方法? - Tomas
1
@Tom 没有使用指令,无法在Angular中编译HTML。 - Dave Alperovich
显示剩余4条评论

2
不久前,我成功地渲染了从类似这样的服务返回的一些HTML代码:
$scope.greeting = $sce.trustAsHtml('<h2>Hello World</h2>');

在你的HTML中
<div ng-bind-html="htmlGreeting"></div>

不要忘记在控制器中注入$sce服务。
编辑:这里有一个示例fiddle:https://jsfiddle.net/b78hkssn/2/

很奇怪,我最近的一个项目中只是少量地使用了它。它是静默失败还是返回错误信息?你有任何线索吗,为什么它不起作用? - davguij
trustAsHtml 用于禁用 SCE,它不会编译。HTML 不能通过 AngularJS "喂" 给浏览器。Angular 不支持被动模板化。该框架绕过了浏览器的 HTML 解释器。 - Dave Alperovich
我在我的答案中包含了一个链接到一个fiddle,展示了它的工作原理。 - davguij
您正在使用指令 ng-bind-html。该指令专门将内容编译为 HTML。在 AngularJS 中,指令是将字符串编译为标记的唯一方法。但 OP 显然不能使用任何指令来解决此问题。请检查他在我的答案中的第一个评论 我需要它完全不使用指令。否则,他原来的禁用 SCE 的方法将使信任变得不必要。 - Dave Alperovich
你是对的,@DaveAlperovich,我忽略了那个部分。抱歉。 - davguij
1
不,这一点都不明显。我只有在 OP 的回复后才意识到。问题是误导性的,因为 OP 还在学习 Angular。你的答案(针对所形成的问题)非常好。我希望更多的五位数声望用户也能像你一样仔细。 - Dave Alperovich

0
尝试使用装饰器增强或更改$sce的标准行为:
 angular
  .module( appName, [ ] )
  .config([ "$provide", function( $provide )
  {
        // Use the `decorator` to enhance or change behaviors of original service instance; 

        $provide.decorator( '$sce', [ "$delegate", function( $delegate )
        {
            // Save the original $sce.parseAsHtml
            var parseAsHtml= $sce.parseAsHtml;

            $delegate.parseHtml= function( ) {
              // Implements your custom behavior...
            };

            return $delegate;
        }]);
  }]);

尝试过了,还是不行。我已经深入挖掘了 Angular 代码,似乎 Angular 自动用文本节点替换每个 {{}} 表达式,这基本上阻止了 HTML 渲染。这可能吗? - Tomas

-1

我成功找到了另一种解决问题的方法,而不需要使用任何指令。

基本上,我使用一个注入器来使用$compile服务。

JS:

angular.injector(['ng']).invoke(function($compile, $rootScope) {
    $('.html-content').append($compile('<h2>Hello World</h2>')($rootScope));
});

这是一个演示:https://jsfiddle.net/davguij/tby59sk7/1/

那么你是绕过整个Angular管道并执行那段代码吗?这样HTML就不会被跟踪,Angular也变得无用了。所以我们现在又回到了使用jQuery的代码了。 - Maxime Rouiller

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