วิธีการใช้ ng-repeat โดยไม่มีองค์ประกอบ html


142

ฉันต้องใช้ng-repeat(ใน AngularJS) เพื่อแสดงรายการองค์ประกอบทั้งหมดในอาร์เรย์

ภาวะแทรกซ้อนคือองค์ประกอบของอาร์เรย์จะเปลี่ยนเป็นหนึ่งสองหรือสามแถวของตาราง

ฉันไม่สามารถสร้าง html ที่ถูกต้องถ้าng-repeatจะถูกใช้ในองค์ประกอบเช่นชนิดขององค์ประกอบการทำซ้ำไม่ได้รับอนุญาตระหว่างและ<tbody><tr>

ตัวอย่างเช่นถ้าฉันใช้ ng-repeat on <span>ฉันจะได้รับ:

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

อันไหนไม่ถูกต้อง html

แต่สิ่งที่ฉันต้องสร้างคือ:

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

โดยที่แถวแรกถูกสร้างขึ้นโดยองค์ประกอบแถวลำดับที่สามแถวที่สามที่สองและที่ห้าและที่หกจากองค์ประกอบอาร์เรย์สุดท้าย

ฉันจะใช้ ng-repeat ในลักษณะที่องค์ประกอบ html ที่ถูกผูกไว้ 'หายไป' ในระหว่างการเรนเดอร์ได้อย่างไร?

หรือมีวิธีแก้ไขปัญหานี้อีกหรือไม่


การชี้แจง: โครงสร้างที่สร้างขึ้นควรมีลักษณะดังนี้ แต่ละองค์ประกอบอาร์เรย์สามารถสร้างระหว่าง 1-3 แถวของตาราง คำตอบควรสนับสนุนแถว 0-n ต่อองค์ประกอบอาร์เรย์

<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>          

บางทีคุณควรใช้ "replace: true"? ดูสิ่งนี้: stackoverflow.com/questions/11426114/…

นอกจากนี้ทำไมคุณไม่สามารถใช้ ng-repeat บน tr เองได้?

2
@Tommy เพราะ "แต่ละองค์ประกอบของอาร์เรย์จะเปลี่ยนเป็นหนึ่งสองหรือสามแถวของตาราง" ถ้าฉันใช้ ng-repeat กับtrฉันจะได้รับหนึ่งแถวต่อองค์ประกอบอาร์เรย์เท่าที่ฉันเข้าใจ
fadedbee

1
โอเคฉันเข้าใจแล้ว คุณไม่สามารถทำแบบจำลองให้เรียบก่อนที่จะใช้ใน repeater หรือไม่

@ ทอมมี่ไม่ 1-3 trs ซึ่งสร้างโดยองค์ประกอบอาร์เรย์หนึ่งไม่มีโครงสร้างเดียวกัน
fadedbee

คำตอบ:


66

ปรับปรุง:ถ้าคุณกำลังใช้ 1.2 + เชิงมุมใช้NG-ซ้ำเริ่มต้น ดูคำตอบของ @ jmagnusson

ไม่งั้นจะทำ ng-repeat บน tbody ได้ยังไง (AFAIK มันก็โอเคที่จะมี <tbody> หลายอันในตารางเดียว)

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

62
ในขณะที่มันใช้งานได้ในทางเทคนิคมันน่าผิดหวังมากที่คำตอบสำหรับกรณีการใช้งานทั่วไปนี้คือคุณต้องฉีดมาร์กอัป (ไม่จำเป็น) โดยไม่จำเป็น ฉันมีปัญหาเดียวกัน (กลุ่มของแถวซ้ำ - หนึ่งส่วนหัว TR กับหนึ่งหรือมากกว่าเด็ก TRs ซ้ำเป็นกลุ่ม) เล็กน้อยกับเอนจิ้นแม่แบบอื่น ๆ แฮ็คที่ดีที่สุดกับ Angular ดูเหมือน
Brian Moeskau

1
ตกลง ฉันพยายามที่จะทำซ้ำในองค์ประกอบ DT + DD ไม่มีวิธีในการทำเช่นนั้นโดยไม่เพิ่มองค์ประกอบการห่อที่ไม่ถูกต้อง
David Lin

2
@DavidLin ใน Angular v1.2 (ทุกครั้งที่ออกมา) คุณจะสามารถทำซ้ำองค์ประกอบหลายอย่างเช่น dt และ dd: youtube.com/watch?v=W13qDdJDHp8&t=17m28s
Mark Rajcok

