AngularJS ng-repeat không có phần tử html


91

Tôi hiện đang sử dụng đoạn mã này để hiển thị danh sách:

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

Tuy nhiên, <div>phần tử này đang gây ra một số lỗi hiển thị rất nhỏ trên một số trình duyệt. Tôi muốn biết có cách nào để thực hiện ng-repeat mà không cần vùng chứa div, hoặc một số phương pháp thay thế để đạt được hiệu quả tương tự.


Bạn đang nói về vấn đề kết xuất nào?
Ja͢ck 12/10/12

dải phân cách li cuối cùng có vẻ dày hơn một chút giống như được xếp chồng lên nhau (chrome win7). Đây có thể là một vấn đề css, tuy nhiên, tôi muốn biết liệu điều này có thể được khắc phục trong góc cạnh hay không. Để so sánh, knockoutJS cho phép ràng buộc không chứa bằng cách sử dụng <! - ->.
nehz

Tôi hiểu rồi, tôi sử dụng phptal ở phía máy chủ và họ có một tal: tag khối đặc biệt cho mục đích này :) đoán với DOM phải lúc nào cũng chấp nhận một loại mới của thẻ đó là khó khăn hơn với góc
Jack

Bạn cũng có thể cập nhật html để phản ánh cách bạn đang sử dụng htmlAppendchỉ thị không?
Nick

Xong ... đã làm điều này một lúc trước, nhưng tôi nhớ nó đã hoạt động
nehz

Câu trả lời:


104

Như Andy Joslin đã nói rằng họ đang làm việc dựa trên bình luận ng-lặp lại nhưng dường như có quá nhiều vấn đề về trình duyệt . May mắn thay AngularJS 1.2 thêm hỗ trợ tích hợp để lặp lại mà không cần thêm các phần tử con với các chỉ thị mới ng-repeat-startng-repeat-end.

Đây là một ví dụ nhỏ để thêm phân trang 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>

Một ví dụ làm việc đầy đủ có thể được tìm thấy ở đây .

John Lindquist cũng có một video hướng dẫn về điều này tại trang egghead.io tuyệt vời của anh ấy .


3
Điều này không yêu cầu một phần tử in?
hitautodestruct.

2
Tôi thực sự bối rối những gì điều này đạt được chỉ đơn giản là <li ng-repeat = "trang trong [1,2,3,4,5,6]"> <a href="#"> {{page}} </ a > </li> -edit: nevermind I think I get it
Shadaez

6
Tôi hiểu rằng bạn chỉ đang cố gắng chứng minh ng-repeat-start/endnhưng đây là một ví dụ khó hiểu và trường hợp sử dụng sai cho nó. Một tiêu chuẩn ng-repeatnên được sử dụng ở đây vì mã của bạn hiển thị thêm một khoảng trống licho mỗi mục. Bạn có thể nên đề cập đến điều đó trong bài đăng của bạn.
GFoley83

2
@ GFoley83 bạn nói đúng. Nhưng dường như anh ấy muốn có thêm yếu tố đó cho mỗi lần lặp lại, điều mà không thể không có ng-repeat-start. Tôi sẽ thêm dividerlớp html vào câu trả lời của mình để rõ ràng hơn.
jmagnusson

1
ng-repeat-startng-repeat-endhơi khó hiểu. Các tài liệu góc giúp: https://docs.angularjs.org/api/ng/directive/ngRepeat#special-repeat-start-and-end-points
perilandmishap

30

Cú pháp ràng buộc không chứa KnockoutJS

Vui lòng thông báo cho tôi một chút: KnockoutJS cung cấp một tùy chọn cực kỳ thuận tiện là sử dụng cú pháp liên kết không chứa cho foreachliên kết của nó như đã thảo luận trong Chú thích 4 của foreachtài liệu ràng buộc. http://knockoutjs.com/documentation/foreach-binding.html

Như ví dụ tài liệu Knockout minh họa, bạn có thể viết ràng buộc của mình trong KnockoutJS như sau:

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

Tôi nghĩ rằng khá đáng tiếc là AngularJS không cung cấp loại cú pháp này.


Angular's ng-repeat-startng-repeat-end

Trong cách AngularJS để giải quyết ng-repeatvấn đề, các mẫu tôi bắt gặp thuộc loại jmagnusson được đăng trong câu trả lời (hữu ích) của anh ấy.

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

