如何使用引导程序将 ng-repeat 数据拆分为三列

IT技术 javascript angularjs angularjs-ng-repeat
2021-01-11 21:03:34

我在我的代码中使用 ng-repeat 我有基于 ng-repeat 的“n”个文本框。我想将文本框与三列对齐。

这是我的代码

<div class="control-group" ng-repeat="oneExt in configAddr.ext">
    {{$index+1}}. 
    <input type="text" name="macAdr{{$index+1}}" 
           id="macAddress" ng-model="oneExt.newValue" value=""/>
</div>
6个回答

最可靠和技术上正确的方法是在控制器中转换数据。这是一个简单的块函数和用法。

function chunk(arr, size) {
  var newArr = [];
  for (var i=0; i<arr.length; i+=size) {
    newArr.push(arr.slice(i, i+size));
  }
  return newArr;
}

$scope.chunkedData = chunk(myData, 3);

那么您的视图将如下所示:

<div class="row" ng-repeat="rows in chunkedData">
  <div class="span4" ng-repeat="item in rows">{{item}}</div>
</div>

如果您在 中有任何输入ng-repeat,您可能希望在修改或提交数据时取消分块/重新加入数组。这是在 a 中的样子$watch,以便数据始终以原始合并格式可用:

$scope.$watch('chunkedData', function(val) {
  $scope.data = [].concat.apply([], val);
}, true); // deep watch

许多人更喜欢使用过滤器在视图中完成此操作。这是可能的,但只能用于显示目的!如果您在此过滤视图中添加输入,则会导致可以解决但不美观或不可靠的问题

这个过滤器的问题在于它每次都返回新的嵌套数组。Angular 正在观察过滤器的返回值。过滤器第一次运行时,Angular 知道该值,然后再次运行它以确保它完成更改。如果两个值相同,则循环结束。如果不是,过滤器将一次又一次地触发,直到它们相同,或者 Angular 意识到正在发生无限摘要循环并关闭。因为新的嵌套数组/对象以前没有被 Angular 跟踪,所以它总是看到与以前不同的返回值。要修复这些“不稳定”过滤器,您必须将过滤器包装在一个memoize函数中。lodash有一个memoize函数,最新版本的 lodash 也包含一个chunk函数,所以我们可以非常简单地使用创建这个过滤器npmmodule并使用browserify编译脚本webpack

记住:只显示!如果您使用输入,请在控制器中过滤!

安装 lodash:

npm install lodash-node

创建过滤器:

var chunk = require('lodash-node/modern/array/chunk');
var memoize = require('lodash-node/modern/function/memoize');

angular.module('myModule', [])
.filter('chunk', function() {
  return memoize(chunk);
});

这是带有此过滤器的示例:

<div ng-repeat="row in ['a','b','c','d','e','f'] | chunk:3">
  <div class="column" ng-repeat="item in row">
    {{($parent.$index*row.length)+$index+1}}. {{item}}
  </div>
</div>

垂直订购商品

1  4
2  5
3  6

关于垂直列(从上到下列表)而不是水平列(从左到右),确切的实现取决于所需的语义。不均匀划分的列表可以以不同的方式分布。这是一种方法:

<div ng-repeat="row in columns">
  <div class="column" ng-repeat="item in row">
    {{item}}
  </div>
</div>
var data = ['a','b','c','d','e','f','g'];
$scope.columns = columnize(data, 3);
function columnize(input, cols) {
  var arr = [];
  for(i = 0; i < input.length; i++) {
    var colIdx = i % cols;
    arr[colIdx] = arr[colIdx] || [];
    arr[colIdx].push(input[i]);
  }
  return arr;
}

然而,获取列的最直接、最简单的方法是使用CSS 列

.columns {
  columns: 3;
}
<div class="columns">
  <div ng-repeat="item in ['a','b','c','d','e','f','g']">
    {{item}}
  </div>
</div>
谢谢你的帮助。但是在 angular 中使用带有 ui-chart 的 carousel 无法绘制图表 bt carousel 工作正常。我的代码是 <carousel interval="myInterval"> <slide ng-repeat="milestone in mileStone | split:4" active="slide.active"> <div class ="col-md-3" ng-repeat="里程碑中的里程碑 1"> <div style="text-align:center;"> <div ui-chart="data" chart-options="chartOptions"></div> </div> </div> </slide > </carousel> 我将我的范围变量初始化为里程碑 JSON 数据。
2021-03-13 21:03:34
@bahadir 我更新了答案以使其更加清晰。看看如果你制作一个只返回[]vs[[]]的过滤器会发生什么[{}]嵌套的数组/对象使 Angular 在每个 上看到不同的结果filter,并不断重复寻找结果以保持不变(稳定)。
2021-03-17 21:03:34
@m59 现在这个函数在第一行a b c第二行显示数据d e f我可以在第二列和第三列的a b 第一列c d显示e f吗?谢谢
2021-03-18 21:03:34
你真的是垃圾评论:) 自己试试吧。var x = [1,2,3]; var y = [1,2,3]; console.log(x === y);深度检查意味着对字符串进行字符串化和比较,这是有风险的,因为对象可能无法字符串化,或者单独递归地检查每个属性。我认为 Angular可以为过滤器实现它,但我确信他们没有这样做是有充分理由的。可能是因为他们主要是为了简单修改数据集而使用过滤器,而不是对结构进行彻底修改。
2021-04-01 21:03:34
@Ifch0o1 如果那是[].concat.call([], val). 你必须考虑做什么applyval是一个数组数组,我们希望将其中的每个数组作为参数传递给concat我认为您关注的是 的上下文[],这不是这里的重点。我们想要的是[].concat(val[1], val[2], val[3], etc),所以我们需要apply([], val)
2021-04-08 21:03:34

