【问题标题】:Bind Angularjs to newly created html element dynamically将 Angularjs 动态绑定到新创建的 html 元素
【发布时间】:2013-11-20 23:08:53
【问题描述】:

我有一个包含多个选项卡的选项卡页面,一旦单击调用服务以返回一些数据。其中一些数据返回 html 表单并且非常随机。我想收集那些输入的值并通过服务将数据发送回服务器。我遇到的问题是我无法从动态创建的 html 中的输入元素中获取数据。

我创建了一个Plunker 来说明问题所在。请注意,html 值可以随时更改,因此对 html 进行硬编码将不起作用。这是来自 plunker 的代码,但请查看 plunker 以获得最佳视图。

app.js

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

app.controller('MainCtrl', function($scope, $sce, $compile) {
    $scope.name = 'World';
    $scope.html = "";

    $scope.htmlElement = function(){
        var html = "<input type='text' ng-model='html'></input>";
        return $sce.trustAsHtml(html);
    }

});

index.html

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

  <head>
    <meta charset="utf-8" />
    <title>AngularJS Plunker</title>
    <script>document.write('<base href="' + document.location + '" />');</script>
    <link rel="stylesheet" href="style.css" />
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0-rc.3/angular.js"></script>
    <script src="app.js"></script>
  </head>

  <body ng-controller="MainCtrl">
    <p>Hello {{name}}!</p>

    <div ng-bind-html="htmlElement()"></div>

    {{html}}

  </body>

</html>

【问题讨论】:

  • 为什么要在控制器而不是指令中进行 DOM 修改?
  • 这只是举例。实际的 html 通过服务来自服务器。控制器中没有 DOM 操作。我一直想知道是否可以使用指令和 $compile 来编译 html 并将 html 绑定到模型。
  • 完全可以使用$compile(element.contents())(scope),在此之前您可以将字符串添加到element.html() 方法并在ngModel 上设置$watch,我不知道这是否是您想要的。 ..

标签: angularjs model-binding


【解决方案1】:

一种解决方案是将 ngInclude 与 $templateCache 一起使用,如 Plunker 中所示。

有几点需要注意。

第一个是您可以使用服务获取模板并将其添加到 $templateCache,如 here 所述(复制示例):

myApp.service('myTemplateService', ['$http', '$templateCache', function ($http, $templateCache) {
  $http(/* ... */).then(function (result) {
    $templateCache.put('my-dynamic-template', result);
  });
}]);

然后您可以将其包含在您的模板中,如下所示:

<div ng-include="'my-dynamic-template'"></div>

ngInclude 将允许对 html 字符串进行数据绑定,因此您不需要 ngBindHtml。

第二个是,当 ngInclude 创建一个新范围时,在新创建的范围之外访问 html 属性将无法正常工作,除非您通过父范围上的对象访问它(例如 ng-model="data.html" 而不是ng-model="html"。请注意,在这种情况下,父作用域中的 $scope.data = {} 使 html 可以在 ngInclude 作用域之外访问。

(请参阅this answer,了解为什么您应该始终在 ngModel 中使用点。)


编辑

正如您所指出的,在使用服务返回 HTML 时,ngInclude 选项的用处要小得多。

这是编辑后的plunker,其中包含使用 $compile 的基于指令的解决方案,如上面 David 的评论所示。

相关补充:

app.directive('customHtml', function($compile, $http){
  return {
    link: function(scope, element, attrs) {
      $http.get('template.html').then(function (result) {
        element.replaceWith($compile(result.data)(scope));
      });
    }
  }
})

【讨论】:

  • 我认为这越来越接近了,但并没有真正做到这一点,因为模板仍然需要在应用程序首次运行时应用,并且不能像服务时那样在以后设置通话已完成。我编辑了您的 plunker 以向您显示服务调用不起作用。
  • 确实 :) 上面更新了。
  • @Sarah - 非常感谢。我一直在寻找这样的东西,而您的 Plunker 示例非常棒。我分叉了你的 plunker 并添加了一种附加多个模板文件的方法,这些模板文件将附加到元素中。您可以在以下位置查看:plnkr.co/edit/Ch5uykLwlF8Td2zQEoH9?p=preview
【解决方案2】:

根据莎拉的回答,我创建了一个结构来放置指令

.directive('dynamic', function(AmazonService, $compile) {
  return {
    restrict: 'E',
    link: function(scope, element, attrs) {
      AmazonService.getHTML()
     .then(function(result){
       element.replaceWith($compile(result.data)(scope));
     })
     .catch(function(error){
       console.log(error);
     });
   }
 };
});

在 html 中:

<dynamic></dynamic>

谢谢莎拉,帮了大忙!!!

【讨论】:

    【解决方案3】:

    我有一个带有一些 ng-repeat 的动态表,然后当我尝试用 javascript 回调函数填充一列时,它只给我像 html 文本这样的

    <td class="tableList_"+myValue> "span class=someclass> some_text /span>" </td>
    <td class="tableList_"+myValue> "span class=someclass> some_text /span>" </td>
    <td class="tableList_"+myValue> "span class=someclass> some_text /span>" </td>
    

    所以我用 jquery 解决了我的问题:

    $(".tableListFilas td").each(function() {
        var td_class = $(this).attr("class");
    
        if(td_class == 'tableList_'+titulo)
        {
             var toExtraHtml = $(this).text();
             $(this).html(toExtraHtml);
        }
    });
    

    那么最后的输出就不错了:

    <td class="tableList_COLORS"> <span class=someclass>some_text</span> </td>
    <td class="tableList_COLORS"> <span class=someclass>some_text</span> </td>
    <td class="tableList_COLORS"> <span class=someclass>some_text</span> </td>  
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-08
      • 1970-01-01
      • 1970-01-01
      • 2013-10-23
      相关资源
      最近更新 更多