AngularJS ng-repeat โดยไม่มีองค์ประกอบ html


91

ฉันกำลังใช้โค้ดชิ้นนี้เพื่อแสดงรายการ:

<ul ng-cloak>
    <div ng-repeat="n in list">
        <li><a href="{{ n[1] }}">{{ n[0] }}</a></li>
        <li class="divider"></i>
    </div>
    <li>Additional item</li> 
</ul>

อย่างไรก็ตาม<div>องค์ประกอบดังกล่าวก่อให้เกิดข้อบกพร่องในการแสดงผลเล็กน้อยในบางเบราว์เซอร์ ฉันอยากทราบว่ามีวิธีทำ ng-repeat โดยไม่ใช้ div container หรือวิธีอื่นเพื่อให้ได้ผลเช่นเดียวกัน


คุณกำลังพูดถึงประเด็นการเรนเดอร์อะไร
Ja͢ck

ตัวแบ่ง Li ตัวสุดท้ายดูเหมือนจะหนาขึ้นเล็กน้อยเหมือนซ้อนกัน (chrome win7) นี่อาจเป็นปัญหา css อย่างไรก็ตามฉันต้องการทราบว่าสามารถแก้ไขในเชิงมุมได้หรือไม่ สำหรับการเปรียบเทียบ knockoutJS อนุญาตการผูกคอนเทนเนอร์โดยใช้ <! - ->
nehz

ฉันเห็นฉันใช้ phptal ที่ฝั่งเซิร์ฟเวอร์และพวกเขามีแท็ก tal: block เพื่อจุดประสงค์นี้โดยเฉพาะ :) เดาว่า DOM ไม่ยอมรับแท็กประเภทใหม่ที่ยากกว่าด้วยเชิงมุม
เสมอไป

คุณสามารถอัปเดต html เพื่อแสดงวิธีการใช้htmlAppendคำสั่งได้หรือไม่?
นิค

เสร็จแล้ว ... ทำเมื่อครู่นี้ แต่ฉันจำได้ว่ามันใช้งานได้
nehz

คำตอบ:


104

ในฐานะที่เป็นแอนดี้ Joslin กล่าวว่าพวกเขาทำงานเกี่ยวกับการแสดงความคิดเห็นตาม NG-ซ้ำแต่เห็นได้ชัดว่ามีปัญหาเบราว์เซอร์มากเกินไป โชคดีที่ AngularJS 1.2 เพิ่มการรองรับในตัวสำหรับการทำซ้ำโดยไม่ต้องเพิ่มองค์ประกอบลูกด้วยคำสั่งใหม่ng-repeat-startและng-repeat-end.

นี่คือตัวอย่างเล็กน้อยสำหรับการเพิ่มหน้า Bootstrap :

<ul class="pagination">
  <li>
    <a href="#">&laquo;</a>
  </li>
  <li ng-repeat-start="page in [1,2,3,4,5,6]"><a href="#">{{page}}</a></li>
  <li ng-repeat-end class="divider"></li>
  <li>
    <a href="#">&raquo;</a>
  </li>
</ul>

ตัวอย่างการทำงานเต็มรูปแบบที่สามารถพบได้ที่นี่

จอห์น Lindquist นอกจากนี้ยังมีวิดีโอสอนมากกว่านี้ได้ที่หน้า egghead.io ของเขายอดเยี่ยม


3
สิ่งนี้ไม่ต้องการการพิมพ์องค์ประกอบหรือไม่?
hitautodestruct

2
ฉันสับสนอย่างมากว่าสิ่งนี้ประสบความสำเร็จได้อย่างไรใน <li ng-repeat = "page ใน [1,2,3,4,5,6]"> <a href="#"> {{page}} </ a > </li> -edit: ไม่เป็นไรฉันคิดว่าฉันเข้าใจแล้ว
Shadaez

6
ฉันเข้าใจว่าคุณแค่พยายามสาธิตng-repeat-start/endแต่นี่เป็นตัวอย่างที่น่าสับสนและกรณีการใช้งานที่ไม่ถูกต้อง ng-repeatควรใช้มาตรฐานที่นี่เนื่องจากโค้ดของคุณแสดงค่าว่างพิเศษliสำหรับแต่ละรายการ คุณควรพูดถึงสิ่งนั้นในโพสต์ของคุณ
GFoley83

2
@ GFoley83 คุณถูกต้อง แต่ดูเหมือนว่าเขาต้องการองค์ประกอบพิเศษสำหรับการทำซ้ำแต่ละครั้งซึ่งเป็นสิ่งที่ขาดไม่ได้ng-repeat-startเลย ฉันจะเพิ่มdividerคลาส html ในคำตอบเพื่อให้ชัดเจนยิ่งขึ้น
jmagnusson

