ChatGPT解决这个技术问题 Extra ChatGPT

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

情况

嵌套在我们的 Angular 应用程序中的是一个名为 Page 的指令,由一个控制器支持,该控制器包含一个具有 ng-bind-html-unsafe 属性的 div。这被分配给一个名为“pageContent”的 $scope 变量。这个 var 从数据库中获得动态生成的 HTML。当用户翻到下一页时,会调用 DB,并将 pageContent 变量设置为这个新的 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
                    }
                }
            }
        };
    });

页面指令的模板(来自上述 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;
        });

});

这样可行。我们看到来自 DB 的页面 HTML 在浏览器中很好地呈现。当用户翻到下一页时,我们会看到下一页的内容,以此类推。到目前为止,一切都很好。

问题

这里的问题是我们希望在页面内容中包含交互式内容。例如,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>

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

页面控制器

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

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

在抽象的意义上,我想你可以说我们正在尝试在 Angular 应用程序中动态嵌套 Angular 块,并且需要能够将它们交换进出。

我已经多次阅读各种 Angular 文档,以及各种博客文章,以及 JS Fiddled with people's code。我不知道我是否完全误解了 Angular,或者只是错过了一些简单的东西,或者我很慢。无论如何,我可以使用一些建议。

$compile 和围绕它的文档博客让我觉得我也很慢——尽管我觉得我的 js 很强大——我想如果我真的掌握了这个,我会做一个白痴风格的博客——那是我的专长!

B
Buu

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

演示.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>

脚本.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>';
}

非常感谢,布欧!创建属性指令和添加范围监视功能是我缺少的两件事。既然这行得通,我想我会再次阅读指令和 $compile,以更好地了解幕后发生的事情。
我也是!Angular 团队真的可以改进这方面的文档。
$compile(ele.contents())(scope); - 此行解决了我不编译动态添加的角度组件的问题。谢谢。
teplateURL 中的@BuuNguyen 假设如果您使用 ng-bind-html 包含一些动态 htmnl 页面,那么使用 compile 不起作用会从其他不安全的内容中产生错误,使用 trustAsHTml 只会删除不安全的错误不编译,有什么建议吗?
我喜欢这个例子,但它没有让我的工作。我有一个 switch 语句,它是由于用户选择而发生的,所以它是动态的。根据我想插入包含指令的html。如果我将其置于自然引导阶段,该指令将起作用。但是我有这个根本没有触发 --- case 'info': $scope.htmlString = $sce.trustAsHtml('
dddzzz
');休息; --- 当我想做类似的事情时 --- $compile($sce.trustAsHtml('
dddzzz
'));有关解决方法等的任何想法...
k
krillgar

在 Angular 1.2.10 中,行 scope.$watch(attrs.dynamic, function(html) { 返回一个无效字符错误,因为它试图查看 attrs.dynamic 的值,即 html 文本。

我通过从范围属性中获取属性来解决这个问题

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

您好,如果我使用 element.html,它会返回 TypeError:无法调用 null 的方法“insertBefore”。因此,经过一番谷歌搜索后,我发现我必须使用 element.append 但如果我在多个地方使用该指令 - 它会生成多重 HTML。所以 2 个指令生成 4 个相同的 HTML 代码。感谢您的回答。
我不会用 append 代替你,今晚我会看看,我会回复你的。老实说,我在页面的很多地方都使用了这个指令,没有任何问题。我将尝试重现该问题,然后再与您联系。
@AlexandrosSpyropoulos 我只是测试了一下,发现我的代码运行良好,即使是 1.2.12。我认为您可能错过了 HTML 中的声明
? (通过该声明, $watch 监视范围内的 'html' 属性,而不是您提到的实际 HTML,因此应该没有无效的字符错误。)如果没有,请给我发送显示它不起作用的 plunkr,我会看看有什么问题。
你也许是对的。那时我一直在期待,html 实际上是一个包含 html :P 的变量。不过,在指令上设置范围是个好主意。 umur.io/…
$compile(ele.contents())(scope); - 此行解决了我不编译动态添加的角度组件的问题。谢谢。
k
kwerle

在谷歌讨论组中找到。为我工作。

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

g
georgeawg

您可以使用

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>

谢谢!这对我有帮助。但是,您需要包含 ngSanitize 和 angular-sanitize.js:var myApp = angular.module('myApp', ['ngSanitize']);
在将引导图标绑定到材料 md-list 跨度元素期间,这对我也有用
R
Ramesh M

试试下面的代码,通过 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);