Programming

HTML 요소없이 ng-repeat를 사용하는 방법

procodes 2020. 6. 21. 20:58
반응형

HTML 요소없이 ng-repeat를 사용하는 방법


ng-repeat배열의 모든 요소를 ​​나열 하려면 (AngularJS에서) 사용해야 합니다.

복잡한 점은 배열의 각 요소가 테이블의 1, 2 또는 3 행으로 변환된다는 것입니다.

ng-repeat사이에 반복되는 요소 유형이 없으므로 요소에 사용되는 경우 유효한 HTML을 만들 수 없습니다 .<tbody><tr>

예를 들어, ng-repeat on을 사용하면 다음과 같은 결과가 나타납니다 <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>          

업데이트 : Angular 1.2 이상을 사용하는 경우 ng-repeat-start를 사용하십시오 . @jmagnusson의 답변을 참조하십시오.

그렇지 않으면 ng-repeat를 tbody에 넣는 것은 어떻습니까? (AFAIK, 단일 테이블에 여러 <tbody>가 있으면 괜찮습니다.)

<tbody ng-repeat="row in array">
  <tr ng-repeat="item in row">
     <td>{{item}}</td>
  </tr>
</tbody>

AngularJS 1.2부터는 ng-repeat-start정확히 요청하는 것을 지시하는 지시문 이 있습니다. 사용 방법에 대한 설명은 이 질문에 대한 답변 참조하십시오 .


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>

The important point: for tags used for ng-repeat-start and ng-repeat-end set ng-if="0", to let not be inserted in the page. In this way the inner content will be handled exactly as it is in knockoutjs (using commands in <!--...-->), and there will be no garbage.


You might want to flatten the data within your controller:

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;
  }
}

And then in the HTML:

<table>
  <tbody>
    <tr ng-repeat="item in flattened()"><td>{{item}}</td></tr>
  </tbody>
</table>

The above is correct but for a more general answer it is not enough. I needed to nest ng-repeat, but stay on the same html level, meaning write the elements in the same parent. The tags array contain tag(s) that also have a tags array. It is actually a tree.

[{ name:'name1', tags: [
  { name: 'name1_1', tags: []},
  { name: 'name1_2', tags: []}
  ]},
 { name:'name2', tags: [
  { name: 'name2_1', tags: []},
  { name: 'name2_2', tags: []}
  ]}
]

So here is what I eventually did.

<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>

Note the ng-if="false" that hides the start and end divs.

It should print

name1,name1_1,name1_2,name2,name2_1,name2_2,


I would like to just comment, but my reputation is still lacking. So i'm adding another solution which solves the problem as well. I would really like to refute the statement made by @bmoeskau that solving this problem requires a 'hacky at best' solution, and since this came up recently in a discussion even though this post is 2 years old, i'd like to add my own two cents:

As @btford has pointed out, you seem to be trying to turn a recursive structure into a list, so you should flatten that structure into a list first. His solution does that, but there is an opinion that calling the function inside the template is inelegant. if that is true (honestly, i dont know) wouldnt that just require executing the function in the controller rather than the directive?

either way, your html requires a list, so the scope that renders it should have that list to work with. you simply have to flatten the structure inside your controller. once you have a $scope.rows array, you can generate the table with a single, simple ng-repeat. No hacking, no inelegance, simply the way it was designed to work.

Angulars directives aren't lacking functionality. They simply force you to write valid html. A colleague of mine had a similar issue, citing @bmoeskau in support of criticism over angulars templating/rendering features. When looking at the exact problem, it turned out he simply wanted to generate an open-tag, then a close tag somewhere else, etc.. just like in the good old days when we would concat our html from strings.. right? no.

as for flattening the structure into a list, here's another solution:

// 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']

this will work for any tree-like structure that has sub items. If you want the whole item instead of a property, you can shorten the flattening function even more.

hope that helps.


for a solution that really works

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>

add an angular.js directive

//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]);
}());

for a brief explanation,

ng-repeat binds itself to the <remove> element and loops as it should, and because we have used ng-repeat-start / ng-repeat-end it loops a block of html not just an element.

then the custom remove directive places the <remove> start and finish elements with <!--removed element-->


<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>

I think that this is valid :)

참고URL : https://stackoverflow.com/questions/11490968/how-to-use-ng-repeat-without-an-html-element

반응형