Angular ng-repeat adiciona linha de bootstrap a cada 3 ou 4 cols

Eu estou procurando o padrão certo para injetar uma class de linha de boot a cada 3 colunas. Eu preciso disso porque cols não tem um hight fixo (e eu não quero consertar um), então quebra meu design!

Aqui está o meu código:

...

Mas só exibe um produto em cada linha. O que eu quero como resultado final é:

 
...
...
...
...
...
...

Posso conseguir isso apenas com o padrão ng-repeat (sem diretiva ou controlador)? Os documentos introduzem ng-repeat-start e ng-repeat-end, mas não consigo descobrir como usá-lo neste caso de uso! Eu sinto que isso é algo que costumamos usar em modelos de bootstrap! ? obrigado

A resposta mais votada, embora eficaz, não é o que eu consideraria ser o modo angular, nem está usando as próprias classs do bootstrap para lidar com essa situação. Como @claies mencionou, a class .clearfix é destinada a situações como essas. Na minha opinião, a implementação mais limpa é a seguinte:

 

{{product.title}}

Essa estrutura evita a indexação desordenada da matriz de produtos, permite a notação de pontos limpa e faz uso da class clearfix para sua finalidade pretendida.

Eu sei que é um pouco tarde, mas ainda pode ajudar alguém. Eu fiz assim:

 
{{products[$index]}}
{{products[$index + 1]}}
{{products[$index + 2]}}

jsfiddle

Ok, esta solução é muito mais simples do que as que já estão aqui, e permite diferentes larguras de colunas para diferentes larguras de dispositivos.

 
... your content here ...

Observe que a parte % 6 deve ser igual ao número de colunas resultantes. Então, se no elemento column você tiver a class col-lg-2 , haverá 6 colunas, então use ... % 6 .

Esta técnica (excluindo o ng-if ) está documentada aqui: Documento do Bootstrap

Enquanto o que você quer realizar pode ser útil, há outra opção que eu acredito que você pode estar negligenciando que é muito mais simples.

Você está correto, as tabelas do Bootstrap agem estranhamente quando você tem colunas que não têm altura fixa. No entanto, existe uma class de bootstrap criada para combater esse problema e executar resets responsivos .

basta criar um vazio

antes do início de cada nova linha para permitir que os flutuantes sejam redefinidos e as colunas retornem às suas posições corretas.

aqui é um bootply .

Obrigado por suas sugestões, você me pegou no caminho certo!

Vamos para uma explicação completa:

  • Por padrão AngularJS http get query retorna um object

  • Portanto, se você quiser usar a function @Ariel Array.prototype.chunk, primeiro é necessário transformar o object em uma matriz.

  • E então, para usar a function chunk EM SEU CONTROLADOR, caso contrário, usado diretamente em ng-repeat, isso levará a um erro infdig . O controlador final parece:

     // 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); }); 

E o HTML se torna:

 

Por outro lado, decidi devolver diretamente um array [] em vez de um object {} do meu arquivo JSON. Desta forma, o controlador se torna (observe a syntax específica 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 permanece o mesmo que acima.

OTIMIZAÇÃO

Última pergunta em suspense é: como torná-lo 100% AngularJS sem estender javascript array com function chunk … se algumas pessoas estão interessadas em nos mostrar se ng-repeat-start e ng-repeat-end são o caminho a percorrer .. . Estou curioso 😉

SOLUÇÃO DE ANDREW

Graças a @Andrew, agora sabemos que adicionar uma class clearfix bootstrap a cada três (ou qualquer número) corrige o problema de exibição da altura do bloco.

Então, o HTML se torna:

 
My product descrition with {{product.property}}

E o seu controlador permanece bastante suave com a function chunck removida :

 // 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; }); 

Baseado na solução Alpar, usando apenas modelos com anidated ng-repeat. Funciona com linhas cheias e parcialmente vazias:

 
{{product}}

JSFiddle

Você pode fazê-lo sem uma diretiva, mas não tenho certeza se é o melhor caminho. Para fazer isso, você deve criar uma matriz de array a partir dos dados que deseja exibir na tabela e, depois disso, usar 2 ng-repeat para percorrer a matriz.

para criar a matriz para exibição use essa function como aquela 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)]; }) ); } 

e então fazer algo assim usando 2 ng-repeat

 
{{item}}

Acabei de fazer uma solução dele funcionando apenas no modelo. A solução é

   
{{product.foo}}

O ponto está usando dados duas vezes, um é para um loop externo. As tags de span extras permanecerão, mas isso depende de como você troca.

Se é um layout de 3 colunas, vai ser como

   
{{product.foo}}

Honestamente eu queria

 $index 

Embora não tenha funcionado.

Apenas outra pequena melhoria sobre a resposta do @Duncan e as outras respostas baseadas no elemento clearfix. Se você quiser tornar o conteúdo clicável , precisará de um z-index > 0 ou um clearfix irá sobrepor o conteúdo e manipular o clique.

Este é o exemplo não está funcionando (você não pode ver o ponteiro do cursor e clicar não fará nada):

 

{{product.title}}

Enquanto esta é a fixa :

 

{{product.title}}

Eu adicionei z-index: 1 para ter o conteúdo aumentado sobre o clearfix e eu removi o div do container usando em vez de ng-repeat-start e ng-repeat-end (disponível em AngularJS 1.2) porque ele fez z-index não está funcionando.

Espero que isto ajude!

Atualizar

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

Eu resolvi isso usando ng-class

 
{{item.name}}

A melhor maneira de aplicar uma class é usar ng-class. Ela pode ser usada para aplicar classs com base em alguma condição.

 

e depois no seu controlador

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

Pouca modificação na solução de @alpar

 
{{products[idx+$parent.$index]}}

jsfiddle

Depois de combinar muitas respostas e sugestões aqui, esta é a minha resposta final, que funciona bem com flex , o que nos permite fazer colunas com a mesma altura, também verifica o último índice, e você não precisa repetir o HTML interno. Não usa clearfix :

 
{{ product.name }}

Ele irá produzir algo como isto:

 
Product Name
Product Name
Product Name
Product Name
Product Name
Product Name

Isso funcionou para mim, sem emenda ou qualquer coisa necessária:

HTML

 

JavaScript

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

Born Solutions é o melhor, só precisa de um pouco de tweek para as necessidades, eu tive diferentes soluções responsivas e mudei um pouco

 

Experimente este exemplo

            
{{products[$index]}}
{{products[$index + 1]}}
{{products[$index + 2]}}

Com base na resposta da Alpar, aqui está uma maneira mais generalizada de dividir uma única lista de itens em vários contêineres (linhas, colunas, baldes, o que for):

 
{{item.name}}

para uma lista de 10 itens, gera:

 
Item 1
Item 4
Item 7
Item 10
Item 2
Item 5
Item 8
Item 3
Item 6
Item 9

O número de contêineres pode ser rapidamente codificado em uma function do controlador:

JS (ES6)

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

HTML

 
...

Essa abordagem evita a duplicação da marcação de itens ( {{item.name}} neste caso) no modelo de origem – não uma grande vitória para uma extensão simples, mas para uma estrutura DOM mais complexa (que eu tinha) isso ajuda a manter o modelo DRY.