example bootstrap javascript angularjs angularjs-ng-repeat

javascript - example - cómo dividir los datos ng-repeat con tres columnas usando bootstrap



tooltip bootstrap (19)

Aquí hay una manera fácil de hacerlo. Es más manual y termina con marcado desordenado. No lo recomiendo, pero hay situaciones en las que esto podría ser útil.

Aquí hay un enlace de violín http://jsfiddle.net/m0nk3y/9wcbpydq/

HTML:

<div ng-controller="myController"> <div class="row"> <div class="col-sm-4"> <div class="well"> <div ng-repeat="person in people = data | limitTo:Math.ceil(data.length/3)"> {{ person.name }} </div> </div> </div> <div class="col-sm-4"> <div class="well"> <div ng-repeat="person in people = data | limitTo:Math.ceil(data.length/3):Math.ceil(data.length/3)"> {{ person.name }} </div> </div> </div> <div class="col-sm-4"> <div class="well"> <div ng-repeat="person in people = data | limitTo:Math.ceil(data.length/3):Math.ceil(data.length/3)*2"> {{ person.name }} </div> </div> </div> </div> </div>

JS:

var app = angular.module(''myApp'', []); app.controller(''myController'', function($scope) { $scope.Math = Math; $scope.data = [ {"name":"Person A"}, ... ]; });

Esta configuración requiere que usemos algunas Matemáticas en el marcado: /, por lo que necesitará inyectar Matemáticas agregando esta línea: $scope.Math = Math;

Estoy usando ng-repeat con mi código Tengo ''n'' número de cuadro de texto basado en ng-repeat. Quiero alinear el cuadro de texto con tres columnas.

este es mi código

<div class="control-group" ng-repeat="oneExt in configAddr.ext"> {{$index+1}}. <input type="text" name="macAdr{{$index+1}}" id="macAddress" ng-model="oneExt.newValue" value=""/> </div>


Basándose en la muy buena respuesta de m59. Descubrí que las entradas del modelo serían borrosas si cambiaban, por lo que solo podía cambiar un carácter a la vez. Este es uno nuevo para listas de objetos para cualquier persona que lo necesite:

EDITAR Actualizado para manejar múltiples filtros en una página

