diff --git a/apps/angular/3-directive-enhancement/src/app/app.component.ts b/apps/angular/3-directive-enhancement/src/app/app.component.ts
index cd1d5f23c..3834c6030 100644
--- a/apps/angular/3-directive-enhancement/src/app/app.component.ts
+++ b/apps/angular/3-directive-enhancement/src/app/app.component.ts
@@ -1,5 +1,5 @@
-import { NgFor, NgIf } from '@angular/common';
import { ChangeDetectionStrategy, Component } from '@angular/core';
+import { NgForDirective } from './ng-for.directive';
interface Person {
name: string;
@@ -7,14 +7,12 @@ interface Person {
@Component({
standalone: true,
- imports: [NgFor, NgIf],
+ imports: [NgForDirective],
selector: 'app-root',
template: `
- 0; else emptyList">
-
- {{ person.name }}
-
-
+
+ {{ person.name }}
+
The list is empty !!
`,
styles: [],
diff --git a/apps/angular/3-directive-enhancement/src/app/ng-for.directive.ts b/apps/angular/3-directive-enhancement/src/app/ng-for.directive.ts
new file mode 100644
index 000000000..dc276da0b
--- /dev/null
+++ b/apps/angular/3-directive-enhancement/src/app/ng-for.directive.ts
@@ -0,0 +1,60 @@
+import {
+ Directive,
+ effect,
+ inject,
+ input,
+ TemplateRef,
+ ViewContainerRef,
+} from '@angular/core';
+
+interface NgForDirectiveContext {
+ $implicit: T;
+}
+
+@Directive({
+ selector: '[appNgFor]',
+ standalone: true,
+})
+export class NgForDirective {
+ private readonly viewContainer = inject(ViewContainerRef);
+ private readonly templateRef = inject(TemplateRef);
+
+ appNgForOf = input();
+ appNgForEmpty = input>();
+
+ constructor() {
+ effect(() => {
+ const items = this.appNgForOf();
+ const empty = this.appNgForEmpty();
+ this.render(items, empty);
+ });
+ }
+
+ private render(items?: T[], empty?: TemplateRef) {
+ if (items && items.length > 0) {
+ this.viewContainer.clear();
+ items.forEach((item) => {
+ this.viewContainer.createEmbeddedView(this.templateRef, {
+ $implicit: item,
+ });
+ });
+ } else {
+ this.viewContainer.clear();
+ if (empty) {
+ this.viewContainer.createEmbeddedView(empty);
+ }
+ }
+ }
+
+ /**
+ * The guard body is not used at runtime, and included only to avoid
+ * TypeScript errors.
+ * @See https://angular.dev/guide/directives/structural-directives#typing-the-directives-context
+ */
+ static ngTemplateContextGuard(
+ dir: NgForDirective,
+ ctx: any,
+ ): ctx is NgForDirectiveContext {
+ return true;
+ }
+}