Добавление строк с ng-repeat и вложенным циклом
Я ищу способ добавления строк в таблицу. Моя структура данных выглядит так:
rows = [
{ name : 'row1', subrows : [{ name : 'row1.1' }, { name : 'row1.2' }] },
{ name : 'row2' }
];
Я хочу создать таблицу, которая выглядит так:
table
row1
row1.1
row1.2
row2
Возможно ли это с помощью angular js ng-repeat? Если нет, то каким образом это будет
Изменить:
Сгладить массив было бы плохое решение, потому что, если я могу перебирать вспомогательные элементы, я мог бы использовать разные теги html внутри ячеек, другие классы css и т.д.
Ответы
Ответ 1
Вы не сможете сделать это с помощью ng-repeat. Однако вы можете сделать это с помощью директивы.
<my-table rows='rows'></my-table>
Fiddle.
myApp.directive('myTable', function () {
return {
restrict: 'E',
link: function (scope, element, attrs) {
var html = '<table>';
angular.forEach(scope[attrs.rows], function (row, index) {
html += '<tr><td>' + row.name + '</td></tr>';
if ('subrows' in row) {
angular.forEach(row.subrows, function (subrow, index) {
html += '<tr><td>' + subrow.name + '</td></tr>';
});
}
});
html += '</table>';
element.replaceWith(html)
}
}
});
Ответ 2
Более года спустя, но нашел обходное решение, по крайней мере, для двух уровней (отцов → сыновей).
Просто повторите tbody
's:
<table>
<tbody ng-repeat="row in rows">
<tr>
<th>{{row.name}}</th>
</tr>
<tr ng-repeat="sub in row.subrows">
<td>{{sub.name}}</td>
</tr>
</tbody>
</table>
Насколько я знаю, все браузеры поддерживают несколько элементов tbody
внутри таблицы.
Ответ 3
Более 3 лет спустя, я столкнулся с той же проблемой, и перед тем, как записать директиву, я попробовал это, и это сработало для меня:
<table>
<tbody>
<tr ng-repeat-start="row in rows">
<td>
{{ row.name }}
</td>
</tr>
<tr ng-repeat-end ng-repeat="subrow in row.subrows">
<td>
{{ subrow.name }}
</td>
</tr>
</tbody>
</table>
Ответ 4
Я немного удивлен, что многие из них выступают за пользовательские директивы и создают переменные прокси, обновляемые $watch.
Подобные проблемы являются причиной того, что были созданы фильтры AngularJS!
Из документов:
A filter formats the value of an expression for display to the user.
Мы не пытаемся манипулировать данными, просто отформатируем его для отображения по-другому. Поэтому сделаем фильтр, который принимает в нашем массиве строк, выравнивает его и возвращает сплющенные строки.
.filter('flattenRows', function(){
return function(rows) {
var flatten = [];
angular.forEach(rows, function(row){
subrows = row.subrows;
flatten.push(row);
if(subrows){
angular.forEach(subrows, function(subrow){
flatten.push( angular.extend(subrow, {subrow: true}) );
});
}
});
return flatten;
}
})
Теперь нам нужно добавить фильтр в ngRepeat:
<table class="table table-striped table-hover table-bordered">
<thead>
<tr>
<th>Rows with filter</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="row in rows | flattenRows">
<td>{{row.name}}</td>
</tr>
</tbody>
</table>
Теперь вы можете комбинировать таблицу с другими фильтрами, если хотите, например, поиск.
В то время как подход с несколькими телами удобен и действителен, он испортит любой css, который опирается на порядок или индекс дочерних строк, таких как "полосатая" таблица, а также делает предположение, что вы не создали свой стиль чтобы вы не хотели повторять.
Здесь plunk: http://embed.plnkr.co/otjeQv7z0rifPusneJ0F/preview
Редактировать: я добавил значение подземелья и использовал его в таблице, чтобы показать, какие строки являются подвигами, поскольку вы указали на заботу о том, что сможете это сделать.
Ответ 5
Да, возможно:
Контроллер:
app.controller('AppController',
[
'$scope',
function($scope) {
$scope.rows = [
{ name : 'row1', subrows : [{ name : 'row1.1' }, { name : 'row1.2' }] },
{ name : 'row2' }
];
}
]
);
HTML:
<table>
<tr ng-repeat="row in rows">
<td>
{{row.name}}
<table ng-show="row.subrows">
<tr ng-repeat="subrow in row.subrows">
<td>{{subrow.name}}</td>
</tr>
</table>
</td>
</tr>
</table>
Plunker
Если вы не хотите подтаблицы, сгладьте строки (в то время как аннотации подвих, чтобы можно было различать):
Контроллер:
function($scope) {
$scope.rows = [
{ name : 'row1', subrows : [{ name : 'row1.1' }, { name : 'row1.2' }] },
{ name : 'row2' }
];
$scope.flatten = [];
var subrows;
$scope.$watch('rows', function(rows){
var flatten = [];
angular.forEach(rows, function(row){
subrows = row.subrows;
delete row.subrows;
flatten.push(row);
if(subrows){
angular.forEach(subrows, function(subrow){
flatten.push( angular.extend(subrow, {subrow: true}) );
});
}
});
$scope.flatten = flatten;
});
}
HTML:
<table>
<tr ng-repeat="row in flatten">
<td>
{{row.name}}
</td>
</tr>
</table>
Plunker
Ответ 6
Вот пример. Этот код печатает все имена всех людей в массиве peopeByCity
.
TS:
export class AppComponent {
peopleByCity = [
{
city: 'Miami',
people: [
{
name: 'John', age: 12
}, {
name: 'Angel', age: 22
}
]
}, {
city: 'Sao Paulo',
people: [
{
name: 'Anderson', age: 35
}, {
name: 'Felipe', age: 36
}
]
}
]
}
HTML:
<div *ngFor="let personsByCity of peopleByCity">
<div *ngFor="let person of personsByCity.people">
{{ person.name }}
</div>
</div>