这个解决方案非常简单:

JSON:

[{id:"1",name:"testA"},{id:"2",name:"test B"},{id:"3",name:"test C"},{id:"4",name:"test D"},{id:"5",name:"test E"}]

HTML:

<div ng-controller="MyCtrl">
  <table>
    <tr ng-repeat="item in items" ng-switch on="$index % 3">
      <td ng-switch-when="0">
        {{items[$index].id}} {{items[$index].name}}
      </td>
      <td ng-switch-when="0">
        <span ng-show="items[$index+1]">
          {{items[$index+1].id}} {{items[$index+1].name}}
        </span>
      </td>
      <td ng-switch-when="0">
        <span ng-show="items[$index+2]">    
          {{items[$index+2].id}} {{items[$index+2].name}}
        </span>
      </td>
    </tr>
  </table>
</div>

小提琴演示

在此处输入图片说明

最佳答案!并使用本机指令做需要的事情!恭喜!
2021-03-26 21:03:34
此解决方案有效,但就最佳实践而言,您可能不应该使用表格来定义标记中的布局:)
2021-03-28 21:03:34
这是迄今为止最好的解决方案。使用新框架需要时间才能找到所有的怪癖,但 ng-switch 是天赐之物
2021-04-03 21:03:34
正如@DaveCooper 提到的,这里有一个没有表格的替代布局:plnkr.co/edit/81oj8mHaNyfQpCmRBWO4?p=preview考虑表格数据的表格,但除此之外,对于移动设备和可变屏幕尺寸来说,这是一个更好的布局。
2021-04-04 21:03:34
如果您要使用 div 而不是表格,则可以ng-switch-when="0"在外部 div 上放置一次,而不是放在所有 3 个项目上。
2021-04-09 21:03:34

一个干净、适应性强的解决方案,不需要数据操作

HTML:

<div class="control-group" class="label"
    ng-repeat="oneExt in configAddr.ext"
    ng-class="{'new-row': startNewRow($index, columnBreak) }">
    {{$index+1}}. 
    <input type="text" name="macAdr{{$index+1}}" 
       id="macAddress{{$index}}" ng-model="oneExt.newValue" />
</div>

CSS:

.label {
    float: left;
    text-align: left;
}
.new-row {
    clear: left;
}

JavaScript:

$scope.columnBreak = 3; //Max number of colunms
$scope.startNewRow = function (index, count) {
    return ((index) % count) === 0;
};

这是一个简单的解决方案,用于将数据动态呈现为行和列,无需操作您尝试显示的数据数组。另外,如果您尝试调整浏览器窗口的大小,您可以看到网格动态适应屏幕/div 的大小。

(我还为您的 id 添加了一个 {{$index}} 后缀,因为如果您不这样做,ng-repeat 将尝试创建多个具有相同 id 的元素。)

一个类似的工作示例

我相信 OP 想要 Twitter Bootstrap 行/列的标记,但这可能对某人有帮助。但是,您需要将代码和解释放在答案中。仅链接答案将被删除。
2021-03-29 21:03:34
Big +1 for不需要数据操作这非常适合我想要使用 ng-repeat 将跨度中的数据分成 2 列的需求,这样我的 Bootstrap 模式就不会那么长!我很惊讶这实现起来是多么简单!<span ng-repeat="z in waiverModalLinks" ng-class="{'new-row':startNewRow($index, columnBreak)}" class="{{z.id}}"><a href="{{z.link}}{{z.title}}">{{z.title}}</a></span>那是在`modal-body'里面。
2021-04-02 21:03:34
@m59 更新答案。谢谢你的建议
2021-04-06 21:03:34

m59的回答很好。我不喜欢它的一件事是它使用divs 来表示可能是表数据的内容。

因此,结合 m59 的过滤器(上面某处的答案),这里是如何在表格中显示它。

<table>
    <tr class="" ng-repeat="rows in foos | chunk:2">
        <td ng-repeat="item in rows">{{item}}</td>
    </tr>
</table>

下面是一个更简单的方法:

<table>
    <tr ng-repeat="item in lists" ng-hide="$index%2!==0">
        <td>
            <label>{{ lists[$index].name}}</label>
        </td>
        <td ng-hide="!lists[$index+1]">
            <label>{{ lists[$index+1].name}}</label>
        </td>
    </tr>
</table>

Cumulo Nimbus 的回答对我很有用,但我希望这个网格由一个 div 包裹,当列表太长时,它可以显示滚动条。

为了实现这一点,我style="height:200px; overflow:auto"在表格周围添加了一个 div,使其显示为单列。

现在适用于数组长度为 1。

当数组中只有一项时,它不会显示第一行本身。要解决此更改 ng-hide="$index%2!==0"
2021-04-09 21:03:34