Cách sử dụng ng-repeat mà không có phần tử html


142

Tôi cần sử dụng ng-repeat(trong AngularJS) để liệt kê tất cả các phần tử trong một mảng.

Sự phức tạp là mỗi phần tử của mảng sẽ biến đổi thành một, hai hoặc ba hàng của một bảng.

Tôi không thể tạo html hợp lệ, nếu ng-repeatđược sử dụng trên một phần tử, vì không có loại phần tử lặp lại nào được phép giữa <tbody><tr>.

Ví dụ: nếu tôi sử dụng ng-repeat trên <span>, tôi sẽ nhận được:

<table>
  <tbody>
    <span>
      <tr>...</tr>
    </span>
    <span>
      <tr>...</tr>
      <tr>...</tr>
      <tr>...</tr>
    </span>
    <span>
      <tr>...</tr>
      <tr>...</tr>
    </span>
  </tbody>
</table>          

Đó là html không hợp lệ.

Nhưng những gì tôi cần được tạo ra là:

<table>
  <tbody>
    <tr>...</tr>
    <tr>...</tr>
    <tr>...</tr>
    <tr>...</tr>
    <tr>...</tr>
    <tr>...</tr>
  </tbody>
</table>          

trong đó hàng đầu tiên được tạo bởi phần tử mảng đầu tiên, ba hàng tiếp theo bởi phần thứ hai và thứ năm và thứ sáu bởi phần tử mảng cuối cùng.

Làm cách nào tôi có thể sử dụng ng-repeat theo cách sao cho phần tử html bị ràng buộc 'biến mất' trong khi kết xuất?

Hoặc có một giải pháp khác cho điều này?


Làm rõ: Cấu trúc được tạo nên như sau. Mỗi phần tử mảng có thể tạo giữa 1-3 hàng của bảng. Câu trả lời lý tưởng nên hỗ trợ các hàng 0-n cho mỗi phần tử mảng.

<table>
  <tbody>
    <!-- array element 0 -->
    <tr>
      <td>One row item</td>
    </tr>
    <!-- array element 1 -->
    <tr>
      <td>Three row item</td>
    </tr>
    <tr>
      <td>Some product details</td>
    </tr>
    <tr>
      <td>Customer ratings</td>
    </tr>
    <!-- array element 2 -->
    <tr>
      <td>Two row item</td>
    </tr>
    <tr>
      <td>Full description</td>
    </tr>
  </tbody>
</table>          

Có lẽ bạn nên sử dụng "thay thế: đúng"? Xem điều này: stackoverflow.com/questions/11426114/

Ngoài ra, tại sao bạn không thể sử dụng ng-repeat trên tr?

2
@ Mẹ ơi, vì "mỗi phần tử của mảng sẽ biến đổi thành một, hai hoặc ba hàng của một bảng". Nếu tôi sử dụng ng-repeat trên thì trtôi sẽ nhận được một hàng cho mỗi phần tử mảng, theo như tôi hiểu.
fadedbee

1
Ok, tôi hiểu rồi. Bạn không thể làm phẳng mô hình trước khi bạn sử dụng nó trong bộ lặp?

@ Mẹ ơi, không. Các 1-3 trđược tạo bởi một phần tử mảng không có cùng cấu trúc.
fadedbee

Câu trả lời:


66

Cập nhật: Nếu bạn đang sử dụng Angular 1.2+, hãy sử dụng ng-repeat-start . Xem câu trả lời của @ jmagnusson.

Nếu không, làm thế nào về việc đặt ng-repeat trên tbody? (AFAIK, không có nhiều <tbody> s trong một bảng.)

<tbody ng-repeat="row in array">
  <tr ng-repeat="item in row">
     <td>{{item}}</td>
  </tr>
</tbody>

62
Mặc dù điều này có thể hoạt động về mặt kỹ thuật, nhưng thật đáng thất vọng khi câu trả lời cho trường hợp sử dụng phổ biến này là bạn phải tiêm đánh dấu tùy ý (nếu không không cần thiết). Tôi có cùng một vấn đề (các nhóm hàng lặp lại - một tiêu đề TR với một hoặc nhiều TR con, được lặp lại dưới dạng một nhóm). Có vẻ tầm thường với các công cụ mẫu khác, có vẻ như hacky tốt nhất với Angular.
Brian Moeskau

1
Đã đồng ý. Tôi đang cố gắng lặp lại các yếu tố DT + DD. không có cách nào để làm điều đó mà không thêm một yếu tố gói không hợp lệ
David Lin

2
@DavidLin, trong Angular v1.2 (bất cứ khi nào nó xuất hiện) bạn sẽ có thể lặp lại qua nhiều yếu tố, ví dụ: dt và dd: youtube.com/watch?v=W13qDdJDHp8&t=17m28s
Mark Rajcok

Điều này được xử lý một cách tao nhã trong KnockoutJS bằng cách sử dụng cú pháp luồng điều khiển không chứa: knoutoutjs.com/documentation/foreach-binding.html . Hy vọng sẽ thấy Angular làm điều gì đó tương tự sớm.
Nhà Cory

