Adding rows with ng-repeat and nested loop

前端 未结 6 910
情书的邮戳
情书的邮戳 2020-12-02 15:25

I\'m looking for a way to add rows to a table. My data structure looks like that:

  rows = [
    { name : \'row1\', subrows : [{ name : \'row1.1\' }, { name          


        
相关标签:
6条回答
  • 2020-12-02 15:55

    You won't be able to do this with ng-repeat. You can do it with a directive, however.

    <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)
            }
        }
    });
    
    0 讨论(0)
  • 2020-12-02 16:00

    I'm a bit surprised that so many are advocating custom directives and creating proxy variables being updated by $watch.

    Problems like this are the reason that AngularJS filters were made!

    From the docs:

    A filter formats the value of an expression for display to the user.
    

    We aren't looking to manipulate the data, just format it for display in a different way. So let's make a filter that takes in our rows array, flattens it, and returns the flattened rows.

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

    Now all we need is to add the filter to 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>
    

    You are now free to combine your table with other filters if desired, like a search.

    While the multiple tbody approach is handy, and valid, it will mess up any css that relies on the order or index of child rows, such as a "striped" table and also makes the assumption that you haven't styled your tbody in a way that you don't want repeated.

    Here's a plunk: http://embed.plnkr.co/otjeQv7z0rifPusneJ0F/preview

    Edit:I added a subrow value and used it in the table to show which rows are subrows, as you indicated a concern for being able to do that.

    0 讨论(0)
  • 2020-12-02 16:03

    Here is an example. This code prints all names of all the people within the peopeByCity array.

    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>
    
    0 讨论(0)
  • 2020-12-02 16:07

    More than 3 years later, I have been facing the same issue, and before writing down a directive I tried this out, and it worked well for me :

    <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>
    
    0 讨论(0)
  • Yes, it's possible:

    Controller:

    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

    In case you don't want sub-tables, flatten the rows (while annotating subrows, to be able to differentiate):

    Controller:

    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

    0 讨论(0)
  • 2020-12-02 16:16

    More than one year later but found a workaround, at least for two levels (fathers->sons).
    Just repeat 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>
    

    As far as I know all browsers support multiple tbody elements inside a table.

    0 讨论(0)
提交回复
热议问题