【问题标题】:Populate table with ng-repeat and check matching header data使用 ng-repeat 填充表并检查匹配的标题数据
【发布时间】:2016-04-17 05:17:28
【问题描述】:

我有很多年用于填充表格标题行,并且我有一个用于填充表格的对象。 我需要在相应的年份标题下填充正确的年份数据,所以我需要检查对象中的年份(Y)是否对应于标题数组中的年份,如果不是,那么我需要添加一个空细胞。对象按年份排序。最好的方法是什么? 这是fiddle

控制器

 var app = angular.module("testModule", []);
 app.controller('testController', function($scope) {
 $scope.headerYears = [2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020];

$scope.rows = [{
  "Name": "Name1",
  "Col": [{
    "Y": 2013,
    "M": 25711
  }, {
    "Y": 2014,
    "M": 26095
  }, {
    "Y": 2015,
    "M": 23641
  }, {
    "Y": 2016,
    "M": 22224
  }, {
    "Y": 2017,
    "M": 21968
  }, {
    "Y": 2018,
    "M": 23820
  }, {
    "Y": 2019,
    "M": 26673
  }, {
    "Y": 2020,
    "M": 29329.5
  }]
}, {
  "Name": "Name2",
  "Col": [{
    "Y": 2013,
    "M": 83
  }, {
    "Y": 2014,
    "M": 461
  }, {
    "Y": 2015,
    "M": 1067
  }, {
    "Y": 2016,
    "M": 1120
  }, {
    "Y": 2017,
    "M": 1050
  }, {
    "Y": 2018,
    "M": 600
  }, {
    "Y": 2019,
    "M": 475
  }, {
    "Y": 2020,
    "M": 481
  }]
}, {
  "Name": "Name3",
  "Col": [{
    "Y": 2013,
    "M": 25794
  }, {
    "Y": 2014,
    "M": 26556
  }, {
    "Y": 2015,
    "M": 24708
  }, {
    "Y": 2016,
    "M": 23424
  }, {
    "Y": 2017,
    "M": 23297
  }, {
    "Y": 2018,
    "M": 24412.5
  }, {
    "Y": 2019,
    "M": 27090.5
  }, {
    "Y": 2020,
    "M": 29754.5
  }]
 }]
});

HTML

<table border="1" data-ng-app="testModule" data-ng-controller="testController">
   <thead>
    <tr>
      <th ng-repeat="i in headerYears">{{i}}</th>
    </tr>
  </thead>
  <tbody>
    <tr ng-repeat="row in rows">
      <td ng-repeat="item in row.Col">{{item.M}}{{item.Y}}</td>
    </tr>
  </tbody>

【问题讨论】:

  • 根据我的说法,您应该编写应用程序逻辑代码,例如根据headerYears同步所有rows Col数据。

标签: javascript angularjs


【解决方案1】:

我会在 DOM 中做一个 ng-if

<table border="1" data-ng-app="testModule" data-ng-controller="testController">
  <thead>
    <tr>
      <th ng-repeat="i in headerYears">{{i}}</th>
    </tr>
  </thead>
  <tbody>
    <tr >
      <td ng-repeat="i in headerYears" >{{i}}  
      <span ng-repeat="row in rows"></span> 
      <span ng-repeat="item in row.Col">{{item.Y}} </span>
      </td>     
    </tr>
  </tbody>
</table>

编辑:您可以将 NG-IF 添加到跨度中,例如 span ng-if="item.Y==i" 和另一个跨度 ng-if="item.Y != i"

【讨论】:

  • 这是最简单的,允许我修改后的输出。我不确定使用这种方法会有什么后果..
【解决方案2】:

由于 row.col 的长度可以小于、大于或等于 headerYears 长度,因此您必须确保表格在列上具有一致性。

这意味着对于每一行,您必须重复 headerYears 以创建相同的列大小。

看看我创建的plunker,它可能会为您提供解决方案。

另外,最好创建一个新的对象数组,这些对象绑定到控制器中提供的年份,然后 ng-repeat 到这个新数组。

恕我直言,这将提供更清洁的 DOM,并且可以更轻松地维护。

