Skip to content

Instantly share code, notes, and snippets.

@ierhalim
Last active August 1, 2021 19:29
Show Gist options
  • Save ierhalim/297ef69d64e7a64119fcf87579f189de to your computer and use it in GitHub Desktop.
Save ierhalim/297ef69d64e7a64119fcf87579f189de to your computer and use it in GitHub Desktop.
Alternate NgTemplate
import { Component, forwardRef, Input, TemplateRef } from '@angular/core';
import { APP_TEMPLATE_CONSUMER_ACCESSOR, TemplateConsumer } from '../models/TemplateConsumer';
@Component({
selector: 'app-my-alternate-list',
template: `
<div class="my-list">
<ng-container *ngIf="!!data && data.length > 0 else emptyTemplate">
<div class="list-item" *ngFor="let item of data">
<ng-container *ngTemplateOutlet="itemTemplate;context:{item:item}"></ng-container>
</div>
</ng-container>
</div>
`,
// Providing the component instance as TemplateConsumer
providers: [{
provide: APP_TEMPLATE_CONSUMER_ACCESSOR,
useExisting: forwardRef(() => MyAlternateListComponent)
}]
})
export class MyAlternateListComponent implements TemplateConsumer {
@Input()
data: Array<unknown>;
itemTemplate: TemplateRef<unknown>;
emptyTemplate: TemplateRef<unknown>;
private readonly templateNameSetters = {
item: (templateRef: TemplateRef<unknown>) => {
this.itemTemplate = templateRef;
},
empty: (templateRef: TemplateRef<unknown>) => {
this.emptyTemplate = templateRef;
}
};
setTemplate(name: string, template: TemplateRef<unknown>) {
if (!!this.templateNameSetters[name]) {
this.templateNameSetters[name](template);
} else {
// Optional, Throwing an error can cause usability difficulties in some cases.
throw new Error(`'${name}' template is not supported by '${MyAlternateListComponent.name}'`);
}
}
}
import { Directive, Inject, Input, TemplateRef } from "@angular/core";
import { APP_TEMPLATE_CONSUMER_ACCESSOR, TemplateConsumer } from "./models/TemplateConsumer";
@Directive({
selector: '[appTemplate]'
})
export class TemplateDirective {
constructor(
// Injecting the component instance that provides APP_TEMPLATE_CONSUMER_ACCESSOR
@Inject(APP_TEMPLATE_CONSUMER_ACCESSOR) private readonly templateConsumer: TemplateConsumer,
private readonly templateRef: TemplateRef<unknown>
) { }
private _appTemplate: string;
@Input()
set appTemplate(value: string) {
this._appTemplate = value;
this.templateConsumer.setTemplate(value, this.templateRef);
}
get appTemplate(): string {
return this._appTemplate;
}
}
import { InjectionToken, TemplateRef } from "@angular/core";
export interface TemplateConsumer{
setTemplate(name: string, template: TemplateRef<unknown>);
}
export const APP_TEMPLATE_CONSUMER_ACCESSOR =
new InjectionToken<ReadonlyArray<TemplateConsumer>>('TemplateConsumerAccessor');
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment