提问者:小点点

从数据库编译动态HTML字符串


我们的Angular应用程序中嵌套了一个名为Page的指令,由一个控制器支持,该控制器包含一个带有ng-bind-html-unsafe属性的div。它被分配给一个名为'page content'的$scope var。这个var从数据库中获得动态生成的HTML。当用户翻转到下一个页面时,将对DB进行调用,并将pageContent var设置为这个新的HTML,通过ng-bind-html-unsafe将其呈现在屏幕上。代码如下:

页面指令

angular.module('myApp.directives')
    .directive('myPage', function ($compile) {

        return {
            templateUrl: 'page.html',
            restrict: 'E',
            compile: function compile(element, attrs, transclude) {
                // does nothing currently
                return {
                    pre: function preLink(scope, element, attrs, controller) {
                        // does nothing currently
                    },
                    post: function postLink(scope, element, attrs, controller) {
                        // does nothing currently
                    }
                }
            }
        };
    });

Page指令的模板(来自上面templateUrl属性的“Page.html”)

<div ng-controller="PageCtrl" >
   ...
   <!-- dynamic page content written into the div below -->
   <div ng-bind-html-unsafe="pageContent" >
   ...
</div>

页面控制器

angular.module('myApp')
  .controller('PageCtrl', function ($scope) {

        $scope.pageContent = '';

        $scope.$on( "receivedPageContent", function(event, args) {
            console.log( 'new page content received after DB call' );
            $scope.pageContent = args.htmlStrFromDB;
        });

});

这招管用。我们可以看到页面的HTML在浏览器中很好地呈现在DB中。当用户翻转到下一页时,我们会看到下一页的内容,依此类推。到目前为止还不错。

这里的问题是,我们希望在页面内容中包含交互式内容。例如,HTML可能包含一个缩略图,当用户点击它时,Angular应该会做一些很棒的事情,比如显示一个弹出的模式窗口。我在数据库中的HTML字符串中放置了Angular方法调用(ng-click),但当然Angular不会识别方法调用或指令,除非它以某种方式解析HTML字符串,识别它们并编译它们。

在我们的数据库中

第1页得内容:

<p>Here's a cool pic of a lion. <img src="lion.png" ng-click="doSomethingAwesone('lion', 'showImage')" > Click on him to see a large image.</p>

第2页的内容:

<p>Here's a snake. <img src="snake.png" ng-click="doSomethingAwesone('snake', 'playSound')" >Click to make him hiss.</p>

回到页面控制器中,我们然后添加相应的$scope函数:

页面控制器

$scope.doSomethingAwesome = function( id, action ) {
    console.log( "Going to do " + action + " with "+ id );
}

我不知道如何从DB的HTML字符串中调用'Do SomethingAwesome'方法。我意识到Angular必须以某种方式解析HTML字符串,但是如何解析呢?我读过一些关于$compile服务的含糊不清的描述,并复制和粘贴了一些示例,但没有任何效果。而且,大多数示例只显示在指令的链接阶段设置动态内容。我们希望佩奇在应用程序的整个生命周期中都能保持活力。当用户翻阅页面时,它不断地接收,编译和显示新的内容。

从抽象的意义上说,我想你可以说我们试图在一个Angular应用程序中动态地嵌套Angular块,并且需要能够交换它们。

我多次阅读了各种角度文档,以及各种博客文章,JS也在摆弄人们的代码。我不知道我是否完全误解了Angular,或者只是错过了一些简单的东西,或者也许我太慢了。无论如何,我需要一些建议。


共3个答案

匿名用户

ng-bind-html-unsafe只将内容呈现为HTML。它不将角度作用域绑定到结果DOM。为此,您必须使用$compile服务。我创建这个插件是为了演示如何使用$compile创建一个指令,呈现用户输入的动态HTML,并绑定到控制器的作用域。资料来源如下。

demo.html

<!DOCTYPE html>
<html ng-app="app">

  <head>
    <script data-require="angular.js@1.0.7" data-semver="1.0.7" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.js"></script>
    <script src="script.js"></script>
  </head>

  <body>
    <h1>Compile dynamic HTML</h1>
    <div ng-controller="MyController">
      <textarea ng-model="html"></textarea>
      <div dynamic="html"></div>
    </div>
  </body>

</html>

script.js

var app = angular.module('app', []);

app.directive('dynamic', function ($compile) {
  return {
    restrict: 'A',
    replace: true,
    link: function (scope, ele, attrs) {
      scope.$watch(attrs.dynamic, function(html) {
        ele.html(html);
        $compile(ele.contents())(scope);
      });
    }
  };
});

function MyController($scope) {
  $scope.click = function(arg) {
    alert('Clicked ' + arg);
  }
  $scope.html = '<a ng-click="click(1)" href="#">Click me</a>';
}

匿名用户

在angular 1.2.10中,scope.$watch(attrs.dynamic,function(html){行返回了一个无效字符错误,因为它试图监视attrs.dynamic的值,该值是html文本。

我通过从scope属性中获取属性来修复这个问题

 scope: { dynamic: '=dynamic'}, 

我的例子

angular.module('app')
  .directive('dynamic', function ($compile) {
    return {
      restrict: 'A',
      replace: true,
      scope: { dynamic: '=dynamic'},
      link: function postLink(scope, element, attrs) {
        scope.$watch( 'dynamic' , function(html){
          element.html(html);
          $compile(element.contents())(scope);
        });
      }
    };
  });

匿名用户

在谷歌讨论组中发现。对我有效。

var $injector = angular.injector(['ng', 'myApp']);
$injector.invoke(function($rootScope, $compile) {
  $compile(element)($rootScope);
});

相关问题