1
ng-repeat-startและng-repeat-endมีความสับสนเล็กน้อย เอกสารเชิงมุมช่วยได้: https://docs.angularjs.org/api/ng/directive/ngRepeat#special-repeat-start-and-end-points
perilandmishap

30

KnockoutJS containerless binding syntax

โปรดอดทนกับฉันสักครู่: KnockoutJS เสนอตัวเลือกที่สะดวกเป็นพิเศษในการใช้ไวยากรณ์การผูกแบบไม่ใช้คอนเทนเนอร์สำหรับการforeachผูกตามที่กล่าวไว้ในหมายเหตุ 4 ของforeachเอกสารการผูก http://knockoutjs.com/documentation/foreach-binding.html

ดังตัวอย่างเอกสาร Knockout คุณสามารถเขียนการผูกของคุณใน KnockoutJS ดังนี้:

<ul>
    <li class="header">Header item</li>
    <!-- ko foreach: myItems -->
        <li>Item <span data-bind="text: $data"></span></li>
    <!-- /ko -->
</ul>

ฉันคิดว่ามันค่อนข้างโชคร้ายที่ AngularJS ไม่มีไวยากรณ์ประเภทนี้


Angular ng-repeat-startและng-repeat-end

ในวิธี AngularJS ในการแก้ng-repeatปัญหาตัวอย่างที่ฉันเจอเป็นประเภท jmagnusson ที่โพสต์ไว้ในคำตอบ (เป็นประโยชน์) ของเขา

<li ng-repeat-start="page in [1,2,3,4,5]"><a href="#">{{page}}</a></li>
<li ng-repeat-end></li>

ความคิดเดิมของฉันเมื่อเห็นไวยากรณ์นี้คือจริงเหรอ? เหตุใด Angular จึงบังคับให้มาร์กอัปพิเศษทั้งหมดนี้ซึ่งฉันไม่ต้องการทำอะไรเลยและมันง่ายกว่ามากใน Knockout แต่แล้วความคิดเห็นของ hitautodestruct ในคำตอบของ jmagnusson เริ่มทำให้ฉันสงสัย: สิ่งที่สร้างขึ้นด้วย ng-repeat-start และ ng-repeat-end ในแท็กแยกกัน?


วิธีที่สะอาดกว่าในการใช้งานng-repeat-startและng-repeat-end

จากการตรวจสอบการยืนยันของ hitautodestruct การเพิ่มng-repeat-endลงในแท็กแยกต่างหากเป็นสิ่งที่ฉันไม่ต้องการทำในกรณีส่วนใหญ่เพราะมันสร้างองค์ประกอบที่ไร้ประโยชน์อย่างเต็มที่ในกรณีนี้<li>รายการที่ไม่มีอะไรอยู่ในนั้น รายการที่มีการแบ่งหน้าของ Bootstrap 3 จะจัดรูปแบบรายการเพื่อให้ดูเหมือนว่าคุณไม่ได้สร้างรายการที่ไม่จำเป็น แต่เมื่อคุณตรวจสอบ html ที่สร้างขึ้นพวกเขาจะอยู่ที่นั่น

โชคดีที่คุณไม่จำเป็นต้องทำอะไรมากเพื่อให้มีโซลูชันที่สะอาดกว่าและ html ในปริมาณที่สั้นลง: เพียงแค่วางng-repeat-endคำประกาศไว้บนแท็ก html เดียวกับที่มีng-repeat-start .

<ul class="pagination">
  <li>
    <a href="#">&laquo;</a>
  </li>    
  <li ng-repeat-start="page in [1,2,3,4,5]" ng-repeat-end><a href="#"></a></li>
  <li>
    <a href="#">&raquo;</a>
  </li>
</ul>

สิ่งนี้ให้ข้อดี 3 ประการ:

  1. แท็ก html น้อยที่จะเขียน
  2. Angular ไม่ได้สร้างแท็กว่างเปล่าที่ไร้ประโยชน์
  3. เมื่ออาร์เรย์ที่จะทำซ้ำว่างเปล่าแท็กที่มีng-repeatจะไม่ถูกสร้างขึ้นทำให้คุณได้รับข้อได้เปรียบเดียวกันกับการผูกแบบไม่ใช้คอนเทนเนอร์ของ Knockout ให้คุณในเรื่องนี้

แต่ยังมีวิธีที่สะอาดกว่า

หลังจากการตรวจสอบต่อไปความคิดเห็นใน GitHub ในเรื่องนี้สำหรับเชิงมุมhttps://github.com/angular/angular.js/issues/1891 ,
คุณไม่จำเป็นต้องใช้งานng-repeat-startและng-repeat-endเพื่อให้บรรลุข้อได้เปรียบเดียวกัน แทนที่จะยกตัวอย่างของ jmagnusson อีกครั้งเราสามารถไป:

<ul class="pagination">
  <li>
    <a href="#">&laquo;</a>
  </li>
  <li ng-repeat="page in [1,2,3,4,5,6]"><a href="#">{{page}}</a></li>
  <li>
    <a href="#">&raquo;</a>
  </li>
</ul>

ดังนั้นควรใช้เมื่อใดng-repeat-startและng-repeat-end? ตามเอกสารเชิงมุมถึง

... ทำซ้ำชุดขององค์ประกอบแทนที่จะเป็นองค์ประกอบหลักเพียงรายการเดียว ...

พอคุยโชว์บ้าง!

พอใช้; jsbin นี้จะอธิบายถึง 5 ตัวอย่างของสิ่งที่เกิดขึ้นเมื่อคุณทำและเมื่อคุณไม่ได้ใช้ng-repeat-endบนแท็กเดียวกัน

http://jsbin.com/eXaPibI/1/


11
ดูเหมือนคุณจะเข้าใจประเด็นของคำถามผิดไป เป้าหมายคือการทำซ้ำสองรายการขึ้นไปพร้อมกันและทั้งตัวอย่างของคุณหรือหน้าที่คุณเชื่อมโยงเพื่อเป็นหนทางในการทำสิ่งนี้ให้สำเร็จ ตามที่คุณสังเกตเห็นตัวเองการติดng-repeat-startและng-repeat-endเข้ากับองค์ประกอบเดียวกันนั้นไม่มีประโยชน์อย่างยิ่งเมื่อคุณสามารถใช้ค่าเริ่มต้นของเชิงมุมng-repeatและใช้มันได้
Asad Saeeduddin

@ อาซาด - "ประเด็นคำถาม" อปท. ไม่ได้ระบุไว้ชัดเจน นอกจากนี้คุณได้ตรวจสอบผลลัพธ์ DOM ที่แสดงผลของคำตอบที่ยอมรับแล้วหรือยัง ฉันนึกไม่ออกว่ามีใครต้องการผลลัพธ์แบบนั้นอย่างน้อยก็ไม่ใช่สำหรับรายการการแบ่งหน้า bootstrap
mg1075

1
@ mg1075 ใช่ผลลัพธ์ของคำตอบที่ยอมรับนั้นไม่สามารถยอมรับได้ซึ่งเป็นสาเหตุที่ฉันเลื่อนลงมาที่นี่จนสุด ประเด็นของคำถามนั้นชัดเจนมาก: หาวิธีสมัครng-repeatหรือหาทางเลือกอื่นในการใช้งานของ OP ng-repeatซึ่งจะกำจัดอาร์ติdivแฟกต์ใน HTML คำตอบของคุณไม่ได้ทำเช่นนี้เนื่องจากไม่มีวิธีใดที่จะใช้กับสองliองค์ประกอบในคำถาม หากฉันผิดโปรดให้มาร์กอัปตัวอย่างที่ปรับรหัสของ OP เพื่อกำจัดdivองค์ประกอบ
Asad Saeeduddin

@ Asad - ประเด็นของคำถามจะชัดเจนขึ้นหาก OP ได้ให้ตัวอย่างผลลัพธ์ที่เสร็จสมบูรณ์ที่เขาต้องการ ความจริงที่ว่าเขายอมรับคำตอบที่ "ยอมรับ" โดยที่คำตอบที่ยอมรับนั้นใช้การแบ่งหน้า bootstrap กับมาร์กอัปที่ไม่เหมาะสมเป็นหลักเท่านั้นที่ทำให้ปัญหานั้นสับสนยิ่งขึ้น ตัวอย่างที่ 2 ใน jsbin หากนั่นคือสิ่งที่ตั้งใจไว้จริงๆจะแก้ปัญหาของ OP ด้วยวิธีที่คำตอบที่ยอมรับทำ แต่ไม่มีใครควรใช้มาร์กอัปประเภทนั้นสำหรับการแบ่งหน้า bootstrap jsbin.com/eXaPibI/1
mg1075

1
อันที่จริงฉันเพิ่งดูคำตอบแรกอีกครั้งและมาร์กอัปที่สร้างขึ้นนั้นเหมาะสมกับกรณีการใช้งานของ OP แม้ว่าจะไม่เป็นไปตามข้อกำหนดของฉันก็ตาม OP ต้องการให้มีliการสร้างรายการแบ่งซึ่งเป็นสิ่งพิเศษที่liคุณเห็นใน jsbin ของคุณ
Asad Saeeduddin

