3

I am using the Angular2 Material grid list component and I want to split the list and the item in separate components.

Here's my list:

@Component({
  selector: 'app-list',
  template: `
    <md-grid-list cols="12">
        <app-item *ngFor="let item of items"></app-item>
    </md-grid-list>
  `
})
export class ListComponent {
  items: Array<number> = [1, 2]; // dummy data
}

Here is my item component:

@Component({
  selector: 'app-item',
  template: `
    <md-grid-tile [colspan]="6">
      First
    </md-grid-tile>
    <md-grid-tile [colspan]="6">
      Second
    </md-grid-tile>
  `
})
export class ItemComponent implements OnInit { }

The issue is that the child item component gets rendered in the actual DOM inside a wrapper <app-item> custom (invalid) DOM element. And the styles are broken because the Angular2 Material grid list component expects the following structure:

<md-grid-list cols="12">
  <!-- Item 1 -->
  <md-grid-tile [colspan]="6"></md-grid-tile>
  <md-grid-tile [colspan]="6"></md-grid-tile>

  <!-- Item 2 -->
  <md-grid-tile [colspan]="6"></md-grid-tile>
  <md-grid-tile [colspan]="6"></md-grid-tile>
</md-grid-list>

... but the actual DOM structure is:

<md-grid-list cols="12">
  <!-- Item 1 -->
  <app-item> <!-- same issue if I replace this with `div` or `span` -->
    <md-grid-tile [colspan]="6"></md-grid-tile>
    <md-grid-tile [colspan]="6"></md-grid-tile>
  </app-item>

  <!-- Item 2 -->
  <app-item>
    <md-grid-tile [colspan]="6"></md-grid-tile>
    <md-grid-tile [colspan]="6"></md-grid-tile>
  </app-item>
</md-grid-list>

I have looked at ng-content, DynamicComponentLoader, the ViewContainerRef, but they don't seem to provide a solution to this as far as I can see.

I read the response here, but the attribute selectors don't work for me as well. It doesn't matter if the wrapping component is <app-item> or <div> or <span> or whatever, the styling always breaks.

Does anybody know if I can render a child component without any parent wrapper? Is there a workaround you can suggest for my use-case?

Daniel
  • 3,541
  • 3
  • 33
  • 46
Kaloyan Kosev
  • 12,483
  • 8
  • 59
  • 90

2 Answers2

6

@sergeras, the solution you proposed doesn't work.

I was very surprised that the approach by using attribute selectors and <ng-container> is causing an error and I raised an issue in the Angular Material 2 official repository.

Jeremy Elbourn, one of the top contributors to the Angular Material 2, provided an explanation:

... you can view the grid-list as a single UI component with a specific API. Placing the grid tiles inside of another component hides them completely from the grid list since each component is effectively a black box.

Therefore, the answer to my question is: It is currently not possible to separate in different Angular 2 components the list and the list item of the Angular2 Material grid list component. And there is no workaround.

Community
  • 1
  • 1
Kaloyan Kosev
  • 12,483
  • 8
  • 59
  • 90
0

You can use attribute selectors and ng-container, which would make your parent component like this:

@Component({
  selector: 'app-list',
  template: `
    <md-grid-list cols="12">
        <ng-container appItem *ngFor="let item of items"></ng-container>
    </md-grid-list>
  `
})

And then the child component would be like this:

@Component({
  selector: '[appItem]',
  template: `
    <md-grid-tile [colspan]="6">
      First
    </md-grid-tile>
    <md-grid-tile [colspan]="6">
      Second
    </md-grid-tile>
  `
})
export class VehiclesItemComponent implements OnInit { }
sargeras
  • 179
  • 1
  • 14
  • 1
    Hm, this solution fires the following error: `Failed to execute 'appendChild' on 'Node': This node type does not support this method.` Am I missing something? – Kaloyan Kosev Feb 21 '17 at 13:30
  • I got the same result as @KaloyanKosev when I tried this. It looks like ng-container doesn't like attribute selectors... – João Mendes Mar 09 '17 at 13:20
  • @JoãoMendes I found [an answer](http://stackoverflow.com/a/42958860/1333836) to our question! Sadly, it turned out that the thing we want to achieve is not possible. I haven't found any workaround yet. – Kaloyan Kosev Mar 22 '17 at 17:40
  • It does not work for grid list, but it does work in general case (outside of material2), right? – charlie_pl May 06 '17 at 17:21