Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create table composed by multiple components

So, as I started to dig in to angular2, I figured I create a table listing persons. One component for creating the table (person-list), and one for component for each person in the table (person-list-item).

Easy peezy, right? With the below output I realised it was not that easy. As you can see, the table rows are not following the table structure.

enter image description here

By viewing the html in the inspector we can also see that the <person-list-item> is ruining the table.

enter image description here

Is there a way to solve this problem, or should I just create the table rows in the <person-list> element in order to not let the browser ruin the table? I guess this is an issue that applies to other cases where multiple components would ruin a certain DOM element.

app.component

import {PersonListComponent} from './person-list.component';
import {Component} from 'angular2/core';

let template=`
<person-list></person-list>
`;

@Component({
    selector:'appz',
    template:template,
    providers:[PersonService],
    directives:[PersonListComponent]
})

export class AppComponent {
    public title;

    constructor(private _personService: PersonService) { 
        this.title=_personService.getPersons();
    }
}

person-list.component

import {Component} from 'angular2/core';
import {PersonListItemComponent} from './person-list-item.component';
import {Person} from './person';

let template=`
    <h3>Persons</h3>
    <table class="table">
        <thead>
            <tr>
                <th>Firstname</th>
                <th>Lastname</th>
                <th>Age</th>
            </tr>
        </thead>
        <tbody>
            <person-list-item 
                [firstName]="'John'"
                [lastName]="'Doe'"
                [age]='44'>
            </person-list-item>
            <person-list-item 
                [firstName]="'Foo'"
                [lastName]="'Bar'"
                [age]='34'>
            </person-list-item>
        </tbody>
    </table>
`;

@Component({
    selector:'person-list',
    template:template,
    directives:[PersonListItemComponent],
    inputs:['persons']
})
export class PersonListComponent {
    public persons: Person[];
};

person-list-item.component

import {Component} from 'angular2/core';

let template=`
    <tr>
        <td>{{firstName}}</td>
        <td>{{lastName}}</td>
        <td>{{age}}</td>            
    </tr>
`;

@Component({
    selector:'person-list-item',
    template: template,
    inputs:['firstName', 'lastName', 'age']
})

export class PersonListItemComponent {
    public firstName;
    public lastName;
    public age;
}
like image 817
cbass Avatar asked Jan 06 '16 12:01

cbass


2 Answers

Just use an attribute or class selector instead of the tag selector for your component

for example selector: 'tr[person-list-item]' and use it like

<tr person-list-item>

or selector: 'tr[personListItem]' and <tr personListItem>

Alternatively you can use other ways to build a table. For example like shown in https://github.com/dart-lang/polymer-dart-patterns/blob/b3e8a306d05a9f3aae695a75ca5f4e3dccd64cf5/web/control_flow/using_template_repeat_with_a_table_row/my_element.html for a similar use case for Polymer where CSS is used to set div to behave like a table/tr/td

<style>
  .table {
    display: table;
  }
  .row {
    display: table-row;
  }
  .cell {
    display: table-cell;
  }
</style>
<div class="table">
  <template is="dom-repeat" items="{{fruits}}" as="fruit">
    <div class="row">
      <div class="cell">{{fruit}}</div>
    </div>
  </template>
</div>
like image 158
Günter Zöchbauer Avatar answered Oct 08 '22 16:10

Günter Zöchbauer


Unless PersonListItemComponent will someday be more complicated, I would dispense with that component and generate the rows in PersonListComponent using the <template> form of NgFor, which allows for multiple elements to be repeated.

Note: as Günter Zöchbauer mentions in the comments below, some browsers currently do not support <template> elements inside <table> elements. So this approach may be a bit premature.

import {Component, Input} from 'angular2/core';
@Component({
  selector: 'person-list',
  template: `
    <table>
      <tbody>
        <template ngFor #person [ngForOf]="people">
          <tr>
            <td>{{person.name}}
            <td>{{person.age}}
        </template>
      </tbody>
    </table>
  `,
  styles: ['td { border: 1px solid gray } ']
})
export class PersonListComponent {
  @Input() people;
}
@Component({
  selector: 'my-app',
  template: `<person-list [people]="people"></person-list>`,
  directives: [PersonListComponent]
})
export class AppComponent {
  people = [ { name: 'Mark', age: "over 40" }, {name: 'cbass', age: "24?" }];
  constructor() { console.clear(); }
}

plunker

like image 25
Mark Rajcok Avatar answered Oct 08 '22 14:10

Mark Rajcok