Suy nghĩ ban đầu của tôi khi nhìn thấy cú pháp này là: thực sự? Tại sao Angular buộc tất cả các đánh dấu bổ sung này mà tôi không muốn làm gì cả và điều đó dễ dàng hơn nhiều trong Knockout? Nhưng sau đó nhận xét của hitautodestruct trong câu trả lời của jmagnusson bắt đầu khiến tôi tự hỏi: điều gì đang được tạo với ng-repeat-start và ng-repeat-end trên các thẻ riêng biệt?


Một cách tốt hơn để sử dụng ng-repeat-startng-repeat-end

Khi điều tra về khẳng định của hitautodestruct, việc thêm ng-repeat-endvào một thẻ riêng biệt là chính xác những gì tôi không muốn làm trong hầu hết các trường hợp, bởi vì nó tạo ra các phần tử hoàn toàn vô dụng: trong trường hợp này, <li>các mục không có gì trong đó. Danh sách phân trang của Bootstrap 3 tạo kiểu cho các mục trong danh sách để có vẻ như bạn không tạo ra bất kỳ mục thừa nào, nhưng khi bạn kiểm tra html được tạo, chúng ở đó.

May mắn thay , bạn không cần phải làm gì nhiều để có một giải pháp sạch hơn và số lượng html ngắn hơn: chỉ cần đặt ng-repeat-endkhai báo trên cùng một thẻ html có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>

Điều này mang lại 3 lợi thế:

  1. ít thẻ html để viết
  2. các thẻ trống, vô dụng không được tạo bởi Angular
  3. khi mảng cần lặp lại trống, thẻ với ng-repeatsẽ không được tạo, mang lại cho bạn lợi thế tương tự như ràng buộc không chứa của Knockout mang lại cho bạn về mặt này

Nhưng vẫn có một cách sạch hơn

Sau khi xem xét thêm các nhận xét trong github về vấn đề này cho Angular, https://github.com/angular/angular.js/issues/1891 ,
bạn không cần sử dụng ng-repeat-startng-repeat-endđạt được những lợi ích tương tự. Thay vào đó, làm lại ví dụ của jmagnusson, chúng ta chỉ có thể đi:

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

Vậy sử dụng khi nào ng-repeat-startng-repeat-end? Theo tài liệu góc , để

... lặp lại một loạt các phần tử thay vì chỉ một phần tử mẹ ...

Nói đủ rồi, chỉ ra một số ví dụ!

Đủ công bằng; jsbin này sẽ trình bày qua năm ví dụ về những gì sẽ xảy ra khi bạn làm và khi bạn không sử dụng ng-repeat-endtrên cùng một thẻ.

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


11
Có vẻ như bạn đã hiểu sai ý của câu hỏi. Mục tiêu là lặp lại hai hoặc nhiều mục danh sách đồng thời và không phải ví dụ của bạn cũng như trang bạn đã liên kết để cung cấp cách thực hiện điều này. Như bạn đã lưu ý, việc đính kèm ng-repeat-startng-repeat-endvào cùng một phần tử hoàn toàn vô ích khi bạn có thể sử dụng mặc định của góc ng-repeatvà được thực hiện với nó.
Asad Saeeduddin

@Asad - "điểm của câu hỏi" không được OP nêu rõ. Ngoài ra, bạn đã kiểm tra đầu ra DOM được hiển thị của câu trả lời được chấp nhận chưa? Tôi không thể tưởng tượng bất cứ ai muốn loại đầu ra đó, ít nhất là chắc chắn không cho danh sách phân trang bootstrap.
mg1075

1
@ mg1075 Có, đầu ra của câu trả lời được chấp nhận là không thể chấp nhận được, đó là lý do tại sao tôi cuộn xuống đây. Điểm của câu hỏi rất rõ ràng: hãy tìm cách áp dụng ng-repeathoặc tìm một giải pháp thay thế cho cách sử dụng của OP ng-repeatđể loại bỏ lỗi divtạo tác trong HTML. Câu trả lời của bạn không làm được điều này, vì không có cách nào để sử dụng nó cho hai liyếu tố trong câu hỏi. Nếu tôi sai ở đây, vui lòng cung cấp đánh dấu mẫu điều chỉnh mã của OP để loại bỏ divphần tử.
Asad Saeeduddin

