从数据库编译动态 HTML 字符串 [英] Compiling dynamic HTML strings from database

查看:16
本文介绍了从数据库编译动态 HTML 字符串的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

情况

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

页面指令

angular.module('myApp.directives').directive('myPage', function ($compile) {返回 {templateUrl: 'page.html',限制:'E',编译:函数编译(元素,属性,transclude){//当前什么都不做返回 {前:功能preLink(范围,元素,属性,控制器){//当前什么都不做},帖子:函数postLink(范围,元素,属性,控制器){//当前什么都不做}}}};});

页面指令的模板(page.html"来自上面的 templateUrl 属性)

页面控制器

angular.module('myApp').controller('PageCtrl', function ($scope) {$scope.pageContent = '';$scope.$on( "receivedPageContent", function(event, args) {console.log('数据库调用后收到的新页面内容');$scope.pageContent = args.htmlStrFromDB;});});

那行得通.我们看到来自 DB 的页面 HTML 在浏览器中呈现得很好.当用户翻到下一页时,我们会看到下一页的内容,依此类推.到目前为止一切顺利.

问题

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

在我们的数据库中

第 1 页的内容:

<p>这是一张很酷的狮子照片.<img src="lion.png";ng-click="doSomethingAwesone('lion', 'showImage')";>点击他查看大图.</p>

第 2 页的内容:

这是一条蛇.<img src="snake.png";ng-click="doSomethingAwesone('snake', 'playSound')";>点击让他发出嘶嘶声.</p>

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

页面控制器

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

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

从抽象意义上讲,我想您可能会说我们正在尝试在 Angular 应用程序中动态嵌套 Angular 块,并且需要能够将它们交换进和交换出.

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

解决方案

ng-bind-html-unsafe 仅将内容呈现为 HTML.它不会将 Angular 范围绑定到结果 DOM.为此,您必须使用 $compile 服务.我创建了 this plunker 来演示如何使用 $compile 创建一个呈现动态的指令由用户输入并绑定到控制器范围的 HTML.来源贴在下面.

demo.html

<html ng-app="app"><头><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><身体><h1>编译动态 HTML</h1><div ng-controller="MyController"><textarea ng-model="html"></textarea><div dynamic="html"></div>

</html>

script.js

var app = angular.module('app', []);app.directive('dynamic', function ($compile) {返回 {限制:'A',替换:真的,链接:函数(范围、元素、属性){scope.$watch(attrs.dynamic, function(html) {ele.html(html);$compile(ele.contents())(scope);});}};});函数 MyController($scope) {$scope.click = function(arg) {alert('点击' + arg);}$scope.html = '<a ng-click="click(1)" href="#">点击我</a>';}

The Situation

Nested within our Angular app is a directive called Page, backed by a controller, which contains a div with an ng-bind-html-unsafe attribute. This is assigned to a $scope var called 'pageContent'. This var gets assigned dynamically generated HTML from a database. When the user flips to the next page, a called to the DB is made, and the pageContent var is set to this new HTML, which gets rendered onscreen through ng-bind-html-unsafe. Here's the code:

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 ("page.html" from the templateUrl property above)

<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;
        });

});

That works. We see the page's HTML from the DB rendered nicely in the browser. When the user flips to the next page, we see the next page's content, and so on. So far so good.

The Problem

The problem here is that we want to have interactive content inside of a page's content. For instance, the HTML may contain a thumbnail image where, when the user clicks on it, Angular should do something awesome, such as displaying a pop-up modal window. I've placed Angular method calls (ng-click) in the HTML strings in our database, but of course Angular isn't going to recognize either method calls or directives unless it somehow parses the HTML string, recognizes them and compiles them.

In our DB

Content for Page 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>

Content for Page 2:

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

Back in the Page controller, we then add the corresponding $scope function:

Page controller

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

I can't figure out how to call that 'doSomethingAwesome' method from within the HTML string from the DB. I realize Angular has to parse the HTML string somehow, but how? I've read vague mumblings about the $compile service, and copied and pasted some examples, but nothing works. Also, most examples show dynamic content only getting set during the linking phase of the directive. We would want Page to stay alive throughout the life of the app. It constantly receives, compiles and displays new content as the user flips through pages.

In an abstract sense, I guess you could say we are trying to dynamically nest chunks of Angular within an Angular app, and need to be able to swap them in and out.

I've read various bits of Angular documentation multiple times, as well as all sorts of blog posts, and JS Fiddled with people's code. I don't know whether I'm completely misunderstanding Angular, or just missing something simple, or maybe I'm slow. In any case, I could use some advice.

解决方案

ng-bind-html-unsafe only renders the content as HTML. It doesn't bind Angular scope to the resulted DOM. You have to use $compile service for that purpose. I created this plunker to demonstrate how to use $compile to create a directive rendering dynamic HTML entered by users and binding to the controller's scope. The source is posted below.

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>';
}

这篇关于从数据库编译动态 HTML 字符串的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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