3
Câu trả lời này đã lỗi thời, thay vào đó hãy sử dụng ng-repeat-start
iwein

73

Kể từ AngularJS 1.2, có một lệnh được gọi là ng-repeat-startchính xác những gì bạn yêu cầu. Xem câu trả lời của tôi trong câu hỏi này để biết mô tả về cách sử dụng nó.


Angular đã bắt kịp, đây là giải pháp thích hợp bây giờ.
iwein

33

Nếu bạn sử dụng ng> 1.2, đây là một ví dụ về việc sử dụng ng-repeat-start/endmà không tạo các thẻ không cần thiết:

<html>
  <head>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
    <script>
      angular.module('mApp', []);
    </script>
  </head>
  <body ng-app="mApp">
    <table border="1" width="100%">
      <tr ng-if="0" ng-repeat-start="elem in [{k: 'A', v: ['a1','a2']}, {k: 'B', v: ['b1']}, {k: 'C', v: ['c1','c2','c3']}]"></tr>

      <tr>
        <td rowspan="{{elem.v.length}}">{{elem.k}}</td>
        <td>{{elem.v[0]}}</td>
      </tr>
      <tr ng-repeat="v in elem.v" ng-if="!$first">
        <td>{{v}}</td>
      </tr>

      <tr ng-if="0" ng-repeat-end></tr>
    </table>
  </body>
</html>

Điểm quan trọng: đối với các thẻ được sử dụng cho ng-repeat-startng-repeat-endđặt ng-if="0", để không được chèn vào trang. Theo cách này, nội dung bên trong sẽ được xử lý chính xác như trong knout (sử dụng các lệnh trong <!--...-->) và sẽ không có rác.


sau khi đặt ng-if = "0", nó sẽ báo lỗi không thể tìm thấy kết hợp ng-repeat-end.
MCTS vikky

19

Bạn có thể muốn làm phẳng dữ liệu trong bộ điều khiển của mình:

function MyCtrl ($scope) {
  $scope.myData = [[1,2,3], [4,5,6], [7,8,9]];
  $scope.flattened = function () {
    var flat = [];
    $scope.myData.forEach(function (item) {
      flat.concat(item);
    }
    return flat;
  }
}

Và sau đó trong HTML:

<table>
  <tbody>
    <tr ng-repeat="item in flattened()"><td>{{item}}</td></tr>
  </tbody>
</table>

1
Không, không phải vậy. Gọi một hàm bên trong biểu thức ngRepeat hoàn toàn không được khuyến nghị
Nik

Trong trường hợp của tôi, tôi đã cần phải thêm một tách cho mỗi phần tử nơi index = 0 và! ng-repeat-start, ng-repeat-endPhá vỡ thiết kế của tôi, vì vậy giải pháp là tạo ra một biến phụ thêm đối tượng tách này trước mỗi phần tử và lặp var mới: <div class="c477_group"> <div class="c477_group_item" ng-repeat="item in itemsWithSeparator" ng-switch="item.id" ng-class="{'-divider' : item.id == 'SEPARATOR'}"> <div class="c478" ng-switch-when="FAS"/> <div class="c478" ng-switch-when="SEPARATOR" /> <div class="c479" ng-switch-default /> </div> </div>
hermeslm

6

Trên đây là chính xác nhưng đối với một câu trả lời tổng quát hơn thì không đủ. Tôi cần lồng nhau lặp lại, nhưng vẫn ở cùng mức html, nghĩa là viết các phần tử trong cùng một cha mẹ. Mảng thẻ chứa (các) thẻ cũng có một mảng thẻ. Nó thực sự là một cái cây.

[{ name:'name1', tags: [
  { name: 'name1_1', tags: []},
  { name: 'name1_2', tags: []}
  ]},
 { name:'name2', tags: [
  { name: 'name2_1', tags: []},
  { name: 'name2_2', tags: []}
  ]}
]

Vì vậy, đây là những gì tôi cuối cùng đã làm.

<div ng-repeat-start="tag1 in tags" ng-if="false"></div>
    {{tag1}},
  <div ng-repeat-start="tag2 in tag1.tags" ng-if="false"></div>
    {{tag2}},
  <div ng-repeat-end ng-if="false"></div>
<div ng-repeat-end ng-if="false"></div>

Lưu ý ng-if = "false" ẩn div bắt đầu và kết thúc.

Nó nên in

tên1, tên1_1, tên1_2, tên2, tên2_1, tên2_2,


1

Tôi chỉ muốn bình luận, nhưng danh tiếng của tôi vẫn còn thiếu. Vì vậy, tôi đang thêm một giải pháp khác cũng giải quyết vấn đề. Tôi thực sự muốn bác bỏ tuyên bố của @bmoeskau rằng việc giải quyết vấn đề này đòi hỏi một giải pháp 'hacky at best', và vì điều này đã xuất hiện gần đây trong một cuộc thảo luận mặc dù bài đăng này đã được 2 năm, tôi muốn thêm vào sở hữu hai xu:

Như @btford đã chỉ ra, dường như bạn đang cố gắng biến một cấu trúc đệ quy thành một danh sách, vì vậy bạn nên làm phẳng cấu trúc đó thành một danh sách trước. Giải pháp của ông thực hiện điều đó, nhưng có ý kiến ​​cho rằng việc gọi hàm bên trong khuôn mẫu là không phù hợp. Nếu đó là sự thật (thành thật mà nói, tôi không biết) sẽ không yêu cầu thực thi chức năng trong bộ điều khiển chứ không phải chỉ thị?

dù bằng cách nào, html của bạn yêu cầu một danh sách, vì vậy phạm vi kết xuất nó nên có danh sách đó để làm việc. bạn chỉ cần làm phẳng cấu trúc bên trong bộ điều khiển của bạn. một khi bạn có một mảng $ scope.rows, bạn có thể tạo bảng với một lần lặp ng đơn giản. Không hack, không liên kết, chỉ đơn giản là cách nó được thiết kế để làm việc.

Chỉ thị Angenses không thiếu chức năng. Họ chỉ đơn giản là buộc bạn phải viết html hợp lệ. Một đồng nghiệp của tôi đã có một vấn đề tương tự, trích dẫn @bmoeskau để hỗ trợ cho những lời chỉ trích về các tính năng tạo khuôn / tạo khuôn. Khi xem xét vấn đề chính xác, hóa ra anh ta chỉ đơn giản muốn tạo một thẻ mở, sau đó là một thẻ đóng ở một nơi khác, v.v. giống như trong những ngày xưa tốt đẹp khi chúng ta sẽ ghép html của mình từ các chuỗi .. phải không? Không.

đối với việc làm phẳng cấu trúc thành một danh sách, đây là một giải pháp khác:

// assume the following structure
var structure = [
    {
        name: 'item1', subitems: [
            {
                name: 'item2', subitems: [
                ],
            }
        ],
    }
];
var flattened = structure.reduce((function(prop,resultprop){
    var f = function(p,c,i,a){
        p.push(c[resultprop]);
        if (c[prop] && c[prop].length > 0 )
          p = c[prop].reduce(f,p);
        return p;
    }
    return f;
})('subitems','name'),[]);

// flattened now is a list: ['item1', 'item2']

điều này sẽ làm việc cho bất kỳ cấu trúc giống như cây có các mục phụ. Nếu bạn muốn toàn bộ vật phẩm thay vì một tài sản, bạn có thể rút ngắn chức năng làm phẳng hơn nữa.

Hy vọng rằng sẽ giúp.


Đẹp một. Mặc dù nó không giúp tôi trực tiếp nhưng nó đã mở mang đầu óc tôi cho một giải pháp khác. Cảm ơn rất nhiều!
Marian Zburlea

0

cho một giải pháp thực sự hiệu quả

html

<remove  ng-repeat-start="itemGroup in Groups" ></remove>
   html stuff in here including inner repeating loops if you want
<remove  ng-repeat-end></remove>

thêm một lệnh angular.js

//remove directive
(function(){
    var remove = function(){

        return {    
            restrict: "E",
            replace: true,
            link: function(scope, element, attrs, controller){
                element.replaceWith('<!--removed element-->');
            }
        };

    };
    var module = angular.module("app" );
    module.directive('remove', [remove]);
}());

cho một lời giải thích ngắn gọn,

ng-repeat liên kết chính nó với <remove>phần tử và các vòng lặp như vậy, và vì chúng ta đã sử dụng ng-repeat-start / ng-repeat-end nên nó lặp một khối html không chỉ là một phần tử.

sau đó tùy chỉnh loại bỏ chỉ thị đặt các <remove>yếu tố bắt đầu và kết thúc với<!--removed element-->


-2
<table>
  <tbody>
    <tr><td>{{data[0].foo}}</td></tr>
    <tr ng-repeat="d in data[1]"><td>{{d.bar}}</td></tr>
    <tr ng-repeat="d in data[2]"><td>{{d.lol}}</td></tr>
  </tbody>
</table>

Tôi nghĩ rằng điều này là hợp lệ :)


Trong khi điều này hoạt động, nó sẽ chỉ hoạt động nếu mảng có ba phần tử.
btford

Chỉ cần đảm bảo rằng mảng có 3 phần tử, ngay cả khi chúng là mảng trống (lặp lại với một mảng trống đơn giản là không hiển thị bất cứ thứ gì).
Renan Tomal Fernandes

7
Quan điểm của tôi là OP có thể muốn một giải pháp hoạt động cho số lượng mục khác nhau trong mảng. Tôi giả sử mã hóa "phải có ba mục trong mảng này" vào mẫu sẽ là một giải pháp kém.
btford

Trong bình luận cuối cùng về câu hỏi của mình, ông nói rằng các yếu tố sẽ không có cùng cấu trúc, vì vậy việc mã hóa từng cấu trúc là không thể tránh khỏi.
Renan Tomal Fernandes
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.