นี้จะถูกจัดการอย่างหรูหราใน KnockoutJS ใช้ containerless การควบคุมการไหลของไวยากรณ์: knockoutjs.com/documentation/foreach-binding.html หวังว่าจะได้เห็น Angular ทำอะไรบางอย่างที่คล้ายกันในไม่ช้า
Cory House

3
คำตอบนี้ล้าสมัยใช้ ng-repeat-start แทน
iwein

73

ในฐานะของ AngularJS 1.2 มีคำสั่งเรียกng-repeat-startว่าทำสิ่งที่คุณขออย่างแน่นอน ดูคำตอบของฉันในคำถามนี้สำหรับคำอธิบายวิธีการใช้งาน


เชิงมุมจมนี่เป็นทางออกที่เหมาะสมในขณะนี้
iwein

33

หากคุณใช้ ng> 1.2 นี่คือตัวอย่างของการใช้ng-repeat-start/endโดยไม่สร้างแท็กที่ไม่จำเป็น:

<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>

จุดสำคัญ: สำหรับแท็กที่ใช้สำหรับng-repeat-startและng-repeat-endตั้งค่าng-if="0"เพื่อไม่ให้แทรกในหน้าเว็บ ด้วยวิธีนี้เนื้อหาภายในจะได้รับการจัดการตรงตามที่เป็นใน knockoutjs (ใช้คำสั่งใน<!--...-->) และจะไม่มีขยะ


หลังจากตั้งค่า ng-if = "0" จะเกิดข้อผิดพลาดว่าไม่สามารถค้นหา ng-repeat-end ที่ตรงกันได้
vikky MCTS

19

คุณอาจต้องการทำให้ข้อมูลในชุดควบคุมของคุณแบนเรียบ:

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;
  }
}

แล้วใน HTML:

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

1
ไม่มันไม่ใช่. ไม่แนะนำให้เรียกใช้ฟังก์ชันภายในนิพจน์ ngRepeat
Nik

ในกรณีของฉันฉันไม่จำเป็นต้องเพิ่มคั่นสำหรับแต่ละองค์ประกอบที่ดัชนี = 0 และ! ng-repeat-start, ng-repeat-endทำลายการออกแบบของฉันเพื่อแก้ปัญหาคือการสร้างตัวแปรเสริมเพิ่มวัตถุคั่นนี้ก่อนที่แต่ละองค์ประกอบและย้ำ var ใหม่: <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

ข้างต้นถูกต้อง แต่สำหรับคำตอบทั่วไปมันไม่เพียงพอ ฉันต้องการซ้อน ng-repeat แต่อยู่ในระดับ html เดียวกันหมายถึงเขียนองค์ประกอบในพาเรนต์เดียวกัน อาร์เรย์แท็กมีแท็กที่มีอาร์เรย์แท็กด้วย มันเป็นต้นไม้จริงๆ

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

ดังนั้นนี่คือสิ่งที่ฉันทำในที่สุด

<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>

สังเกต ng-if = "false" ที่ซ่อน div เริ่มต้นและจุดสิ้นสุด

มันควรจะพิมพ์

name1, name1_1, name1_2, name2, name2_1, name2_2,


1

ฉันต้องการแสดงความคิดเห็น แต่ชื่อเสียงของฉันยังขาดอยู่ ดังนั้นฉันกำลังเพิ่มโซลูชันอื่นซึ่งแก้ปัญหาได้เช่นกัน ฉันต้องการลบล้างคำสั่งของ @bmoeskau จริง ๆ ว่าการแก้ปัญหานี้ต้องใช้วิธี 'แฮ็กที่ดีที่สุด' และเนื่องจากสิ่งนี้เกิดขึ้นเมื่อเร็ว ๆ นี้ในการอภิปรายแม้ว่าโพสต์นี้จะมีอายุ 2 ปีฉันต้องการเพิ่มของฉัน ของตัวเองสองเซ็นต์:

