Кутове ng-повторення додайте завантажувальний рядок кожні 3 або 4 cols


111

Я шукаю правильну схему для введення класу рядків завантажувального коду кожні 3 колонки. Мені це потрібно, тому що у cols немає фіксованої висоти (і я не хочу її виправляти), тому це порушує мою конструкцію!

Ось мій код:

<div ng-repeat="product in products">
    <div ng-if="$index % 3 == 0" class="row">
        <div class="col-sm-4" >
            ...
        </div>
    </div>
</div>

Але він відображає лише один продукт у кожному рядку. Я хочу отримати кінцевий результат:

<div class="row">
    <div class="col-sm4"> ... </div>
    <div class="col-sm4"> ... </div>
    <div class="col-sm4"> ... </div>
</div>
<div class="row">
    <div class="col-sm4"> ... </div>
    <div class="col-sm4"> ... </div>
    <div class="col-sm4"> ... </div>
</div>

Чи можу я досягти цього лише за допомогою ng-повторного шаблону (без директиви чи контролера)? У документах вводять нг-повтор старт і нг-повтор-кінець , але я не можу зрозуміти, як використовувати саме цей випадок використання! Я відчуваю, що це те, що ми часто використовуємо в шаблоні завантаження! ? Дякую


Я думаю, ви повинні моделювати свої дані таким чином, що відповідає вашому дизайну. Це, мабуть, має бути багатовимірний масив або об'єкт із поданням рядків і стовпців, тоді ви повинні перебирати рядки та використовувати директиву "ng-class" умовного класу та внутрішній рядок потім слід перебрати стовпці.
— antanas_sepikas

Цікаве і, безумовно, робоче рішення, але в день, коли я хочу відображати 4 вироби підряд, а не 3, я повинен змінити свою структуру даних, я вважаю за краще, щоб це
— залишалося

Я бачу, тоді вам слід, ймовірно, повторити шматки, як у відповіді Аріеля, також ви можете знайти цю публікацію stackoverflow.com/questions/18564888/… корисно.
— antanas_sepikas

Я думаю , що це саме те , що ви шукаєте: stackoverflow.com/a/30426750/1943442
— user1943442

Відповіді:


164

Хоча ефективна відповідь вгорі - це не те, що я вважав би кутовим способом, а також не використання власних класів завантаження, які призначені для вирішення цієї ситуації. Як зазначалося @claies, .clearfixклас призначений для таких ситуацій. На мою думку, найчистіша реалізація полягає в наступному:

<div class="row">
    <div ng-repeat="product in products">
        <div class="clearfix" ng-if="$index % 3 == 0"></div>
        <div class="col-sm-4">
            <h2>{{product.title}}</h2>
        </div>
    </div>
</div>

Ця структура дозволяє уникнути безладного індексації масиву продуктів, забезпечує чисту нотацію точок та використовує клас clearfix за призначенням.


6
Це гарна ідея, однак якщо ви зацікавлені у використанні flexbox, ви повинні використовувати це на ряду, а не на дівах всередині рядків, щоб кожне поле / div було однакової висоти. Clearfix - чудовий, але не допомагає тримати все в черзі.
— Кодований контейнер

3
Це моя найкраща відповідь. Дуже чисто і легко.
— Гінріх

1
Відмінно працює і для моєї реалізації! :)
— Буде Строль

1
Чудово ... Це слід проголосувати як прийняту відповідь!
— Велу

3
Це ідеальна відповідь
— Deepu

148

Я знаю, що це трохи пізно, але це все одно може допомогти комусь. Я зробив це так:

<div ng-repeat="product in products" ng-if="$index % 3 == 0" class="row">
    <div class="col-xs-4">{{products[$index]}}</div>
    <div class="col-xs-4" ng-if="products.length > ($index + 1)">{{products[$index + 1]}}</div>
    <div class="col-xs-4" ng-if="products.length > ($index + 2)">{{products[$index + 2]}}</div>
</div>

jsfiddle


3
це насправді мені дуже допомогло !! Дякую.
— SupimpaAllTheWay

Це дійсно просто реалізувати! Дякую!
— Манас Баджай

Мені дуже допомагали. Дякую!
— Ахмад Аджімі

17
Прекрасне рішення, однак воно не перевіряє, чи переходять $ index + 1 та $ index +2 за межі масиву. Останні два діви вимагають ng-if="$index+1 < products.length"іng-if="$index+2 < products.length"
— Мустафа Озтурк

Чи можемо ми зробити це для пари ключових значень. отримання наступного ключа? Замість отримання $ index + 1
— bpbhat77

25

