数据加载的角度指令模板更新

时间:2014-06-27 18:49:09

标签: javascript angularjs

我有一个指令,其数据是通过api调用接收的。该指令本身工作正常,问题出现(我相信),因为该指令是在api调用完成之前加载的。这导致整个shebang不起作用。我得到{{user}}

而不是我预期的输出

我的指示如下:

app.directive('myDirective', function() {
  return {
    restrict: 'A',
    require: '^ngModel',
    scope: {
      ngModel: '=',
    },
    template: '<tbody style="background-color: red;" ng-bind-html="renderHtml(listing_html)"></tbody>',
    controller: ['$scope', '$http', '$sce',
      function($scope, $http, $sce) {
        $scope.listing_html += "<td>{{user.name}}</td>"
        $scope.renderHtml = function(html_code) {
          return $sce.trustAsHtml(html_code);
        };
      }
    ],
    link: function(scope, iElement, iAttrs, ctrl) {
      scope.$watch('ngModel', function(newVal) {
        // This *is* firing after the data arrives, but even then the
        // {{user}} object is populated. And the `user in ngModel` doesn't
        // run correctly either.
        console.log(scope.ngModel);
        scope.listing_html = "<tr ng-repeat='user in ngModel'><td>{{user}}</td></tr>"
      })
    }

  };
});

而我的HTML只是

<table my-directive my-options='{"Name": "name", "Email": "email"}' ng-model='userData'></table>

我已经创建了plunker,其中包含大量评论,希望有助于解释此问题。

此问题非常this one类似,但该解决方案的关键区别不起作用。添加ng-cloak只是让它不显示。 值得注意的是,我一直在使用this作为构建指令的方法的参考。

2 个答案:

答案 0 :(得分:2)

我认为你要让它变得有点复杂。如果您要尝试在其中插入带有Angular表达式的动态HTML,则需要首先使用$ compile服务进行编译(这会将指令等挂接到动态HTML中,然后转换为Angular)。话虽如此,我认为你不需要为你想要完成的事情做到这一点。

看看这个更新的插件:http://plnkr.co/edit/RWcwIhlv3dMbjln4dOyb?p=preview

您可以使用指令中的模板生成所需的动态更改。在我的例子中,我使用ng-repeat来重复提供给指令的用户,以及提供给指令的选项。 ng-repeat进行观察,因此只要更新通过ng-model提供给指令的数据,ng-repeats就会反映这些变化。

<tbody style="background-color: red;">
    <tr><th ng-repeat="option in myOptions">{{option.name}}</th></tr>
    <tr ng-repeat="user in ngModel">
        <td ng-repeat="option in myOptions">{{user[option.value]}}</td>
    </tr>
</tbody>

我在主控制器中定义的选项如下。

$scope.tableOptions = [
  {"name": "Name", "value": "name"}, 
  {"name": "Email", "value": "email"}
];

您可以为指令使用添加其他属性,例如显示顺序等。您甚至可以动态地从选项中删除项目,然后从输出表中删除数据。

让我知道这是否有帮助,或者我是否误解了你想要完成的事情。

答案 1 :(得分:1)

我不是百分百肯定,但我相信ngBindHtml在这种情况下不会帮助你 ngBindHtml用于显示一些“普通”HTML,但您想要显示一些Angular,magic HTML 为此,您需要将$compile HTML格式化为Angular-aware,并将link已编译的HTML格式化为范围。

我使用了以下方法(结果非常好):

controller: function ($scope, $element, $compile) {
  var html = createTmpl(angular.fromJson($scope.myOptions));
  $scope.$watch('ngModel', function (newVal) {
      var elem      = angular.element(html);   // Creating element
      var linkingFn = $compile(elem);          // Compiling element
      linkingFn($scope);                       // Linking element
      $element.html('');                       // Removing previous content
      $element.append(elem);                   // Inserting new content

      // The above is purposedly explicit to highlight what is 
      // going on. It's moe concise equivalent would be:
      //$element.html('').append($compile(html)($scope));
  });

其中createTmpl()被定义为考虑myOptions并返回适当的模板以创建具有标题行(基于myOptions的键)和数据行的表将属性定义为myOptions的值:

function createTmpl(options) {
    // Construct the header-row
    var html = '<tr>';
    angular.forEach(options, function (value, key) {
        html += '<th>' + key + '</th>';
    });
    html += '</tr>\n';

    // Construct the data-rows
    html += '<tr ng-repeat="user in ngModel">';
    angular.forEach(options, function (value, key) {
        html += '<td>{{user' + value + '}}</td>';
    });
    html += '</tr>\n';

    // Return the template
    return html;
}

另请参阅此 short demo <子> 当然,这仅用于演示目的,并不处理生产就绪应用程序应该处理的所有内容(例如,考虑错误,缺少属性,myOptions和诸如此类的变化)。


<强>更新

我的竞争非常激烈,所以我对上面的代码做了一些修改,以支持嵌套属性。例如。给定具有以下结构的对象:

user = {
    name: 'ExpertSystem',
    company: {
        name: 'ExpertSystem S.A.',
        ranking: 100
    }
};

我们可以将公司名称显示在表格的列中,只需定义myOptions,如下所示:

myOptions='{"Company name": "company.name"}