Broadcast component with embedded template

I am using Angular 2-rc3 and have Component , and I want to apply the transition, just differently. Here is my component:

 import { Component, Input } from '@angular/core'; @Component({ selector: 'my-list', template: `<ul> <li *ngFor="let item of data"> -- insert template here -- <ng-content></ng-content> </li> </ul>` }) export class MyListComponent { @Input() data: any[]; } 

And I use it as follows:

 <my-list [data]="cars"> <div>{{item.make | uppercase}}</div> </my-list> 

As you can see, I am trying to determine the inline template that will be used by my component. Now this is going terribly wrong. First, a data binding exception saying can't read property 'make' of undefined . It is trying to read item.make off of my surrounding component, not MyListComponent . But even if I temporarily disable it now:

 <my-list [data]="cars"> <div>{item.make | uppercase}</div> </my-list> 

Then the second problem appears:

 -- insert template here -- -- insert template here -- -- insert template here -- -- insert template here -- {item.make | uppercase} 

So, Angular does not actually copy the template for use in *ngFor , it just binds the elements and is ultimately bound to the last element.

How do I make this work?

I had the same issue with AngularJS where petebacondarwin posted a solution for managing the DOM through compilation , which was great. I have this option with Angular 2 by injecting ElementRef into my component, but! One big difference is that the compile in AngularJS was deleted before the data binding, which means that the template had no problems using {{item.make}} . With Angular 2, this seems bad, as {{item}} parsed in advance. So what is the best way to do this? Using a slightly different notation [[item]] and a line replacing the whole thing does not seem the most elegant way ...

Thanks in advance!

// Edit: Here is Plnkr , which reproduces the problem.

+7
angular angular2-components
source share
2 answers

To state the ngForTemplate method:

( Starting with Angular 4, the element is now called <ng-template> .)

  • Use the <template> tag for both external and internal components instead of <ng-content> .

  • <li> moves to app.component html, and <template> on this component has a special attribute 'let-' , which refers to an iterated variable in the internal component:

     <my-list [data]="cars"> <template let-item> <li> <div>{{item.make | uppercase}}</div> </li> </template> </my-list> 
  • The internal component also has a <template> and uses the ngFor variant like this:

     <ul> <template #items ngFor [ngForOf]="data" [ngForTemplate]="tmpl"> -- insert template here -- </template> </ul> 
  • The variable 'tmpl' assigned to the ngForTemplate attribute must be selected in the component code:

     export class MyListComponent { @Input() data: any[]; @ContentChild(TemplateRef) tmpl: TemplateRef; } 
  • @ContentChild and TemplateRef are Angular bits, so you need to import them

     import { Component, Input, ContentChild, TemplateRef } from '@angular/core'; 

Look at the plug of your plunkr with these changes here plnkr .

This is not the most suitable solution for your stated problem, since you are passing data to a list, you can also have ngFor on the external. In addition, additional content (literal '- insert template here -') is discarded, so you want to show that it should also be on the external template.

I see that this can be useful when the iteration is provided in the internal component (say, from a service call) and, possibly, for some manipulations with the template in the code.

+4
source share
  • <ng-content> inside *ngFor does not work, therefore

     <li *ngFor="let item of data"> -- insert template here -- <ng-content></ng-content> </li> 

will not do anything meaningful. Everything will be translated into the first <ng-content>

https://github.com/angular/angular/issues/8563 can solve some of your requirements.

  • Event binding using ngForTemplate in Angular 2
  • ng-content select a related variable may be an approach that will do something similar, as you demonstrated in your question.
    This requires the user of your component to wrap the content with a <template> .
+1
source share

All Articles