Кутове 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.