Гаразд, це рішення набагато простіше, ніж ті, які вже є тут, і дозволяє різну ширину стовпців для різних ширин пристрою.

<div class="row">
    <div ng-repeat="image in images">
        <div class="col-xs-6 col-sm-4 col-md-3 col-lg-2">
            ... your content here ...
        </div>
        <div class="clearfix visible-lg" ng-if="($index + 1) % 6 == 0"></div>
        <div class="clearfix visible-md" ng-if="($index + 1) % 4 == 0"></div>
        <div class="clearfix visible-sm" ng-if="($index + 1) % 3 == 0"></div>
        <div class="clearfix visible-xs" ng-if="($index + 1) % 2 == 0"></div>
    </div>
</div>

Зауважте, що % 6частина повинна дорівнювати кількості отриманих стовпців. Тож якщо в елементі стовпця у вас клас col-lg-2буде 6 стовпців, тому використовуйте ... % 6.

Ця методика (за винятком ng-if) насправді тут задокументована: документи Bootstrap


1
На мою думку, це найкраще рішення.
— користувач216661

Якщо ви не знайшли початкового завантаження, легко не помітити той факт, що визначати рядки не потрібно. Це спрацювало чудово і є трохи більш повною версією рішення Дункана.
— фосплайт

Це саме те, що я шукав.
— Гінріх

@phosplait Яка перевага цього перед Дунканом?
— Jeppe

17

Хоча те, що ви хочете досягти, може бути корисним, є ще один варіант, на який я вважаю, що ви можете не помітити, що набагато простіше.

Ви маєте рацію, таблиці Bootstrap діють дивно, коли у вас є стовпці, які не мають фіксованої висоти. Однак є клас завантаження, створений для боротьби з цією проблемою та виконання чуйних скидів .

просто створіть порожнє <div class="clearfix"></div>перед початком кожного нового рядка, щоб дозволити скиданням поплавків і поверненню стовпців у правильні позиції.

ось завантаження .


Це не вирішує від'ємну 15px маржу, яку має кожен .row для завантажувальної програми.
— Логус

Це працює з flexтим, щоб колони були однакової висоти?
— Еліссон

16

Дякую за ваші пропозиції, ви вивели мене на правильний шлях!

Перейдемо до повного пояснення:

  • За замовчуванням AngularJS http отримати запит повертає об'єкт

  • Отже, якщо ви хочете використовувати функцію @Ariel Array.prototype.chunk, вам потрібно спочатку перетворити об'єкт у масив.

  • А потім використовувати функцію " ЧАК" у ВАШОМУ КОНТРОЛЕРІ, інакше при використанні прямо в ng-повторенні це призведе до помилки вкладки . Кінцевий контролер виглядає:

    // Initialize products to empty list
    $scope.products = [];
    
    // Load products from config file
    $resource("/json/shoppinglist.json").get(function (data_object)
    {
        // Transform object into array
        var data_array =[];
        for( var i in data_object ) {
            if (typeof data_object[i] === 'object' && data_object[i].hasOwnProperty("name")){
                data_array.push(data_object[i]);
            }
        }
        // Chunk Array and apply scope
        $scope.products = data_array.chunk(3);
    });

І HTML стає:

<div class="row" ng-repeat="productrow in products">

    <div class="col-sm-4" ng-repeat="product in productrow">

З іншого боку, я вирішив безпосередньо повернути масив [] замість об'єкта {} з мого файлу JSON. Таким чином, контролер стає (зверніть увагу на конкретний синтаксис isArray: true ):

    // Initialize products to empty list 
    $scope.products = [];

    // Load products from config file
    $resource("/json/shoppinglist.json").query({method:'GET', isArray:true}, function (data_array)
    {
        $scope.products = data_array.chunk(3);
    });

HTML залишається таким же, як вище.

ОПТИМІЗАЦІЯ

Останнє запитання в напрузі: як зробити це 100% AngularJS без розширення масиву javascript з функцією "... . Мені цікаво ;)

ЕНДРЕЙСЬКЕ РІШЕННЯ

Завдяки @Andrew, тепер відомо, що додавання класу очищення для завантажувального коду кожен три (або будь-яке число) елемент виправляє проблему відображення з висоти блоку різниці.

Отже HTML стає:

<div class="row">

    <div ng-repeat="product in products">

        <div ng-if="$index % 3 == 0" class="clearfix"></div>

        <div class="col-sm-4"> My product descrition with {{product.property}}

А ваш контролер залишається досить м'яким із вилученою функцією:

// Initialize products to empty list 
        $scope.products = [];

        // Load products from config file
        $resource("/json/shoppinglist.json").query({method:'GET', isArray:true}, function (data_array)
        {
            //$scope.products = data_array.chunk(3);
            $scope.products = data_array;
        });

