I personally think that usecase is a great example to create a structural directive you can reuse!
import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core';
interface RandomContext<T> {
appRandom: T[];
$implicit?: T;
controller: {
next: () => void;
};
}
@Directive({
standalone: true,
selector: '[appRandom]',
})
export class RandomDirective<T> {
private context: RandomContext<T> = {
appRandom: [],
$implicit: undefined,
controller: {
next: () => this.pickNewElement(),
},
};
@Input()
set appRandom(elements: T[]) {
this.context.appRandom = elements;
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.appRandom[
Math.floor(Math.random() * this.context.appRandom.length)
];
}
}
Example usage:
<ng-container
*appRandom="
['foo', 'bar', 'hello', 'world'];
let random;
let ctrl = controller
"
>
<div>{{ random }}</div>
<button (click)="ctrl.next()">Randomize</button>
</ng-container>
Try this out: https://stackblitz.com/edit/angular-ivy-bvsfbe?file=src/app/app.component.html
Of course you can leave out the button, I added it for demonstration purposes. Instead of the string you add your object array, random yields the random picked object then, you can also pick another name instead of random. This would look like:
<div *appRandom="ImageList; let image">
<img [src]="image.Url"/>
</div>
Clean template, isn't it?