@btford ได้ชี้ให้เห็นคุณดูเหมือนจะพยายามเปลี่ยนโครงสร้างแบบเรียกซ้ำให้เป็นรายการดังนั้นคุณควรทำให้โครงสร้างนั้นแบนลงในรายการก่อน วิธีแก้ปัญหาของเขาทำเช่นนั้น แต่มีความเห็นว่าการเรียกใช้ฟังก์ชันภายในเทมเพลตนั้นไม่เหมาะสม หากเป็นจริง (สุจริตฉันไม่รู้) จะไม่ต้องการเพียงแค่การเรียกใช้ฟังก์ชันในคอนโทรลเลอร์แทนที่จะเป็นคำสั่ง?

ไม่ว่าจะด้วยวิธีใด html ของคุณต้องมีรายการดังนั้นขอบเขตที่แสดงผลควรมีรายการนั้นทำงานด้วย คุณต้องเรียบโครงสร้างภายในคอนโทรลเลอร์ของคุณ เมื่อคุณมีอาร์เรย์ $ scope.rows คุณสามารถสร้างตารางด้วยการทำซ้ำแบบง่าย ๆ ไม่มีการแฮ็คไม่มีความไร้เดียงสาเพียงวิธีที่มันถูกออกแบบมาให้ทำงาน

คำสั่งของ Angulars จะไม่ขาดฟังก์ชั่น พวกเขาเพียงแค่บังคับให้คุณเขียน html ที่ถูกต้อง เพื่อนร่วมงานของฉันมีปัญหาที่คล้ายกันโดยอ้างถึง @ bmoeskau เพื่อสนับสนุนการวิพากษ์วิจารณ์เกี่ยวกับคุณลักษณะมุมมอง / การแสดงผลเทมเพลต เมื่อมองปัญหาที่แท้จริงเขาก็แค่อยากสร้าง open-tag จากนั้นก็ปิด tag ที่อื่นและอื่น ๆ เช่นในวันเก่า ๆ ที่เราจะเชื่อมโยง html ของเรากับสตริง .. ใช่ไหม? ไม่

สำหรับโครงสร้างแบนลงในรายการนี่คือวิธีแก้ปัญหาอื่น:

// 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']

สิ่งนี้จะใช้ได้กับโครงสร้างแบบต้นไม้ที่มีรายการย่อย หากคุณต้องการไอเท็มทั้งหมดแทนที่จะเป็นพร็อพเพอร์ตี้คุณสามารถย่อฟังก์ชั่นการย่อให้มากขึ้นได้

หวังว่าจะช่วย


ทำได้ดีนี่. ในขณะที่มันไม่ได้ช่วยฉันโดยตรงมันเปิดใจของฉันไปที่ทางออกอื่น ขอบคุณมาก!
Marian Zburlea

0

สำหรับทางออกที่ใช้งานได้จริง

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>

เพิ่มคำสั่ง 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]);
}());

สำหรับคำอธิบายสั้น ๆ

ng-repeat ผูกตัวเองกับ<remove>องค์ประกอบและลูปตามที่ควรและเพราะเราได้ใช้ ng-repeat-start / ng-repeat-end มันลูปบล็อกของ html ไม่ได้เป็นเพียงองค์ประกอบ

จากนั้นคำสั่งลบที่กำหนดเองจะวาง<remove>องค์ประกอบเริ่มต้นและสิ้นสุดด้วย<!--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>

ฉันคิดว่ามันถูกต้อง :)


ในขณะที่ใช้งานได้จะทำงานเฉพาะเมื่ออาร์เรย์มีองค์ประกอบสามอย่าง
btford

ตรวจสอบให้แน่ใจว่าอาร์เรย์มี 3 องค์ประกอบแม้ว่าจะเป็นอาร์เรย์ว่างเปล่า (ng-repeat กับอาร์เรย์ว่างเปล่าก็ไม่ต้องแสดงผลอะไรเลย)
Renan Tomal Fernandes

7
ประเด็นของฉันคือว่า OP อาจต้องการโซลูชันที่ทำงานกับจำนวนตัวแปรของรายการในอาร์เรย์ ฉันคิดว่า hardcoding "ต้องมีสามรายการในอาร์เรย์นี้" ในแม่แบบจะเป็นทางออกที่ดี
btford

ในความคิดเห็นล่าสุดเกี่ยวกับคำถามของเขาเขาบอกว่าองค์ประกอบจะไม่มีโครงสร้างเดียวกันดังนั้นการเข้ารหัสฮาร์ดแต่ละโครงสร้างจึงหลีกเลี่ยงไม่ได้
Renan Tomal Fernandes
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.