Eu preciso usar ng-repeat
(no AngularJS) para listar todos os elementos em uma matriz.
A complicação é que cada elemento da matriz se transforma em uma, duas ou três linhas de uma tabela.
Não consigo criar html válido, se ng-repeat
for usado em um elemento, pois nenhum tipo de elemento repetido é permitido entre <tbody>
e<tr>
.
Por exemplo, se eu usasse ng-repeat <span>
, eu obteria:
<table>
<tbody>
<span>
<tr>...</tr>
</span>
<span>
<tr>...</tr>
<tr>...</tr>
<tr>...</tr>
</span>
<span>
<tr>...</tr>
<tr>...</tr>
</span>
</tbody>
</table>
Qual é o html inválido.
Mas o que eu preciso ser gerado é:
<table>
<tbody>
<tr>...</tr>
<tr>...</tr>
<tr>...</tr>
<tr>...</tr>
<tr>...</tr>
<tr>...</tr>
</tbody>
</table>
onde a primeira linha foi gerada pelo primeiro elemento da matriz, as próximas três pela segunda e a quinta e a sexta pelo último elemento da matriz.
Como posso usar ng-repeat de forma que o elemento html ao qual está vinculado 'desapareça' durante a renderização?
Ou existe outra solução para isso?
Esclarecimento: A estrutura gerada deve se parecer com abaixo. Cada elemento da matriz pode gerar entre 1-3 linhas da tabela. A resposta deve idealmente suportar 0-n linhas por elemento da matriz.
<table>
<tbody>
<!-- array element 0 -->
<tr>
<td>One row item</td>
</tr>
<!-- array element 1 -->
<tr>
<td>Three row item</td>
</tr>
<tr>
<td>Some product details</td>
</tr>
<tr>
<td>Customer ratings</td>
</tr>
<!-- array element 2 -->
<tr>
<td>Two row item</td>
</tr>
<tr>
<td>Full description</td>
</tr>
</tbody>
</table>
tr
, obteria uma linha por elemento da matriz, pelo que entendi.tr
s que são gerados por um elemento da matriz não têm a mesma estrutura.Respostas:
Atualização: se você estiver usando o Angular 1.2+, use ng-repeat-start . Veja a resposta de @ jmagnusson.
Caso contrário, que tal colocar o ng-repeat em tbody? (AFAIK, não há problema em ter vários <corpos> em uma única tabela.)
fonte
A partir do AngularJS 1.2, existe uma diretiva chamada
ng-repeat-start
que faz exatamente o que você solicita. Veja minha resposta nesta pergunta para uma descrição de como usá-lo.fonte
Se você usar ng> 1.2, aqui está um exemplo de uso
ng-repeat-start/end
sem gerar tags desnecessárias:O ponto importante: para tags usadas
ng-repeat-start
eng-repeat-end
definidasng-if="0"
, para não serem inseridas na página. Dessa maneira, o conteúdo interno será tratado exatamente como em knockoutjs (usando comandos in<!--...-->
) e não haverá lixo.fonte
Você pode achatar os dados em seu controlador:
E então no HTML:
fonte
ng-repeat-start
,ng-repeat-end
interrompesse meu design, a solução foi criar uma variável extra adicionando esse objeto separador antes de cada elemento e iterar a nova var:<div class="c477_group"> <div class="c477_group_item" ng-repeat="item in itemsWithSeparator" ng-switch="item.id" ng-class="{'-divider' : item.id == 'SEPARATOR'}"> <div class="c478" ng-switch-when="FAS"/> <div class="c478" ng-switch-when="SEPARATOR" /> <div class="c479" ng-switch-default /> </div> </div>
O exposto acima está correto, mas para uma resposta mais geral, não é suficiente. Eu precisava aninhar ng-repeat, mas permanecer no mesmo nível de html, ou seja, escrever os elementos no mesmo pai. A matriz de tags contém tags que também possuem uma matriz de tags. Na verdade, é uma árvore.
Então aqui está o que eu finalmente fiz.
Observe o ng-if = "false" que oculta as divs inicial e final.
Deve imprimir
nome1, nome1_1, nome1_2, nome2, nome2_1, nome2_2,
fonte
Gostaria apenas de comentar, mas ainda falta minha reputação. Então, eu estou adicionando outra solução que resolve o problema também. Eu realmente gostaria de refutar a afirmação feita por @bmoeskau de que resolver este problema requer uma solução "hacky na melhor das hipóteses" e, como isso surgiu recentemente em uma discussão, mesmo que este post tenha 2 anos, eu gostaria de adicionar meu possui dois centavos:
Como o @btford apontou, você parece estar tentando transformar uma estrutura recursiva em uma lista; portanto, você deve achatar essa estrutura em uma lista primeiro. Sua solução faz isso, mas há uma opinião de que chamar a função dentro do modelo é deselegante. se isso for verdade (honestamente, eu não sei), isso não exigiria apenas a execução da função no controlador, em vez da diretiva?
de qualquer forma, seu html requer uma lista; portanto, o escopo que o renderiza deve ter essa lista para trabalhar. você simplesmente precisa achatar a estrutura dentro do seu controlador. Depois de ter uma matriz $ scope.rows, você pode gerar a tabela com uma única e simples repetição de ng. Sem hackers, sem deselegância, simplesmente da maneira como foi projetado para funcionar.
As diretivas angulares não estão faltando funcionalidade. Eles simplesmente forçam você a escrever html válido. Um colega meu teve um problema semelhante, citando @bmoeskau em apoio a críticas sobre recursos de modelagem / renderização angulares. Ao analisar o problema exato, descobriu-se que ele simplesmente queria gerar uma marca aberta, depois uma marca fechada em outro lugar, etc., como nos bons velhos tempos em que concatávamos nosso html de strings .. certo? não.
Quanto ao nivelamento da estrutura em uma lista, aqui está outra solução:
isso funcionará para qualquer estrutura de árvore que tenha subitens. Se você quiser o item inteiro em vez de uma propriedade, poderá reduzir ainda mais a função de nivelamento.
espero que ajude.
fonte
para uma solução que realmente funciona
html
adicione uma diretiva angular.js
para uma breve explicação,
ng-repeat liga-se ao
<remove>
elemento e faz um loop como deveria, e porque usamos ng-repeat-start / ng-repeat-end, ele faz um loop de um bloco de html e não apenas de um elemento.a diretiva de remoção personalizada coloca os
<remove>
elementos de início e fim com<!--removed element-->
fonte
Eu acho que isso é válido :)
fonte