@Asad - Điểm của câu hỏi sẽ rõ ràng hơn nếu OP cung cấp một ví dụ hoàn chỉnh về sản lượng mà ông ấy dự định. Việc anh ấy chấp nhận câu trả lời "được chấp nhận", trong đó câu trả lời được chấp nhận sử dụng phân trang bootstrap với đánh dấu không đúng về cơ bản, chỉ làm rối thêm vấn đề. Ví dụ 2 trong jsbin, nếu đó là những gì thực sự được dự định, giải quyết vấn đề của OP theo cách mà câu trả lời được chấp nhận thực hiện, nhưng không ai nên sử dụng loại đánh dấu đó để phân trang bootstrap. jsbin.com/eXaPibI/1
mg1075

1
Trên thực tế, tôi chỉ xem lại câu trả lời đầu tiên và đánh dấu được tạo ra chính xác phù hợp với trường hợp sử dụng của OP, mặc dù nó không đáp ứng yêu cầu của tôi. OP muốn một limục phân chia được tạo, đó là phần bổ sung libạn thấy trong jsbin của mình.
Asad Saeeduddin

6

ngRepeat có thể là không đủ, tuy nhiên bạn có thể kết hợp điều đó với một chỉ thị tùy chỉnh. Bạn có thể ủy thác nhiệm vụ thêm các mục của bộ chia vào mã nếu bạn không bận tâm một chút về jQuery.

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

Một chỉ thị đơn giản như vậy không thực sự cần một giá trị thuộc tính nhưng có thể cung cấp cho bạn nhiều khả năng như thêm một dấu chia có điều kiện theo chỉ mục, độ dài, v.v. hoặc một cái gì đó hoàn toàn khác.


2
tuyệt, tôi đã thêm một chỉ thị tùy chỉnh và nó hoạt động. Hướng dẫn video này giúp: youtube.com/watch?v=A6wq16Ow5Ec
nehz

3

Gần đây, tôi đã gặp phải vấn đề tương tự là tôi phải lặp lại một tập hợp các khoảng và hình ảnh tùy ý - có một phần tử xung quanh chúng không phải là một lựa chọn - tuy nhiên, có một giải pháp đơn giản, hãy tạo một chỉ thị "null":

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

Sau đó, bạn có thể sử dụng lặp lại trên Phần tử đó, trong đó element.url trỏ đến mẫu cho phần tử đó:

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

Điều này sẽ lặp lại bất kỳ số lượng mẫu khác nhau nào mà không có vùng chứa xung quanh chúng

Lưu ý: hmm, tôi có thể đã thề rằng điều này đã xóa phần tử di-null khi kết xuất, nhưng kiểm tra lại nó không ... vẫn giải quyết được các vấn đề về bố cục của tôi mặc dù ... tò mò và tò mò ...


replacekhông được dùng nữa kể từ 2.0.
demalexx

Tôi đã thử cách trên, nhưng mẫu: "" không có gì thay đổi. Tôi đã sử dụng trình liên kết từ jsfiddle.net/markcoleman/fMP9s/1 và sửa đổi nó: link: function (scope, element, attrs) {element [0] .outerHTML = ''; $ compile (element.contents ()) (scope); }
Lauri Lubi

1

Có một giới hạn chỉ thị nhận xét, nhưng ngRepeat không hỗ trợ nó (vì nó cần một phần tử lặp lại).

Tôi nghĩ rằng tôi đã thấy nhóm góc cạnh nói rằng họ sẽ làm việc với các bình luận ng-lặp lại, nhưng tôi không chắc. Bạn nên mở một vấn đề cho nó trên repo. http://github.com/angular/angular.js


Nhận xét từ năm 2012. Đây vẫn là trường hợp? Cố gắng tìm kiếm trong tài liệu của họ, và không thể tìm thấy bất kỳ tài liệu tham khảo nào.
Zack S

1

Không có cách kỳ diệu Angular nào để làm điều này, đối với trường hợp của bạn, bạn có thể làm điều này, để lấy HTML hợp lệ, nếu bạn đang sử dụng Bootstrap. Sau đó, bạn sẽ nhận được hiệu ứng tương tự như thêm li.divider

Tạo một lớp học:

span.divider {
 display: block;
}

Bây giờ hãy thay đổi mã của bạn thành:

<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

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 chỉ thị angle.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]);
}());

để được giải thích ngắn gọn,

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

sau đó, lệnh remove custom sẽ đặt các <remove>phần tử bắt đầu và kết thúc bằng<!--removed element-->


Hay đấy. Tuy nhiên, trong thử nghiệm của tôi, replaceWith(...)kết quả là một nút văn bản không phải là một nhận xét. Tôi đã tìm thấy chỉ sử dụng element.remove()các tác phẩm.
artfulrobot
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.