【问题标题】:Angular passing scope to ng-include角度传递范围到 ng-include
【发布时间】:2014-10-29 23:24:24
【问题描述】:

我有一个我写的控制器,我在我的应用程序的多个地方使用ng-includeng-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;
            });
        });
});

【问题讨论】:

  • 一个解决方案是创建一个新指令,正如我在 answer 中所说的那样
  • kbjr,请记住,ng-repeat 是一个创建新子作用域的指令,并且 ng-include 也是......除此之外,ng-init 可以与 ng- 结合使用包括...恐怕您必须显示控制器(ItemController 的代码)文件和模板文件(item.html)才能完全理解场景以及为什么不工作。

标签: javascript angularjs angularjs-ng-repeat angularjs-ng-include angularjs-ng-init


【解决方案1】:

聚会迟到了,但在不执行愚蠢指令的情况下,有一点角度“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 变量数次。

Here is a plunker to achieve what you want

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

引入一个扩展当前范围的指令,让您有一个独立的范围用于所有 ng-include。 因此,项目引用在所有扩展范围内都被保留并且是唯一的。

【讨论】:

  • 谢谢,这很好用。提示:我发现当添加一个在加载(异步)后动态填充的值时,它不起作用,因为在评估 include 语句时它不可用,但是将 if 语句更改为 ng-if="myVariable " 这样它只会在填充 myVariable 解决该问题时加载。
  • 使用 onload 并不干净,因为它在全局范围内设置了一个变量。请看我的回答。
  • @Tanin 这就是我注入 ng-if 指令的原因,以便为每个 ng-include 创建一个唯一的隔离子范围并避免变量名冲突。
【解决方案2】:

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

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

Link to the documentation.

编辑

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

$scope.dataHolder = {};

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

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

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

【讨论】:

  • 这似乎也不起作用。我认为这可能与项目正在异步加载的事实有关,并且 onload 可能只运行一次?
  • @kbjr 嗯,我刚刚在我的应用程序中对此进行了测试,它确实有效。我认为您关于异步加载项目的结论可能是解释。例如,如果我传入一个字符串值,它就可以工作。
  • 这是我根据文档中的示例创建的plunkr。在“template1”中,我引用了一个名为 bar 的变量,该变量是从范围变量 foo 初始化的。
  • @kbjr 实际上在我的简单示例中甚至没有必要使用onload,因为ng-include 创建的范围继承了父范围的属性。因此,您可以通过在父作用域中初始化一个对象来解决这个问题,然后在加载异步数据时,更改您初始化的对象的属性。我将编辑我的答案...
  • 我仍然需要在模板中引用这个新值,对吧?所以我没有在模板中使用item,而是使用dataHolder.item。当我需要使用 ng-repeat 时,这会破坏另一个用例。
【解决方案3】:

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

scope: {
    item: '='
}

【讨论】:

  • 投了赞成票,因为 ng-init="" 和 onload="" 似乎不起作用,尽管它们应该......可惜我们每次都需要为这个简单的创建一个指令任务。
  • 每次都写一个特定的指令并不理想。请看我的解决方案。希望对您有所帮助!
【解决方案4】:

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

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

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

【讨论】:

    【解决方案5】:

    使用 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 读取对象并将这些成员添加到自己的本地范围内。

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

    【讨论】:

    • Uncaught SyntaxError: Unexpected token &gt;
    • 这是 Coffeescript,不是 Javascript。
    • 这种方式更优雅,避免乱扔全局范围
    【解决方案6】:
    我认为

    ng-init 更适合这个。

    <div ng-include='myFile.html' ng-init="myObject = myCtrl.myObject; myOtherObject=myCtrl.myOtherObject"/>
    

    【讨论】:

    • 请考虑编辑您的帖子,以添加更多关于您的代码的作用以及它为何能解决问题的说明。一个大部分只包含代码的答案(即使它正在工作)通常不会帮助 OP 理解他们的问题。
    • 这不适用于使用不同变量多次绑定同一个模板
    【解决方案7】:

    上述内容不适用于二级属性,例如&lt;div ng-include-template=... ng-include-variables="{ id: var.id }"&gt;。注意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];
                });
              }
            }
          );
    
        }
      };
    });
    

    【讨论】:

    • 这应该是 ngInclude 本身的一部分! ng-include 是 Angular 中模块化的基本单元,它应该有一个干净的参数化方式。
    • 此解决方案负责处理第一个解决方案没有的模型更改...很棒!
    【解决方案8】:

    可能对 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 },
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-04
      • 2016-01-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多