7

Ви можете це зробити без директиви, але я не впевнений, що це найкращий спосіб. Для цього потрібно створити масив масиву з даних, які ви хочете відобразити в таблиці, а після цього використовувати 2 ng-повторення для ітерації через масив.

щоб створити масив для відображення, використовуйте цю функцію, як та products.chunk (3)

Array.prototype.chunk = function(chunkSize) {
    var array=this;
    return [].concat.apply([],
        array.map(function(elem,i) {
            return i%chunkSize ? [] : [array.slice(i,i+chunkSize)];
        })
    );
}

а потім зробіть щось подібне, використовуючи 2 нг-повторення

<div class="row" ng-repeat="row in products.chunk(3)">
  <div class="col-sm4" ng-repeat="item in row">
    {{item}}
  </div>
</div>

7

На основі рішення Alpar, використовуючи лише шаблони з анідованим ng-повтором. Працює з повними та частково порожніми рядками:

<div data-ng-app="" data-ng-init="products='soda','beer','water','milk','wine']" class="container">
    <div ng-repeat="product in products" ng-if="$index % 3 == 0" class="row">
        <div class="col-xs-4" 
            ng-repeat="product in products.slice($index, ($index+3 > products.length ? 
            products.length : $index+3))"> {{product}}</div>
    </div>
</div>

JSFiddle


5

Я щойно прийняв рішення, працюючи лише в шаблоні. Рішення є

    <span ng-repeat="gettingParentIndex in products">
        <div class="row" ng-if="$index<products.length/2+1">    <!-- 2 columns -->
            <span ng-repeat="product in products">
                <div class="col-sm-6" ng-if="$index>=2*$parent.$index && $index <= 2*($parent.$index+1)-1"> <!-- 2 columns -->
                    {{product.foo}}
                </div>
            </span>
        </div>
    </span>

Point використовує дані двічі, один - для зовнішньої петлі. Залишкові теги залишаться, але це залежить від того, як ви торгуєте.

Якщо це макет з 3 стовпцями, це буде схоже

    <span ng-repeat="gettingParentIndex in products">
        <div class="row" ng-if="$index<products.length/3+1">    <!-- 3 columns -->
            <span ng-repeat="product in products">
                <div class="col-sm-4" ng-if="$index>=3*$parent.$index && $index <= 3*($parent.$index+1)-1"> <!-- 3 columns -->
                    {{product.foo}}
                </div>
            </span>
        </div>
    </span>

Чесно кажучи, я хотів

$index<Math.ceil(products.length/3)

Хоча це не спрацювало.


Я спробував це рішення реалізувати по 2 елементи в кожному ряду. Наприклад, у мене є 5 елементів у списку, тож у висновку, який я повинен мати, є 3 рядки з 2 елементами / стовпцями у перших 2 рядках та 1 стовпець у останньому рядку. Проблема в тому, що я отримую тут 5 рядків, а останні 2 ряди порожні. Цікаво, як це виправити? Спасибі
— Маверик Різ

@MaverickAzy дякую за спробу. Я знаю, що існує проблема, що якщо висота цих елементів відрізняється, це не спрацює добре.
— ватару

Висота елементів насправді однакова. Проблема в тому, що я повинен отримати лише 3 ряди, але отримую 5 рядків з останніми 2 порожніми рядками. Чи можете ви сказати мені, якщо довжина products.length 5, то 5/2 + 1 =? Ця логіка мені не зрозуміла в рядку 2 для рядка класу.
— Маверик Різ

@MaverickAzy ці порожні рядки потрібно створити такими, якими вони є. Це псує вашу верстку?
— ватару

ні, це не псує макет. Єдине занепокоєння стосується порожніх рядів. Дуже вдячний, якщо ви можете мені в цьому допомогти. Спасибі
— Maverick Riz

5

Ще одне невелике вдосконалення щодо відповіді @Duncan та інших відповідей на основі елемента clearfix. Якщо ви хочете зробити вміст доступним для натискання, вам знадобиться z-index> 0 на ньому, або clearfix буде перекривати вміст і обробляти клацання.

Цей приклад не працює (ви не можете побачити покажчик курсору, а натискання нічого не призведе):

<div class="row">
    <div ng-repeat="product in products">
        <div class="clearfix" ng-if="$index % 3 == 0"></div>
        <div class="col-sm-4" style="cursor: pointer" ng-click="doSomething()">
            <h2>{{product.title}}</h2>
        </div>
    </div>
</div>

Хоча це фіксований варіант :

