How to create a component with a dynamic template? (Component translates with built-in template)

I am trying to create a component that has a dynamic template string inside it that can access local variables in the template. Each approach I tried ends up with the fact that the "dynamic line of the template" is not $compile 'd (angular 1 terminology, please excuse me).

Here is the code for the component below. Where you see the comment, I would like to insert a template line that can refer to item in ngFor .

 @Component({ selector: 'ion-alpha-scroll', template: ` <ion-scroll [ngStyle]="calculateScrollHeight()" scrollX="false" scrollY="true"> <ion-list class="ion-alpha-list-outer"> <div *ngFor="let items of sortedItems | mapToIterable;"> <ion-item-divider id="scroll-letter-{{items.key}}">{{items.key}}</ion-item-divider> <ion-item *ngFor="let item of items.value"> <!-- how can I pass a dynamic template here that can reference item ? --> </ion-item> </div> </ion-list> </ion-scroll> <ul class="ion-alpha-sidebar" [ngStyle]="calculateDimensionsForSidebar()"> <li (click)="alphaScrollGoToList(letter)" *ngFor="let letter of alphabet"> <div class="letter">{{letter}}</div> </li> </ul> `, pipes: [MapToIterable] }) export class IonAlphaScroll { @Input() listData: any; @Input() key: string; @Input() template: string; .... } 

Ideally, I would like to have the translated content of the ion-alpha-scroll item ngFor in ngFor . I tried using ng-content in the required ngFor component and no luck -

 <ion-alpha-scroll *ngIf="breeds" [listData]="breeds" key="$t"> {{item.$t}} </ion-alpha-scroll> 

One thing I tried was this:

 <ion-alpha-scroll *ngIf="breeds" [listData]="breeds" key="$t" [template]="alphaScrollTemplate"> </ion-alpha-scroll> 

alphaScrollTemplate is just a string containing {{item.$t}} . Then I tried to reference it in the component where the comment asks the question, but it does not work -

 ... <ion-item *ngFor="let item of items.value"> {{template}} <!-- this just outputs {{item.$t}} literally --> </ion-item> ... 

I am really wondering if this is possible even with angular 2. I just found this question, which is very similar to mine . Any help or suggestions would be greatly appreciated, thanks.

0
angular angular2-components
source share
1 answer

Here is the solution I used for angular 2.0.0-rc.3

This solution creates a dynamic component and loads it using ViewContainerRef and ComponentFactory . Here is the ionic component 2 on GitHub .

 export function createComponentFactory(resolver: ComponentResolver, metadata: ComponentMetadata): Promise<ComponentFactory<any>> { const cmpClass = class DynamicComponent {}; const decoratedCmp = Component(metadata)(cmpClass); return resolver.resolveComponent(decoratedCmp); } @Directive({ selector: 'dynamic-html-outlet', }) export class DynamicHTMLOutlet { @Input() src: string; @Input() ionAlphaScrollRef: any; @Input() currentPageClass: any; constructor(private vcRef: ViewContainerRef, private resolver: ComponentResolver) { } ngOnChanges() { if (!this.src) return; const metadata = new ComponentMetadata({ selector: 'dynamic-html', template: this.src, pipes: [MapToIterable] }); createComponentFactory(this.resolver, metadata).then(factory => { const injector = ReflectiveInjector.fromResolvedProviders([], this.vcRef.parentInjector); let component = this.vcRef.createComponent(factory, 0, injector, []); component.instance.ionAlphaScrollRef = this.ionAlphaScrollRef; component.instance.currentPageClass = this.currentPageClass; }); } } @Component({ selector: 'ion-alpha-scroll', template: ` <dynamic-html-outlet [src]="alphaScrollTemplate" [ionAlphaScrollRef]="ionAlphaScrollRef" [currentPageClass]="currentPageClass"> </dynamic-html-outlet> `, pipes: [MapToIterable], directives: [DynamicHTMLOutlet] }) export class IonAlphaScroll { @Input() listData: any; @Input() key: string; @Input() itemTemplate: string; @Input() currentPageClass: any; @Input() triggerChange: any; private _scrollEle: HTMLElement; sortedItems: any = {}; alphabet: any = []; alphaScrollTemplate: string; ionAlphaScrollRef = this; constructor( @Host() private _content: Content, private _elementRef: ElementRef, private vcRef: ViewContainerRef, private resolver: ComponentResolver ) { } ngOnInit() { this.alphaScrollTemplate = ` <style> .ion-alpha-sidebar { position: fixed; right: 0; display: flex; flex-flow: column; z-index: 50000; } .ion-alpha-sidebar li { flex: 1 1 auto; list-style: none; width: 15px; text-align: center; } </style> <ion-scroll class="ion-alpha-scroll" [ngStyle]="ionAlphaScrollRef.calculateScrollDimensions()" scrollX="false" scrollY="true"> <ion-list class="ion-alpha-list-outer"> <div *ngFor="let items of ionAlphaScrollRef.sortedItems | mapToIterable; trackBy:ionAlphaScrollRef.trackBySortedItems"> <ion-item-divider id="scroll-letter-{{items.key}}">{{items.key}}</ion-item-divider> <ion-item *ngFor="let item of items.value"> ${this.itemTemplate} </ion-item> </div> </ion-list> </ion-scroll> <ul class="ion-alpha-sidebar" [ngStyle]="ionAlphaScrollRef.calculateDimensionsForSidebar()"> <li *ngFor="let letter of ionAlphaScrollRef.alphabet" tappable (click)="ionAlphaScrollRef.alphaScrollGoToList(letter)"> <a>{{letter}}</a> </li> </ul> `; setTimeout(() => { this._scrollEle = this._elementRef.nativeElement.querySelector('scroll-content'); this.setupHammerHandlers(); }); } ngOnChanges(changes: {[propertyName: string]: SimpleChange}) { let tmp = {}; for (let i = 0; i < this.listData.length; i++) { let letter = this.listData[i][this.key].toUpperCase().charAt(0); if (typeof tmp[letter] === 'undefined') { tmp[letter] = []; } tmp[letter].push(this.listData[i]); } this.alphabet = this.iterateAlphabet(tmp); this.sortedItems = tmp; } // .... } 
0
source share

All Articles