首页 文章

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

提问于
浏览
129

情况

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

Page directive

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 directive's template (上面的templateUrl属性"page.html")

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

Page controller

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很好地呈现 . 当用户翻到下一页时,我们会看到下一页的内容,依此类推 . 到现在为止还挺好 .

问题

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

In our DB

第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>

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

Page controller

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

我无法弄清楚如何从数据库的HTML字符串中调用'doSomethingAwesome'方法 . 我意识到Angular必须以某种方式解析HTML字符串,但是如何?我读过关于$ compile服务的模糊咕噜声,并复制并粘贴了一些例子,但没有任何效果 . 此外,大多数示例显示仅在指令的链接阶段设置的动态内容 . 我们希望Page在应用程序的整个生命周期中保持活力 . 当用户翻阅页面时,它会不断接收,编译和显示新内容 .

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

我已经多次阅读过各种各样的Angular文档,以及各种各样的博客文章,以及JS人们的代码 . 我不知道我是否完全误解了Angular,或者只是遗漏了一些简单的东西,或者说我很慢 . 无论如何,我可以使用一些建议 .

5 回答

  • 19

    ng-bind-html-unsafe 仅将内容呈现为HTML . 它不会将Angular范围绑定到生成的DOM . 您必须为此目的使用 $compile 服务 . 我创建了this plunker来演示如何使用 $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>';
    }
    
  • 5

    在角度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);
            });
          }
        };
      });
    
  • 246

    在谷歌讨论组中找到 . 适合我 .

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

    您可以使用

    ng-bind-html https://docs.angularjs.org/api/ng/service/$sce

    指令动态绑定html . 但是你必须通过$ sce服务获取数据 .

    请参阅http://plnkr.co/edit/k4s3Bx的现场演示

    var app = angular.module('plunker', []);
    app.controller('MainCtrl', function($scope,$sce) {
        $scope.getHtml=function(){
       return $sce.trustAsHtml("<b>Hi Rupesh hi <u>dfdfdfdf</u>!</b>sdafsdfsdf<button>dfdfasdf</button>");
       }
    });
    
      <body ng-controller="MainCtrl">
    <span ng-bind-html="getHtml()"></span>
      </body>
    
  • 1

    尝试以下代码,通过attr绑定html

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

    试试这个element.html(scope.dynamic);比element.html(attr.dynamic);

相关问题