<div class="row">
    <div ng-repeat-start="product in products" class="clearfix" ng-if="$index % 3 == 0"></div>
    <div ng-repeat-end class="col-sm-4" style="cursor: pointer; z-index: 1" ng-click="doSomething()">
            <h2>{{product.title}}</h2>
    </div>
</div>

Я додав z-index: 1, що вміст піднімається над clearfix, і я видалив контейнер div, використовуючи натомість ng-repeat-startі ng-repeat-end(доступний з AngularJS 1.2), оскільки він зробив z-індекс не працює.

Сподіваюся, це допомагає!

Оновлення

Plunker: http://plnkr.co/edit/4w5wZj


Це працює з flexрядками, щоб колони були однакової висоти?
— Еліссон

Я не впевнений, що розумію ваше запитання. Це швидкий планк, щоб показати вам, що робить цей код: plnkr.co/edit/4w5wZj?p=preview . На словах, виправлення правильно вирівняє другий рядок заголовків: всі вони починаються з однієї точки, але вони все ще не мають такої ж висоти (як ви бачите завдяки кольору фону). Спробуйте видалити клас Clearfix, щоб побачити, що таке поведінка за замовчуванням. Я використовував flexbox лише один чи два рази, але він має багато властивостей css, і я впевнений, що ви зможете знайти те, що шукаєте.
— McGiogen

bootstrap - приклад того, як зробити всі стовпці в одному рядку, щоб отримати однакову висоту найвищого стовпця. Мені довелося цим скористатися. Проблема полягає в тому, що вона втрачає можливість перейти на новий рядок, коли є більше 12 стовпців, тому вам потрібно вручну створити нові рядки. Дослідивши трохи більше, я міг отримати рішення і розмістив тут відповідь, хоча я не знаю, чи найкраще це. Все одно дякую, ваша відповідь мені допомогла!
— Еліссон

Це перший раз, коли я бачу цей приклад, він дійсно корисний! Радий допомогти вам.
— McGiogen

4

Я вирішив це за допомогою ng-класу

<div ng-repeat="item in items">
    <div ng-class="{ 'row': ($index + 1) % 4 == 0 }">
        <div class="col-md-3">
            {{item.name}}
        </div>
    </div>
</div>

2

Найкращий спосіб застосувати клас - це використовувати ng-class.За допомогою нього можна застосовувати класи на основі певної умови.

<div ng-repeat="product in products">
   <div ng-class="getRowClass($index)">
       <div class="col-sm-4" >
           <!-- your code -->
       </div>
   </div>

а потім у вашому контролері

$scope.getRowClass = function(index){
    if(index%3 == 0){
     return "row";
    }
}

2

Після поєднання тут багатьох відповідей та пропозицій, це моя остаточна відповідь, яка добре працює flex, що дозволяє нам робити стовпчики з однаковою висотою, він також перевіряє останній індекс, і вам не потрібно повторювати внутрішній HTML. Він не використовує clearfix:

<div ng-repeat="prod in productsFiltered=(products | filter:myInputFilter)" ng-if="$index % 3 == 0" class="row row-eq-height">
    <div ng-repeat="i in [0, 1, 2]" ng-init="product = productsFiltered[$parent.$parent.$index + i]"  ng-if="$parent.$index + i < productsFiltered.length" class="col-xs-4">
        <div class="col-xs-12">{{ product.name }}</div>
    </div>
</div>

Він виведе щось подібне:

<div class="row row-eq-height">
    <div class="col-xs-4">
        <div class="col-xs-12">
            Product Name
        </div>
    </div>
    <div class="col-xs-4">
        <div class="col-xs-12">
            Product Name
        </div>
    </div>
    <div class="col-xs-4">
        <div class="col-xs-12">
            Product Name
        </div>
    </div>
</div>
<div class="row row-eq-height">
    <div class="col-xs-4">
        <div class="col-xs-12">
            Product Name
        </div>
    </div>
    <div class="col-xs-4">
        <div class="col-xs-12">
            Product Name
        </div>
    </div>
    <div class="col-xs-4">
        <div class="col-xs-12">
            Product Name
        </div>
    </div>
</div>

1

Невелика модифікація рішення @alpar

<div data-ng-app="" data-ng-init="products=['A','B','C','D','E','F', 'G','H','I','J','K','L']" class="container">
    <div ng-repeat="product in products" ng-if="$index % 6 == 0" class="row">
        <div class="col-xs-2" ng-repeat="idx in [0,1,2,3,4,5]">
        {{products[idx+$parent.$index]}} <!-- When this HTML is Big it's useful approach -->
        </div>
    </div>
</div>

jsfiddle


0