我添加了一个过滤器,以便读取列数据并返回适合每种情况的数据。

 app.filter('testFilter', function() {
    return function(col, header) {
       if (!col ){
        return "Empty";
       } 
       if (!header){
        return "Empty"; 
       }


       var returnVal="Empty Item";
       angular.forEach(col, function(colItem){
         if(header===colItem.Y) {
            returnVal = colItem.M+" "+colItem.Y;
        }
       });

    return returnVal;

   }
});

我还更改了 DOM,现在它看起来像下面这样

<tbody>
   <tr ng-repeat="row in rows">
      <td ng-repeat="i in headerYears">
         {{row.Col | testFilter:i }}
      </td>
   </tr>
</tbody>

【讨论】:

  • 这似乎是迄今为止最合适的答案。但是,如果我想在 colItem 中显示更多属性,我想在 中显示它们并且我想以不同的方式设置它们并可能将它们关闭,那么我需要类似 colItem.M span>colItem.Y ...如果我从过滤器返回整个对象,例如returnVal=colItem;如何在 DOM 中访问它?我希望我的问题有意义..
  • 是的,您的问题很有道理。由于您希望控制在 标记内自定义 DOM,如果我在您的位置上,我将为该作业创建一个指令,在整个对象上具有隔离范围并使用它,如下面的@987654322 所示@ 您始终可以使用指令的 templateUrl 功能,这样您就可以清楚地了解正在发生的事情。这样,您还可以为每个单元添加一些功能,例如 CRUD 操作
【解决方案3】:

这很好用,比为您要显示的每个值构建自定义过滤器更好(即,您可以将任何您想要的 HTML 放入 TD 中,然后像平常一样使用 {{item.myProperty}})。享受吧!

它把你所有的数据都放到一个与标题匹配的格式中,让 JS 做它最擅长的事情,然后把干净的数据提供给 Angular。希望对您有所帮助!

//START OF GOOD CODE
$scope.rows = null;

(function(){
  var raw = [{ /** this is all your current "rows" data, just moved**/ }];

  var bucketize = function(col) {
      var data = new Array();
      for (var i = 0; i < $scope.headerYears.length; i++) {
          data.push({}); //initialize to match headerYears setup
          for (var j = 0; j < col.length; j++) {
              if (col[j].Y == $scope.headerYears[i]) {
                  data[i] = col[j]; //replace initialized value with real data
              }
          }
      }
      return data;
  };

  var rows = new Array();

  for (var x = 0; x < raw.length; x++) {
    var row = raw[x];
    row.Col = bucketize(row.Col); //sort data and format it for our desired HTML        
    rows.push(row);
  }

  $scope.rows = rows; //give the scrubbed data to Angular
})();
//END OF GOOD CODE

--编辑--

以下创建了一个无限摘要循环,因为它在每次调用 bucketize() 函数时返回一个新的 Array()。相反,在将数据提供给 Angular 之前清理数据(见上文)。您可以在 AJAX 成功处理程序中执行此操作,甚至可以像我上面那样使用 SEAF。

//NOTE THIS IS BAD, DUE TO INFINITE LOOP CAUSED BY "new Array();"
...
<td ng-repeat="item in bucketize(row.Col)">{{item.Y}}</td>
...
$scope.bucketize = function(col) {
    var data = new Array();
    for (var i = 0; i < $scope.headerYears.length; i++) {
        data.push({}); //initialize to match headerYears setup
        for (var j = 0; j < col.length; j++) {
            if (col[j].Y == $scope.headerYears[i]) {
                data[i] = col[j]; //replace initialized value with real data
            }
        }
    }
    return data;
};
//END OF BAD CODE
  • 基隆

【讨论】:

  • 我什至只是在第一个 for() 循环中构建数据,使用 "data = new Array(); ... for... data.push({}); .. .” 只是为了确保它始终与可变的标题完全匹配......但无论如何。就像我说的,希望对您有所帮助!
  • 它确实有效,但不幸的是在浏览器中返回 docs.angularjs.org/error/$rootScope/infdig 错误。
  • 好收获!我没有看控制台,只是看 HTML 输出。发生这种情况是因为每次迭代都会返回一个名为“数据”的新对象,该对象随后会触发一组全新的摘要。我更新了代码以在 Angular 之外工作。我仍然强烈推荐这种方法——它基本上和你接受的答案做同样的事情,但它依靠 JS 使 JS 数据正确——并依靠 Angular 使 HTML 与 JS 数据匹配——这正是每个人应该做什么。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-11
  • 2023-03-25
相关资源
最近更新 更多