6

ngRepeat อาจไม่เพียงพออย่างไรก็ตามคุณสามารถรวมเข้ากับคำสั่งที่กำหนดเองได้ คุณสามารถมอบหมายงานในการเพิ่มรายการตัวแบ่งลงในโค้ดได้หากคุณไม่สนใจ jQuery เล็กน้อย

 <li ng-repeat="item in coll" so-add-divide="your exp here"></li>

คำสั่งง่ายๆเช่นนี้ไม่จำเป็นต้องมีค่าแอตทริบิวต์ แต่อาจให้ความเป็นไปได้มากมายแก่คุณเช่นการเพิ่มตัวแบ่งตามดัชนีความยาว ฯลฯ หรือสิ่งที่แตกต่างอย่างสิ้นเชิง


2
เจ๋งฉันเพิ่มคำสั่งที่กำหนดเองแล้วมันก็ใช้ได้ คู่มือวิดีโอนี้ช่วยได้: youtube.com/watch?v=A6wq16Ow5Ec
nehz

3

เมื่อเร็ว ๆ นี้ฉันมีปัญหาเดียวกันกับการที่ฉันต้องทำซ้ำคอลเลคชันช่วงและรูปภาพโดยพลการการมีองค์ประกอบรอบตัวไม่ใช่ตัวเลือกอย่างไรก็ตามมีวิธีแก้ปัญหาง่ายๆให้สร้างคำสั่ง "null":

app.directive("diNull", function() {
        return {
            restrict: "E",
            replace: true,
            template: ""
        };
    });

จากนั้นคุณสามารถใช้การทำซ้ำกับองค์ประกอบนั้นโดยที่ element.url ชี้ไปที่เทมเพลตสำหรับองค์ประกอบนั้น:

<di-null ng-repeat="element in elements" ng-include="element.url" ></di-null>

การดำเนินการนี้จะทำซ้ำเทมเพลตต่างๆจำนวนมากโดยไม่มีคอนเทนเนอร์อยู่รอบ ๆ

หมายเหตุ: อืมฉันสาบานได้ว่าคนตาบอดนี้ลบองค์ประกอบ di-null ออกเมื่อแสดงผล แต่ตรวจสอบอีกครั้งมันไม่ได้ ... ยังคงแก้ปัญหาเลย์เอาต์ของฉันแม้ว่า ... curioser และ curioser ...


replaceเลิกใช้งานตั้งแต่ 2.0
demalexx

ฉันลองข้างต้นแล้ว แต่เทมเพลต: "" ทำให้ไม่มีอะไรเปลี่ยนแปลง ฉันใช้ตัวเชื่อมโยงจากjsfiddle.net/markcoleman/fMP9s/1และแก้ไข: link: function (scope, element, attrs) {element [0] .outerHTML = ''; $ คอมไพล์ (element.contents ()) (ขอบเขต); }
Lauri Lubi

1

มีข้อ จำกัด คำสั่งแสดงความคิดเห็น แต่ ngRepeat ไม่รองรับ (เนื่องจากต้องใช้องค์ประกอบในการทำซ้ำ)

ฉันคิดว่าฉันเห็นทีมเชิงมุมบอกว่าพวกเขาจะทำงานกับความคิดเห็นที่ทำซ้ำ แต่ฉันไม่แน่ใจ คุณควรเปิดปัญหาให้กับมันใน repo http://github.com/angular/angular.js


ความคิดเห็นจากปี 2012 ยังคงเป็นเช่นนี้อยู่หรือไม่? พยายามค้นหาในเอกสารแล้วไม่พบข้อมูลอ้างอิงใด ๆ
Zack S

1

ไม่มีวิธีมายากลเชิงมุมในกรณีของคุณคุณสามารถทำได้เพื่อรับ HTML ที่ถูกต้องหากคุณใช้ Bootstrap จากนั้นคุณจะได้รับผลเช่นเดียวกับการเพิ่ม li.divider

สร้างชั้นเรียน:

span.divider {
 display: block;
}

ตอนนี้เปลี่ยนรหัสของคุณเป็นสิ่งนี้:

<ul ng-cloak>
 <li div ng-repeat="n in list">
    <a href="{{ n[1] }}">{{ n[0] }}</a>
    <span class="divider"></span>
 </li>
 <li>Additional item</li>
</ul>

1

สำหรับโซลูชันที่ใช้งานได้จริง

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


เรื่องนี้น่าสนใจ อย่างไรก็ตามในreplaceWith(...)ผลการทดสอบของฉันในโหนดข้อความไม่ใช่ความคิดเห็น เจอแค่ใช้element.remove()งาน
artfulrobot
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.