Це працювало для мене, не потрібно робити сплайсингу чи нічого:

HTML

<div class="row" ng-repeat="row in rows() track by $index">
    <div class="col-md-3" ng-repeat="item in items" ng-if="indexInRange($index,$parent.$index)"></div>
</div>

JavaScript

var columnsPerRow = 4;
$scope.rows = function() {
  return new Array(columnsPerRow);
};
$scope.indexInRange = function(columnIndex,rowIndex) {
  return columnIndex >= (rowIndex * columnsPerRow) && columnIndex < (rowIndex * columnsPerRow) + columnsPerRow;
};

0

Born Solutions найкраще, просто потрібно трохи налаштувати ноги на потреби, у мене були різні чуйні рішення та трохи змінилися

<div ng-repeat="post in posts">
    <div class="vechicle-single col-lg-4 col-md-6 col-sm-12 col-xs-12">
    </div>
    <div class="clearfix visible-lg" ng-if="($index + 1) % 3 == 0"></div>
    <div class="clearfix visible-md" ng-if="($index + 1) % 2 == 0"></div>
    <div class="clearfix visible-sm" ng-if="($index + 1) % 1 == 0"></div>
    <div class="clearfix visible-xs" ng-if="($index + 1) % 1 == 0"></div>
</div>

0

Спираючись на відповідь Альпара, ось більш узагальнений спосіб розділити один список елементів на декілька контейнерів (рядки, стовпці, відра тощо):

<div class="row" ng-repeat="row in [0,1,2]">
  <div class="col" ng-repeat="item in $ctrl.items" ng-if="$index % 3 == row">
    <span>{{item.name}}</span>
  </div>
</div> 

для списку з 10 елементів створює:

<div class="row">
  <div class="col"><span>Item 1</span></div>
  <div class="col"><span>Item 4</span></div>
  <div class="col"><span>Item 7</span></div>
  <div class="col"><span>Item 10</span></div>
</div> 
<div class="row">
  <div class="col"><span>Item 2</span></div>
  <div class="col"><span>Item 5</span></div>
  <div class="col"><span>Item 8</span></div>
</div> 
<div class="row">
  <div class="col"><span>Item 3</span></div>
  <div class="col"><span>Item 6</span></div>
  <div class="col"><span>Item 9</span></div>
</div> 

Кількість контейнерів можна швидко кодувати у функції контролера:

JS (ES6)

$scope.rowList = function(rows) {
  return Array(rows).fill().map((x,i)=>i);
}
$scope.rows = 2;

HTML

<div class="row" ng-repeat="row in rowList(rows)">
  <div ng-repeat="item in $ctrl.items" ng-if="$index % rows == row">
    ...

Такий підхід дозволяє уникнути дублювання розмітки елемента ( <span>{{item.name}}</span>у даному випадку) у вихідному шаблоні - не величезна виграш для простого прольоту, але для більш складної структури DOM (яку я мав), це допомагає зберегти шаблон ДУХОМ.


0

Оновлення 2019 - Bootstrap 4

Оскільки Bootstrap 3 використовує плавучі , він вимагає clearfix скидає всі n (3 або 4) стовпців ( .col-*) у, .rowщоб запобігти нерівномірному загортанню стовпців.

Тепер, коли Bootstrap 4 використовує flexbox , більше не потрібно загортати стовпці в окремі .rowтеги або вставляти зайві знаки, щоб змусити cols обертати кожні n стовпців.

Ви можете просто повторити всі стовпці в одному .rowконтейнері.

Наприклад, 3 стовпці у кожному візуальному рядку:

<div class="row">
     <div class="col-4">...</div>
     <div class="col-4">...</div>
     <div class="col-4">...</div>
     <div class="col-4">...</div>
     <div class="col-4">...</div>
     <div class="col-4">...</div>
     <div class="col-4">...</div>
     (...repeat for number of items)
</div>

Отже, для Bootstrap ng-повторення просто:

  <div class="row">
      <div class="col-4" ng-repeat="item in items">
          ... {{ item }}
      </div>
  </div>

Демонстрація: https://www.codeply.com/go/Z3IjLRsJXX


0

Я робив це лише за допомогою boostrap, ви повинні бути дуже обережними щодо розташування рядка та стовпця, ось мій приклад.

<section>
<div class="container">
        <div ng-app="myApp">
        
                <div ng-controller="SubregionController">
                    <div class="row text-center">
                        <div class="col-md-4" ng-repeat="post in posts">
                            <div >
                                <div>{{post.title}}</div>
                            </div>
                        </div>
                    
                    </div>
                </div>        
        </div>
    </div>
</div> 

</section>

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.