app.filter(''partition'', function() { var cache = {}; // holds old arrays for difference repeat scopes var filter = function(newArr, size, scope) { var i, oldLength = 0, newLength = 0, arr = [], id = scope.$id, currentArr = cache[id]; if (!newArr) return; if (currentArr) { for (i = 0; i < currentArr.length; i++) { oldLength += currentArr[i].length; } } if (newArr.length == oldLength) { return currentArr; // so we keep the old object and prevent rebuild (it blurs inputs) } else { for (i = 0; i < newArr.length; i += size) { arr.push(newArr.slice(i, i + size)); } cache[id] = arr; return arr; } }; return filter; });

Y este sería el uso:

<div ng-repeat="row in items | partition:3:this"> <span class="span4"> {{ $index }} </span> </div>


El enfoque más confiable y técnicamente correcto es transformar los datos en el controlador. Aquí hay una función y uso simple de los fragmentos.

function chunk(arr, size) { var newArr = []; for (var i=0; i<arr.length; i+=size) { newArr.push(arr.slice(i, i+size)); } return newArr; } $scope.chunkedData = chunk(myData, 3);

Entonces su vista se vería así:

<div class="row" ng-repeat="rows in chunkedData"> <div class="span4" ng-repeat="item in rows">{{item}}</div> </div>

Si tiene entradas dentro de la ng-repeat , probablemente quiera desencofrar / volver a unir las matrices a medida que se modifiquen los datos o al enviarlos. Así es como se vería en $watch , para que los datos estén siempre disponibles en el formato original y fusionado:

$scope.$watch(''chunkedData'', function(val) { $scope.data = [].concat.apply([], val); }, true); // deep watch

Muchas personas prefieren lograr esto en la vista con un filtro. ¡Esto es posible, pero solo debe usarse con fines de visualización! Si agrega entradas dentro de esta vista filtrada, causará problemas que pueden resolverse, pero no son bonitos ni confiables .

El problema con este filtro es que devuelve nuevas matrices anidadas cada vez. Angular está mirando el valor de retorno del filtro. La primera vez que se ejecuta el filtro, Angular conoce el valor y luego lo vuelve a ejecutar para asegurarse de que se haya modificado. Si ambos valores son iguales, el ciclo finaliza. De lo contrario, el filtro disparará una y otra vez hasta que sean iguales, o Angular se dará cuenta de que se está produciendo un ciclo de digestión infinito y se apaga. Debido a que Angular nunca rastreó nuevas matrices / objetos anidados, siempre ve el valor de retorno como diferente del anterior. Para arreglar estos filtros "inestables", debe envolver el filtro en una función memoize . lodash tiene una función para memoize y la última versión de lodash también incluye una función de chunk , por lo que podemos crear este filtro de manera muy simple utilizando módulos npm y compilando el script con browserify o webpack .

Recuerde: ¡solo exhibición! ¡Filtra en el controlador si estás usando entradas!

Instala lodash:

npm install lodash-node

Crea el filtro:

var chunk = require(''lodash-node/modern/array/chunk''); var memoize = require(''lodash-node/modern/function/memoize''); angular.module(''myModule'', []) .filter(''chunk'', function() { return memoize(chunk); });

Y aquí hay una muestra con este filtro:

<div ng-repeat="row in [''a'',''b'',''c'',''d'',''e'',''f''] | chunk:3"> <div class="column" ng-repeat="item in row"> {{($parent.$index*row.length)+$index+1}}. {{item}} </div> </div>

Ordenar artículos verticalmente

1 4 2 5 3 6

En cuanto a las columnas verticales (lista de arriba a abajo) en lugar de horizontal (de izquierda a derecha), la implementación exacta depende de la semántica deseada. Las listas que se dividen de manera desigual se pueden distribuir de diferentes maneras. Aquí hay una forma:

<div ng-repeat="row in columns"> <div class="column" ng-repeat="item in row"> {{item}} </div> </div>

var data = [''a'',''b'',''c'',''d'',''e'',''f'',''g'']; $scope.columns = columnize(data, 3); function columnize(input, cols) { var arr = []; for(i = 0; i < input.length; i++) { var colIdx = i % cols; arr[colIdx] = arr[colIdx] || []; arr[colIdx].push(input[i]); } return arr; }

Sin embargo, la forma más directa y sencilla de obtener columnas es usar columnas CSS :

.columns { columns: 3; }

<div class="columns"> <div ng-repeat="item in [''a'',''b'',''c'',''d'',''e'',''f'',''g'']"> {{item}} </div> </div>


Esta solución es muy simple:

JSON:

[{id:"1",name:"testA"},{id:"2",name:"test B"},{id:"3",name:"test C"},{id:"4",name:"test D"},{id:"5",name:"test E"}]

HTML:

<div ng-controller="MyCtrl"> <table> <tr ng-repeat="item in items" ng-switch on="$index % 3"> <td ng-switch-when="0"> {{items[$index].id}} {{items[$index].name}} </td> <td ng-switch-when="0"> <span ng-show="items[$index+1]"> {{items[$index+1].id}} {{items[$index+1].name}} </span> </td> <td ng-switch-when="0"> <span ng-show="items[$index+2]"> {{items[$index+2].id}} {{items[$index+2].name}} </span> </td> </tr> </table> </div>

DEMO en FIDDLE


Este ejemplo produce un repetidor anidado donde los datos externos incluyen una matriz interna que quería enumerar en dos columnas. El concepto sería válido para tres o más columnas.

En la columna interna, repito la "fila" hasta que se alcanza el límite. El límite se determina dividiendo la longitud de la matriz de elementos por el número de columnas deseado, en este caso por dos. El método de división se ubica en el controlador y se pasa la longitud de la matriz actual como parámetro. La función de división de JavaScript (0, array.length / columnCount) luego aplicó el límite al repetidor.

El repetidor de la segunda columna se invoca y repite slice (array.length / columnCount, array.length) que produce la segunda mitad de la matriz en la columna dos.

<div class="row" ng-repeat="GroupAccess in UsersController.SelectedUser.Access" ng-class="{even: $even, odd: $odd}"> <div class="col-md-12 col-xs-12" style=" padding-left:15px;"> <label style="margin-bottom:2px;"><input type="checkbox" ng-model="GroupAccess.isset" />{{GroupAccess.groupname}}</label> </div> <div class="row" style=" padding-left:15px;"> <div class="col-md-1 col-xs-0"></div> <div class="col-md-3 col-xs-2"> <div style="line-height:11px; margin-left:2px; margin-bottom:2px;" ng-repeat="Feature in GroupAccess.features.slice(0, state.DivideBy2(GroupAccess.features.length))"> <span class="GrpFeature">{{Feature.featurename}}</span> </div> </div> <div class="col-md-3 col-xs-2"> <div style="line-height:11px; margin-left:2px; margin-bottom:2px;" ng-repeat="Feature in GroupAccess.features.slice( state.DivideBy2(GroupAccess.features.length), GroupAccess.features.length )"> <span class="GrpFeature">{{Feature.featurename}}</span> </div> </div> <div class="col-md-5 col-xs-8"> </div> </div> </div> // called to format two columns state.DivideBy2 = function(nValue) { return Math.ceil(nValue /2); };

Espero que esto ayude a ver la solución de otra manera. (PD este es mi primer post aquí! :-))


La respuesta de m59 es bastante buena. Lo único que no me gusta es que utiliza div s para lo que potencialmente podrían ser datos para una tabla.

Entonces, junto con el filtro de m59 (responda en algún lugar arriba), aquí se muestra cómo mostrarlo en una tabla.

<table> <tr class="" ng-repeat="rows in foos | chunk:2"> <td ng-repeat="item in rows">{{item}}</td> </tr> </table>


Lo arreglo sin .row

<div class="col col-33 left" ng-repeat="photo in photos"> Content here... </div>

y css

.left { float: left; }


Lo siguiente es una manera más simple:

<table> <tr ng-repeat="item in lists" ng-hide="$index%2!==0"> <td> <label>{{ lists[$index].name}}</label> </td> <td ng-hide="!lists[$index+1]"> <label>{{ lists[$index+1].name}}</label> </td> </tr> </table>

La respuesta de Cumulo Nimbus es útil para mí, pero quiero que esta cuadrícula esté envuelta por un div que puede mostrar la barra de desplazamiento cuando la lista es demasiado larga.

Para lograr esto, agregué style="height:200px; overflow:auto" a un div alrededor de la tabla que hace que se muestre como una sola columna.

Ahora funciona para una matriz de longitud de uno.


Lodash tiene un método de fragmento incorporado ahora que yo personalmente uso: https://lodash.com/docs#chunk

En función de esto, el código del controlador podría ser similar al siguiente:

$scope.groupedUsers = _.chunk( $scope.users, 3 )

Ver código:

<div class="row" ng-repeat="rows in groupedUsers"> <div class="span4" ng-repeat="item in rows">{{item}}</div> </div>


Me encontré en un caso similar, queriendo generar grupos de visualización de 3 columnas cada uno. Sin embargo, aunque estaba usando bootstrap, intentaba separar estos grupos en diferentes divs parentales. También quería hacer algo genéricamente útil.

Me acerqué a él con 2 ng-repeat como a continuación:

<div ng-repeat="items in quotes" ng-if="!($index % 3)"> <div ng-repeat="quote in quotes" ng-if="$index <= $parent.$index + 2 && $index >= $parent.$index"> ... some content ... </div> </div>

Esto hace que sea muy fácil cambiar a un número diferente de columnas, y se divide en varios DIV padres.


Mi enfoque fue una mezcla de cosas.

Mi objetivo era tener una grilla que se adaptara al tamaño de la pantalla. Quería 3 columnas para lg , 2 columnas para sm y md , y 1 columna para xs .

Primero, creé la siguiente función de alcance, usando el servicio angular $window :

$scope.findColNumberPerRow = function() { var nCols; var width = $window.innerWidth; if (width < 768) { // xs nCols = 1; } else if(width >= 768 && width < 1200) { // sm and md nCols = 2 } else if (width >= 1200) { // lg nCols = 3; } return nCols; };

Luego, utilicé la clase propuesta por @Cumulo Nimbus:

.new-row { clear: left; }

En el div que contiene ng-repeat , agregué la directiva de resizable variable, como se explica en esta página , de modo que cada vez que se cambia el tamaño de la $window servicio $window angular se actualiza con los nuevos valores.

En definitiva, en el div repetido tengo:

ng-repeat="user in users" ng-class="{''new-row'': ($index % findColNumberPerRow() === 0) }"

Por favor, háganme saber cualquier falla en este enfoque.

Espero que pueda ser útil.


Otra forma es establecer el width:33.33%; float:left width:33.33%; float:left to a wrapper div como este:

<div ng-repeat="right in rights" style="width: 33.33%;float: left;"> <span style="width:60px;display:inline-block;text-align:right">{{$index}}</span> <input type="number" style="width:50px;display:inline-block" "> </div>


Soy nuevo en bootstrap y angularjs, pero esto también podría hacer Array por 4 elementos como un solo grupo, el resultado será casi como 3 columnas. Este truco usa el principio de la línea de corte bootstrap.

<div class="row"> <div class="col-sm-4" data-ng-repeat="item in items"> <div class="some-special-class"> {{item.XX}} </div> </div> </div>


Tengo una función y la guardé en un servicio para que pueda usarla en toda mi aplicación:

Servicio:

app.service(''SplitArrayService'', function () { return { SplitArray: function (array, columns) { if (array.length <= columns) { return [array]; }; var rowsNum = Math.ceil(array.length / columns); var rowsArray = new Array(rowsNum); for (var i = 0; i < rowsNum; i++) { var columnsArray = new Array(columns); for (j = 0; j < columns; j++) { var index = i * columns + j; if (index < array.length) { columnsArray[j] = array[index]; } else { break; } } rowsArray[i] = columnsArray; } return rowsArray; } }

});

Controlador:

$scope.rows = SplitArrayService.SplitArray($scope.images, 3); //im splitting an array of images into 3 columns

Margen:

<div class="col-sm-12" ng-repeat="row in imageRows"> <div class="col-sm-4" ng-repeat="image in row"> <img class="img-responsive" ng-src="{{image.src}}"> </div> </div>


Todas estas respuestas parecen masivamente sobrediseñadas.

Con mucho, el método más simple sería configurar los divs de entrada en un bootstrap de columna col-md-4, luego el bootstrap lo formateará automáticamente en 3 columnas debido a la naturaleza de 12 columnas de bootstrap:

<div class="col-md-12"> <div class="control-group" ng-repeat="oneExt in configAddr.ext"> <div class="col-md-4"> <input type="text" name="macAdr{{$index}}" id="macAddress" ng-model="oneExt.newValue" value="" /> </div> </div> </div>


Un truco simple con CSS "clearfix" recomendado por Bootstrap:

<div class="row"> <div ng-repeat-start="value in values" class="col-md-4"> {{value}} </div> <div ng-repeat-end ng-if="$index % 3 == 0" class="clearfix"></div> </div>

Muchas ventajas: Eficiente, rápido, utilizando las recomendaciones de Boostrap, evitando posibles problemas de $ digest y sin alterar el modelo angular.


Una solución limpia y adaptable que no requiere manipulación de datos :

El HTML:

<div class="control-group" class="label" ng-repeat="oneExt in configAddr.ext" ng-class="{''new-row'': startNewRow($index, columnBreak) }"> {{$index+1}}. <input type="text" name="macAdr{{$index+1}}" id="macAddress{{$index}}" ng-model="oneExt.newValue" /> </div>

El CSS:

.label { float: left; text-align: left; } .new-row { clear: left; }

El JavaScript:

$scope.columnBreak = 3; //Max number of colunms $scope.startNewRow = function (index, count) { return ((index) % count) === 0; };

Esta es una solución simple para representar datos en filas y columnas de forma dinámica sin necesidad de manipular la matriz de datos que está tratando de mostrar. Además, si intenta cambiar el tamaño de la ventana del navegador, puede ver que la cuadrícula se adapta dinámicamente al tamaño de la pantalla / div.

(También agregué un sufijo de {{$ index}} a su ID ya que ng-repeat intentará crear múltiples elementos con la misma identificación si no lo hace).

Un ejemplo de trabajo similar


esto responde la pregunta original que es cómo obtener 1,2,3 en una columna. - Preguntado por kuppu el 8 de febrero a las 13:47

código angularjs:

function GetStaffForFloor(floor) { var promiseGet = Directory_Service.getAllStaff(floor); promiseGet.then(function (pl) { $scope.staffList = chunk(pl.data, 3); //pl.data; // }, function (errorOD) { $log.error(''Errored while getting staff list.'', errorOD); }); } function chunk(array, columns) { var numberOfRows = Math.ceil(array.length / columns); //puts 1, 2, 3 into column var newRow = []; //array is row-based. for (var i = 0; i < array.length; i++) { var columnData = new Array(columns); if (i == numberOfRows) break; for (j = 0; j < columns; j++) { columnData[j] = array[i + numberOfRows * j]; } newRow.push(columnData); } return newRow; ////this works but 1, 2, 3 is in row //var newRow = []; //for (var i = 0; i < array.length; i += columns) { // newRow.push(array.slice(i, i + columns)); //push effectively does the pivot. array is row-based. //} //return newRow; };

Ver código (nota: usando bootstrap 3):

<div class="staffContainer"> <div class="row" ng-repeat="staff in staffList"> <div class="col-md-4" ng-repeat="item in staff">{{item.FullName.length > 0 ? item.FullName + ": Rm " + item.RoomNumber : ""}}</div> </div> </div>


<div class="row"> <div class="col-md-4" ng-repeat="remainder in [0,1,2]"> <ul> <li ng-repeat="item in items" ng-if="$index % 3 == remainder">{{item}}</li> </ul> </div> </div>