angularjs - example - Repetición angular ng agregar fila de arranque cada 3 o 4 cols
ng-repeat example (18)
Acabo de resolverlo trabajando solo en la plantilla. La solucion es
<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>
El punto está usando datos dos veces, uno es para un bucle externo. Las etiquetas de extensión adicionales permanecerán, pero depende de cómo se intercambie.
Si se trata de un diseño de 3 columnas, será como
<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>
Honestamente queria
$index<Math.ceil(products.length/3)
Aunque no funcionó.
Estoy buscando el patrón correcto para inyectar una clase de fila bootstrap cada 3 columnas. Necesito esto porque cols no tiene una altura fija (y no quiero arreglar una), ¡así que rompe mi diseño!
Aquí está mi código:
<div ng-repeat="product in products">
<div ng-if="$index % 3 == 0" class="row">
<div class="col-sm-4" >
...
</div>
</div>
</div>
Pero solo muestra un producto en cada fila. Lo que quiero como resultado final es:
<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>
¿Puedo lograr esto solo con el patrón ng-repeat (sin directiva o controlador)? Los docs introducen ng-repeat-start y ng-repeat-end, pero no puedo entender cómo usarlo, ¡es este caso de uso! ¡Siento que esto es algo que usamos a menudo en las plantillas de bootstrap! ? Gracias
Basado en la solución Alpar, utilizando solo plantillas con ng-repeat anidado. Funciona con filas completas y parcialmente vacías:
<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>
Bien, esta solución es mucho más simple que las que ya están aquí, y permite diferentes anchos de columna para diferentes anchos de dispositivo.
<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>
Tenga en cuenta que se supone que la parte
% 6
es igual al número de columnas resultantes.
Entonces, si en el elemento de columna tiene la clase
col-lg-2
, habrá 6 columnas, así que use
... % 6
.
Esta técnica (excluyendo el
ng-if
) está realmente documentada aquí:
Bootstrap docs
Born Solutions es la mejor, solo necesito un poco para modificar las necesidades, tuve diferentes soluciones receptivas y cambié un poco
<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>
Después de combinar muchas respuestas y sugerencias aquí, esta es mi respuesta final, que funciona bien con
flex
, que nos permite hacer columnas con la misma altura, también verifica el último índice y no es necesario repetir el HTML interno.
No usa
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>
Producirá algo como esto:
<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>
Esto funcionó para mí, sin empalmes ni nada requerido:
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;
};
Gracias por tus sugerencias, me tienes en el camino correcto!
Vamos para una explicación completa:
-
Por defecto, AngularJS http get query devuelve un objeto
-
Entonces, si desea utilizar la función @Ariel Array.prototype.chunk, primero debe transformar el objeto en una matriz.
-
Y luego, para usar la función de fragmento EN SU CONTROLADOR, de lo contrario, si se usa directamente en ng-repeat, le llevará a un error infdig . El controlador final se ve:
// 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); });
Y HTML se convierte en:
<div class="row" ng-repeat="productrow in products">
<div class="col-sm-4" ng-repeat="product in productrow">
Por otro lado, decidí devolver directamente una matriz [] en lugar de un objeto {} de mi archivo JSON. De esta manera, el controlador se convierte (tenga en cuenta la sintaxis 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 se mantiene igual que el anterior.
MEJORAMIENTO
La última pregunta en suspenso es: cómo hacerlo 100% AngularJS sin extender la matriz de JavaScript con la función Chunk ... si algunas personas están interesadas en mostrarnos si ng-repeat-start y ng-repeat-end son el camino a seguir ... . Soy curioso ;)
SOLUCIÓN DE ANDREW
Gracias a @Andrew, ahora sabemos que agregar una clase de corrección de bootstrap cada tres elementos (o cualquier número) corrige el problema de visualización desde diferentes alturas del bloque.
Entonces HTML se convierte en:
<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}}
Y su controlador se mantiene bastante suave con la función Chunck eliminada :
// 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;
});
La mejor manera de aplicar una clase es usar ng-class. Se puede usar para aplicar clases según alguna condición.
<div ng-repeat="product in products">
<div ng-class="getRowClass($index)">
<div class="col-sm-4" >
<!-- your code -->
</div>
</div>
y luego en tu controlador
$scope.getRowClass = function(index){
if(index%3 == 0){
return "row";
}
}
La respuesta más votada, si bien es efectiva, no es lo que yo consideraría que es la forma angular, ni está usando las propias clases de bootstrap que están destinadas a hacer frente a esta situación.
Como @claies mencionó, la clase
.clearfix
está destinada a situaciones como estas.
En mi opinión, la implementación más limpia es la siguiente:
<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>
Esta estructura evita la indexación desordenada de la matriz de productos, permite una notación de puntos limpia y hace uso de la clase clearfix para su propósito previsto.
Lo hice solo usando boostrap, debes tener mucho cuidado en la ubicación de la fila y la columna, aquí está mi ejemplo.
<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>
Pequeña modificación en la solución de @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>
Puede hacerlo sin una directiva, pero no estoy seguro de que sea la mejor manera. Para hacer esto, debe crear una matriz de matriz a partir de los datos que desea mostrar en la tabla, y luego usar 2 ng-repeat para recorrer la matriz.
para crear la matriz para mostrar, use esta función como productos.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)];
})
);
}
y luego hacer algo así usando 2 ng-repeat
<div class="row" ng-repeat="row in products.chunk(3)">
<div class="col-sm4" ng-repeat="item in row">
{{item}}
</div>
</div>
Sé que es un poco tarde, pero aún podría ayudar a alguien. Lo hice así:
<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>
Si bien lo que desea lograr puede ser útil, hay otra opción que creo que puede pasar por alto que es mucho más simple.
Tienes razón, las tablas Bootstrap actúan de manera extraña cuando tienes columnas que no tienen una altura fija. Sin embargo, hay una clase bootstrap creada para combatir este problema y realizar restablecimientos receptivos .
simplemente cree un
<div class="clearfix"></div>
vacío antes del comienzo de cada nueva fila para permitir que los flotadores se reinicien y las columnas vuelvan a sus posiciones correctas.
Aquí hay un bootply .
Sobre la base de la respuesta de Alpar, aquí hay una forma más generalizada de dividir una sola lista de elementos en múltiples contenedores (filas, columnas, cubos, lo que sea):
<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>
para una lista de 10 elementos, genera:
<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>
El número de contenedores se puede codificar rápidamente en una función de controlador:
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">
...
Este enfoque evita duplicar el marcado del elemento (
<span>{{item.name}}</span>
en este caso) en la plantilla de origen; no es una gran ganancia para un lapso simple, sino para una estructura DOM más compleja (que yo had) esto ayuda a mantener la plantilla SECA.
Solo otra pequeña mejora sobre la
respuesta @Duncan
y las otras respuestas basadas en el elemento clearfix.
Si desea hacer
clic en
el contenido, necesitará un
z-index
> 0 o clearfix se superpondrá al contenido y manejará el clic.
Este es el ejemplo que no funciona (no puede ver el puntero del cursor y hacer clic no hará nada):
<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>
Si bien este es el fijo :
<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>
Agregué
z-index: 1
para que el contenido aumente sobre el clearfix y eliminé el contenedor div usando en su lugar
ng-repeat-start
y
ng-repeat-end
(disponible en AngularJS 1.2) porque hizo el índice z no funciona.
¡Espero que esto ayude!
Actualizar
Plunker: http://plnkr.co/edit/4w5wZj
resolví esto usando ng-class
<div ng-repeat="item in items">
<div ng-class="{ ''row'': ($index + 1) % 4 == 0 }">
<div class="col-md-3">
{{item.name}}
</div>
</div>
</div>
Actualización 2019 - Bootstrap 4
Debido a que Bootstrap 3 usaba flotantes, se requería que
clearfix restableciera
cada
n
(3 o 4) columnas (
.col-*
) en el
.row
para evitar el
.row
desigual de las columnas.
Ahora que Bootstrap 4 usa
flexbox
, ya no es necesario envolver columnas en etiquetas
.row
separadas, o insertar divs adicionales para forzar a cols a envolver cada
n
columnas.
Simplemente puede repetir
todas
las columnas en un solo contenedor
.row
.
Por ejemplo, 3 columnas en cada fila visual es:
<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>
Entonces, para Bootstrap, la repetición ng es simplemente:
<div class="row">
<div class="col-4" ng-repeat="item in items">
... {{ item }}
</div>
</div>
Demostración: https://www.codeply.com/go/Z3IjLRsJXX