41

我有一个我写的控制器,我在我的应用程序的多个地方使用ng-includeand ng-repeat,就像这样:

<div
  ng-repeat="item in items"
  ng-include="'item.html'"
  ng-controller="ItemController"
></div>

在控制器/模板中,我希望item值存在,整个事情都是围绕这个想法构建的。不过,现在我需要以稍微不同的方式使用控制器,没有ng-repeat, 但仍然需要能够传入item. 我看到ng-init并认为它可以做我需要的,像这样:

<div
  ng-init="item = leftItem"
  ng-include="'item.html'"
  ng-controller="ItemController"
></div>
<div
  ng-init="item = rightItem"
  ng-include="'item.html'"
  ng-controller="ItemController"
></div>

但这似乎不起作用。任何人都知道如何在像这样的单个实例中为范围传递变量?

编辑:上面的控制器正在加载leftItemrightItem值,如下所示:

.controller('MainController', function($scope, ItemModel) {
    ItemModel.loadItems()
        .then(function(items) {
            $scope.$apply(function() {
                $scope.leftItem = items.left;
                $scope.rightItem = items.right;
            });
        });
});
4

8 回答 8

37

派对迟到了,但有一点角度“hack”可以在不执行愚蠢指令的情况下实现这一目标。

添加一个内置指令将在您使用 ng-include 的任何地方扩展控制器的范围(如 ng-if),实际上可以让您隔离所有包含范围的变量名称。

所以:

<div ng-include="'item.html'"
  ng-if="true"
  onload="item = rightItem">
</div>
<div ng-include="'item.html'"
  ng-if="true"
  onload="item = leftItem">
</div>

然后,您可以使用不同的项目将模板 item.html 多次绑定到 item 变量。

这是一个实现你想要的东西

问题是该项目在控制器范围内不断变化,该控制器范围仅包含一个对项目变量的引用,该变量在每个 onload 指令时都会被删除。

引入一个扩展当前范围的指令,让您拥有所有 ng-include 的隔离范围。因此,项目引用在所有扩展范围内都被保留和唯一。

于 2015-09-11T22:13:08.660 回答
33

您可以使用提供的onload属性ngInclude来执行此操作:

<div ng-include="'item.html'"
     ng-controller="ItemController"
     onload="item = rightItem">
</div>

链接到文档

编辑

尝试在父范围内做这样的事情:

$scope.dataHolder = {};

然后当接收到异步数据时,将数据存储在dataHolder

$scope.dataHolder.leftItem = items.leftItem;
$scope.dataHolder.rightItem = items.rightItem;

现在,当ng-include加载模板时,它将创建一个继承父级属性的子范围。所以$scope.dataHolder将在这个子作用域中定义(最初作为一个空对象)。但是当接收到异步数据时,对空对象的引用应该包含新接收到的数据。

于 2014-09-05T04:47:29.590 回答
17

我最终将其重写为指令并在范围内绑定所需的值

scope: {
    item: '='
}
于 2014-09-05T07:29:58.240 回答
13

喜欢@Tanin 的回答。一次以非常优雅的方式解决了这么多问题。对于像我这样不了解 Coffeescript 的人,这里是 javascript...

注意:由于我太新而无法理解,此代码要求您引用一次模板名称,而不是 ng-include 要求两次引用您的模板名称,即。<div ng-include-template="template-name.html" ... >代替<div ng-include-template="'template-name.html'" ... >

.directive('ngIncludeTemplate', function() {  
  return {  
    templateUrl: function(elem, attrs) { return attrs.ngIncludeTemplate; },  
    restrict: 'A',  
    scope: {  
      'ngIncludeVariables': '&'  
    },  
    link: function(scope, elem, attrs) {  
      var vars = scope.ngIncludeVariables();  
      Object.keys(vars).forEach(function(key) {  
        scope[key] = vars[key];  
      });  
    }  
  }  
})
于 2016-01-11T10:11:50.313 回答
11

使用 onload 不是一个干净的解决方案,因为它会在全局范围内乱扔垃圾。如果你有更复杂的东西,它就会开始失败。

ng-include 不是那么可重用,因为它可以访问全局范围。这有点奇怪。

以上不属实。带有 onload 的 ng-if 不会乱扔全局范围

我们也不想为每种情况编写特定的指令。

制作通用指令而不是 ng-include 是一种更清洁的解决方案。

理想的用法如下所示:

<div ng-include-template="'item.html'" ng-include-variables="{ item: 'whatever' }"></div>
<div ng-include-template="'item.html'" ng-include-variables="{ item: variableWorksToo }"></div>

该指令是:

.directive(
  'ngIncludeTemplate'
  () ->
    {
      templateUrl: (elem, attrs) -> attrs.ngIncludeTemplate
      restrict: 'A'
      scope: {
        'ngIncludeVariables': '&'
      }
      link: (scope, elem, attrs) ->
        vars = scope.ngIncludeVariables()
        for key, value of vars
          scope[key] = value
    }
)

您可以看到该指令不使用全局范围。相反,它从 ng-include-variables 读取对象并将这些成员添加到它自己的本地范围内。

我希望这是你想要的;它干净而通用。

于 2015-10-25T18:12:37.957 回答
4

我认为 ng-init 对此更好。

<div ng-include='myFile.html' ng-init="myObject = myCtrl.myObject; myOtherObject=myCtrl.myOtherObject"/>
于 2015-11-13T16:19:26.593 回答
4

以上不适用于二级属性,例如<div ng-include-template=... ng-include-variables="{ id: var.id }">. 注意var.id.

更新指令(丑陋,但有效):

.directive('ngIncludeTemplate', function() {
  return {
    templateUrl: function(elem, attrs) { return attrs.ngIncludeTemplate; },
    restrict: 'A',
    scope: {
      'ngIncludeVariables': '&'
    },
    link: function(scope, elem, attrs) {
      var cache = scope.ngIncludeVariables();
      Object.keys(cache).forEach(function(key) {
        scope[key] = cache[key];
      });

      scope.$watch(
        function() {
          var val = scope.ngIncludeVariables();
          if (angular.equals(val, cache)) {
            return cache;
          }
          cache = val;
          return val;
        },
        function(newValue, oldValue) {
          if (!angular.equals(newValue, oldValue)) {
            Object.keys(newValue).forEach(function(key) {
              scope[key] = newValue[key];
            });
          }
        }
      );

    }
  };
});
于 2016-04-24T22:31:59.657 回答
1

Mike 和 Tanin 的答案可能有明显的更新 - 如果您使用内联模板:

<script type="text/ng-template" id="partial">{{variable}}</script>

<div ng-include-template="'partial'" ng-include-variables="{variable: variable}"></div>

然后,在指令 ngIncludeTemplate 中,替换

templateUrl: function(elem, attrs) { return attrs.ngIncludeTemplate; },  

template: function(elem, attrs) { return document.getElementById(attrs.ngIncludeTemplate.split("'")[1]).innerHTML },
于 2016-04-07T10:40:50.883 回答