【问题标题】:Something like "with variable" in AngularJS?AngularJS中的“带变量”之类的东西?
【发布时间】:2015-02-14 12:30:14
【问题描述】:

样本控制器数据:

$scope.items = [{ id: 1, name: 'First'}, { id: 2, name: 'Second'}];

在 Angular 中有什么东西可以让下面的代码像“带变量”一样工作吗?

<ul>
    <li data-ng-repeat="items">{{id}} {{name}}</li>
</ul>

代替:

<ul>
    <li data-ng-repeat="i in items">{{i.id}} {{i.name}}</li>
</ul>

请随意提出一个更易于理解的标题/问题。

【问题讨论】:

  • 您实际上可以为此编写自定义指令。
  • 如果我不那么累的话,我会尝试一个完整的答案,但我认为你需要做的是创建一个使用transclude: 'element' 并调用$scope.$watchCollection 的指令。 ng-repeat 做这些事情。

标签: angularjs


【解决方案1】:

参考AngularngRepeat document,目前只支持以下表达式。

  1. 表达式变量
  2. (键,值)在表达式中
  3. tracking_expression 中的表达式跟踪变量
  4. 作为 alias_expression 的表达式变量

这意味着,您不能简单地使用ng-repeat="items" 来迭代集合。

顺便说一句,ng-repeat 将为每个元素创建一个单独的作用域,并将variable(key, value) 绑定到新创建的作用域。因此,您所指的“带变量”不是 Angular 内置的。您需要为此功能创建自定义指令。

【讨论】:

    【解决方案2】:

    我的首选答案是“不要这样做”,但如果做不到这一点,因为这很有趣,这里有一个概念证明,由 this question 协助,主要改编自 this blog post

    app.directive('myRepeat', function(){
      return {
        transclude : 'element',
        compile : function(element, attrs, linker){
          return function($scope, $element, $attr){
            var collectionExpr = attrs.myRepeat;
            var parent = $element.parent();
            var elements = [];
    
            // $watchCollection is called everytime the collection is modified
            $scope.$watchCollection(collectionExpr, function(collection) {
              var i, block, childScope;
    
              // check if elements have already been rendered
              if(elements.length > 0){
                // if so remove them from DOM, and destroy their scope
                for (i = 0; i < elements.length; i++) {
                  elements[i].el.remove();
                  elements[i].scope.$destroy();
                };
                elements = [];
              }
    
              for (i = 0; i < collection.length; i++) {
                // create a new scope for every element in the collection.
                childScope = $scope.$new();
    
                // ***
                // This is the bit that makes it behave like a `with` 
                // statement -- we assign the item's attributes to the
                // child scope one by one, rather than simply adding
                // the item itself.
                angular.forEach(collection[i], function(v, k) {
                  childScope[k] = v;
                });
                // ***
    
                linker(childScope, function(clone){
                  // clone the transcluded element, passing in the new scope.
                  parent.append(clone); // add to DOM
                  block = {};
                  block.el = clone;
                  block.scope = childScope;
                  elements.push(block);
                });
              };
            });
          }
        }
      }
    });
    

    然后这会做你想做的事:

    app.controller("myController", function($scope, $http) {
      $scope.items = [
        {a: 123, b: 234},
        {a: 321, b: 432}
      ];
    });
    

    使用你想要的 HTML 结构:

    <div ng-controller="myController">
      <ul>
        <li my-repeat="items">
          {{ a }} {{ b }}
        </li>
      </ul>
    </div>
    

    请注意,鉴于属性被复制到子作用域中,而不是被引用,如果对视图进行更改,它们不会影响模型(即父 items 列表),严重限制了该指令。你可以用一个额外的scope.$watch 来解决这个问题,但使用ng-repeat 几乎肯定不会像通常使用的那样大惊小怪。

    【讨论】:

      【解决方案3】:

      我不明白为什么其他用户告诉你你想要的东西必须通过新指令来完成。这是一个有效的 sn-p。

      angular.module("Snippet",[]).controller("List",["$scope",function($scope){
          $scope.items = [{ id: 1, name: 'First'}, { id: 2, name: 'Second'}];
        }]);
      <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
      
      <body ng-app="Snippet" ng-controller="List as list">
      
        <ul>
          <!-- Iterating the array -->
          <li ng-repeat="item in items">
            <!-- Iterating each object of the array -->
            <span ng-repeat="(key,value) in item">{{value}} </span>
          </li>
        </ul>
        
      </body>

      简单地说,你需要通过ng-repeat迭代数组的元素,然后你就可以对检索到的对象item做你想做的事了。例如,如果您想显示它的值,就像您的问题一样,那么新的ng-repeat 可以完成工作。

      【讨论】:

        猜你喜欢
        • 2020-04-02
        • 2016-12-21
        • 1970-01-01
        • 1970-01-01
        • 2012-05-19
        • 2017-09-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多