Как использовать ng-repeat без элемента html
Мне нужно использовать ng-repeat
(в AngularJS), чтобы отобразить все элементы в массиве.
Усложнение состоит в том, что каждый элемент массива будет преобразовываться в одну, две или три строки таблицы.
Я не могу создать допустимый html, если ng-repeat
используется для элемента, поскольку между <tbody>
и <tr>
не разрешен тип повторяющегося элемента.
Например, если я использовал ng-repeat на <span>
, я бы получил:
<table>
<tbody>
<span>
<tr>...</tr>
</span>
<span>
<tr>...</tr>
<tr>...</tr>
<tr>...</tr>
</span>
<span>
<tr>...</tr>
<tr>...</tr>
</span>
</tbody>
</table>
Недопустимый html.
Но мне нужно создать следующее:
<table>
<tbody>
<tr>...</tr>
<tr>...</tr>
<tr>...</tr>
<tr>...</tr>
<tr>...</tr>
<tr>...</tr>
</tbody>
</table>
где первая строка была сгенерирована первым элементом массива, а следующие три - вторым, а пятым и шестым - последним элементом массива.
Как я могу использовать ng-repeat таким образом, чтобы элемент html, с которым он привязан, "исчезает" во время рендеринга?
Или есть другое решение?
Разъяснение: Сгенерированная структура должна выглядеть следующим образом. Каждый элемент массива может генерировать между 1-3 строками таблицы. Ответ должен в идеале поддерживать 0-n строк для элемента массива.
<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>
Ответы
Ответ 1
Обновление: Если вы используете Angular 1.2+, используйте ng-repeat-start. См. Ответ @jmagnusson.
В противном случае, как насчет ввода ng-repeat на tbody? (AFAIK, все в порядке, чтобы иметь несколько элементов в одной таблице.)
<tbody ng-repeat="row in array">
<tr ng-repeat="item in row">
<td>{{item}}</td>
</tr>
</tbody>
Ответ 2
В соответствии с AngularJS 1.2 существует директива, называемая ng-repeat-start
, которая делает именно то, что вы просите. См. Мой ответ в этом вопросе для описания того, как его использовать.
Ответ 3
Если вы используете ng > 1.2, вот пример использования ng-repeat-start/end
без создания ненужных тегов:
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script>
angular.module('mApp', []);
</script>
</head>
<body ng-app="mApp">
<table border="1" width="100%">
<tr ng-if="0" ng-repeat-start="elem in [{k: 'A', v: ['a1','a2']}, {k: 'B', v: ['b1']}, {k: 'C', v: ['c1','c2','c3']}]"></tr>
<tr>
<td rowspan="{{elem.v.length}}">{{elem.k}}</td>
<td>{{elem.v[0]}}</td>
</tr>
<tr ng-repeat="v in elem.v" ng-if="!$first">
<td>{{v}}</td>
</tr>
<tr ng-if="0" ng-repeat-end></tr>
</table>
</body>
</html>
Ответ 4
Возможно, вы захотите сгладить данные в своем контроллере:
function MyCtrl ($scope) {
$scope.myData = [[1,2,3], [4,5,6], [7,8,9]];
$scope.flattened = function () {
var flat = [];
$scope.myData.forEach(function (item) {
flat.concat(item);
}
return flat;
}
}
И затем в HTML:
<table>
<tbody>
<tr ng-repeat="item in flattened()"><td>{{item}}</td></tr>
</tbody>
</table>
Ответ 5
Вышеприведенное правильно, но для более общего ответа этого недостаточно. Мне нужно было вложить ng-repeat, но оставайтесь на том же уровне html, что означает запись элементов в одном и том же родителе.
Массив тегов содержит теги (метки), которые также имеют массив меток.
Это фактически дерево.
[{ name:'name1', tags: [
{ name: 'name1_1', tags: []},
{ name: 'name1_2', tags: []}
]},
{ name:'name2', tags: [
{ name: 'name2_1', tags: []},
{ name: 'name2_2', tags: []}
]}
]
Итак, вот что я в итоге сделал.
<div ng-repeat-start="tag1 in tags" ng-if="false"></div>
{{tag1}},
<div ng-repeat-start="tag2 in tag1.tags" ng-if="false"></div>
{{tag2}},
<div ng-repeat-end ng-if="false"></div>
<div ng-repeat-end ng-if="false"></div>
Обратите внимание на ng-if = "false", который скрывает начальные и конечные divs.
Он должен печатать
имя1, name1_1, name1_2, имя2, NAME2_1, name2_2,
Ответ 6
Я хотел бы просто прокомментировать, но моей репутации все еще не хватает. Поэтому я добавляю другое решение, которое также решает проблему. Я действительно хотел бы опровергнуть выражение, сделанное @bmoeskau о том, что решение этой проблемы требует решения "взлома в лучшем случае", и поскольку это появилось в последнее время в обсуждении, хотя этому сообщению 2 года, я хотел бы добавить свой собственные два цента:
Как отметил @btford, вы пытаетесь превратить рекурсивную структуру в список, поэтому сначала нужно сгладить эту структуру в списке. Его решение делает это, но есть мнение, что вызов функции внутри шаблона является неэлегантным. если это правда (честно говоря, я не знаю), не нужно ли просто выполнять функцию в контроллере, а не директиву?
в любом случае, ваш html требует список, поэтому область, которая его отображает, должна иметь этот список для работы. вам просто нужно сгладить структуру внутри вашего контроллера. если у вас есть массив $scope.rows, вы можете создать таблицу с помощью простого простого ng-повтора. Никаких взломов, неловкости, просто того, как она была разработана для работы.
Угловые директивы не имеют функциональности. Они просто заставляют вас писать допустимый html. У моего коллеги была аналогичная проблема, сославшись на @bmoeskau в поддержку критики в отношении функций шаблонов/рендеринга углов. Если посмотреть на точную проблему, оказалось, что он просто хотел создать открытый тег, затем тег close в другом месте и т.д., Как в старые добрые времена, когда мы будем конкатцировать наш html из строк. Правильно? нет.
как для выравнивания структуры в список, здесь другое решение:
// assume the following structure
var structure = [
{
name: 'item1', subitems: [
{
name: 'item2', subitems: [
],
}
],
}
];
var flattened = structure.reduce((function(prop,resultprop){
var f = function(p,c,i,a){
p.push(c[resultprop]);
if (c[prop] && c[prop].length > 0 )
p = c[prop].reduce(f,p);
return p;
}
return f;
})('subitems','name'),[]);
// flattened now is a list: ['item1', 'item2']
это будет работать для любой древовидной структуры, которая имеет подпункты. Если вам нужен весь элемент вместо свойства, вы можете еще больше сократить функцию сглаживания.
надеюсь, что это поможет.
Ответ 7
вы можете использовать функцию сглаживания подчеркивания $scope.myData= _.flatten($scope.myData);
Ответ 8
для решения, которое действительно работает
HTML
<remove ng-repeat-start="itemGroup in Groups" ></remove>
html stuff in here including inner repeating loops if you want
<remove ng-repeat-end></remove>
добавить директиву angular.js
//remove directive
(function(){
var remove = function(){
return {
restrict: "E",
replace: true,
link: function(scope, element, attrs, controller){
element.replaceWith('<!--removed element-->');
}
};
};
var module = angular.module("app" );
module.directive('remove', [remove]);
}());
для краткого объяснения,
ng-repeat связывается с элементом <remove>
и выполняет циклы, как и должно быть, и поскольку мы использовали ng-repeat-start/ng-repeat-end, он циклически повторяет блок html, а не просто элемент.
затем пользовательская директива удаления помещает начальный и конечный элементы <remove>
<!--removed element-->
Ответ 9
<table>
<tbody>
<tr><td>{{data[0].foo}}</td></tr>
<tr ng-repeat="d in data[1]"><td>{{d.bar}}</td></tr>
<tr ng-repeat="d in data[2]"><td>{{d.lol}}</td></tr>
</tbody>
</table>
Я думаю, что это действительно:)