AngularJS ng-повтор без елемента 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-повтор без контейнера div або якийсь альтернативний метод для досягнення того ж ефекту.


Про які проблеми з візуалізацією Ви говорите?
Ja͢ck

останній роздільник li здається трохи товстішим, як його складений (chrome win7). Це може бути проблемою css, однак, я хотів би знати, чи можна це виправити в кутовому режимі. Для порівняння, knockoutJS дозволяє прив'язування без контейнерів за допомогою <! - ->.
nehz

Я бачу, я використовую phptal на стороні сервера, і у них спеціально для цього є тег tal: block :) здогадуюсь, DOM не завжди приймає новий тип тегу, який складніше з
angular

Чи можете ви також оновити html, щоб відобразити, як ви використовуєте htmlAppendдирективу?
Нік

Готово ... зробив це деякий час тому, але я пам'ятаю, що це працювало
nehz,

Відповіді:


104

Як сказав Енді Джослін, вони працюють над коментарями на основі коментарів, але, мабуть, проблем із браузером було занадто багато . На щастя, 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>

Повний робочий приклад можна знайти тут .

Джон Ліндквіст також має відеоурок про це на своїй чудовій сторінці egghead.io .


3
Чи не потрібен для цього друк елемента?
hitautodestruct

2
Я серйозно заплутаний у тому, що це робить просто <li ng-repeat = "page in [1,2,3,4,5,6]"> <a href="#"> {{page}} </ a > </li> -редагувати: ніколи, я думаю, я зрозумів
Шадаес,

6
Я розумію, що ви просто намагаєтеся продемонструвати, ng-repeat-start/endале це заплутаний приклад і неправильний варіант використання. Тут ng-repeatслід використовувати стандарт, оскільки ваш код робить зайвим порожнім liдля кожного елемента. Вам, мабуть, слід згадати це у своєму дописі.
GFoley83

2
@ GFoley83 ти маєш рацію. Але він, схоже, хоче цей додатковий елемент для кожної ітерації, те, без чого неможливо ng-repeat-start. Я додаю dividerклас html до своєї відповіді, щоб бути більш зрозумілим.
jmagnusson

1
ng-repeat-startі ng-repeat-endтрохи заплутані. Документація Angular допомагає: https://docs.angularjs.org/api/ng/directive/ngRepeat#special-repeat-start-and-end-points
perilandmishap

30

KnockoutJS синтаксис прив'язки без контейнерів

Будь ласка, витримайте зі мною секунду: 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 не пропонує такий тип синтаксису.


Кутові 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 щодо цього питання для Angular, 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 описує п’ять прикладів того, що відбувається, коли ви робите і коли ви не використовуєте один і ng-repeat-endтой же тег.

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


11
Здається, ви неправильно зрозуміли суть питання. Мета полягає в тому, щоб одночасно повторити два або більше пунктів списку, і ні ваш приклад, ні сторінка, на яку ви зв’язали, не забезпечують способу досягнення цього. Як ви вже зазначали, приєднувати один ng-repeat-startі ng-repeat-endтой самий елемент абсолютно марно, коли ви можете використовувати за замовчуванням angular ng-repeatі закінчити з цим.
Асад Саедуддін,

@Asad - ОП не чітко сформулював "пункт питання". Крім того, чи перевіряли ви надані результати DOM прийнятої відповіді? Я не можу уявити, щоб хтось хотів такого виводу, принаймні, звичайно, не для списку пагінації bootstrap.
mg1075

1
@ mg1075 Так, вихід прийнятої відповіді є неприйнятним, саме тому я прокрутив сюди вниз. Суть питання дуже зрозуміла: знайти спосіб застосувати ng-repeatабо знайти альтернативу використанню OP, ng-repeatяка виключає divартефакт у HTML. Ваша відповідь цього не робить, оскільки немає можливості використовувати її для двох liелементів у питанні. Якщо я помиляюся тут, надайте зразок розмітки, який адаптує код OP для усунення divелемента.
Асад Саедуддін,

@Asad - Суть питання була б чіткішою, якби ОП подало готовий приклад результату, який він задумав. Той факт, що він прийняв "прийняту" відповідь, де прийнята відповідь використовує пагінацію bootstrap з по суті неправильною розміткою, лише заплутав проблему. Приклад 2 у jsbin, якщо це те, що насправді передбачається, вирішує проблему OP так, як це робить прийнята відповідь, але ніхто не повинен використовувати такий тип розмітки для пагінації завантаження. jsbin.com/eXaPibI/1
mg1075

1
Насправді, я щойно переглянув першу відповідь, і створена розмітка точно підходить для випадку використання OP, хоча вона не задовольняє мої вимоги. OP хоче створити liелемент розділювача , який є додатковою інформацією, liяку ви бачите у своєму jsbin.
Асад Саедуддін,

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 під час рендерингу, але перевірка його знову не ... все ще вирішує мої проблеми з макетом, хоча ... цікавіше та цікавіше ...


replaceзастаріло з 2.0.
demalexx

Я спробував вище, але шаблон "" спричиняє те, що нічого не змінюється. Я використав компоновщик з jsfiddle.net/markcoleman/fMP9s/1 і змінив його: link: function (scope, element, attrs) {element [0] .outerHTML = ''; $ compile (element.contents ()) (scope); }
Лаурі Лубі

1

Існує обмеження директиви коментарів, але ngRepeat його не підтримує (оскільки йому потрібен елемент для повторення).

Мені здається, я бачив, як команда, що працює на базі, каже, що вони працюватимуть над коментарями, але я не впевнений. Ви повинні відкрити для нього випуск на репо. 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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.