In my opinion, the usecase provided is an excellent example of how to create a reusable structural directive!
import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core';
interface CustomContext<T> {
appCustom: T[];
$implicit?: T;
controller: {
next: () => void;
};
}
@Directive({
standalone: true,
selector: '[appCustom]',
})
export class CustomDirective<T> {
private context: CustomContext<T> = {
appCustom: [],
$implicit: undefined,
controller: {
next: () => this.pickNewElement(),
},
};
@Input()
set appCustom(items: T[]) {
this.context.appCustom = items;
this.pickNewElement();
}
constructor(
private templateRef: TemplateRef<any>,
private viewContainer: ViewContainerRef
) {
this.viewContainer.createEmbeddedView(this.templateRef, this.context);
}
private pickNewElement(): void {
this.context.$implicit =
this.context.appCustom[
Math.floor(Math.random() * this.context.appCustom.length)
];
}
}
Usage example:
<ng-container
*appCustom="
['apple', 'banana', 'orange', 'pear'];
let fruit;
let ctrl = controller
"
>
<div>{{ fruit }}</div>
<button (click)="ctrl.next()">Next Fruit</button>
</ng-container>
Give it a try: https://stackblitz.com/edit/angular-ivy-bvsfbe?file=src/app/app.component.html
You can customize the name of the variable that holds the random item. For instance:
<div *appCustom="CarList; let car">
<p>{{ car.Name }}</p>
</div>
Simple and clean template, right?