# ng-template and ng-container Reference

Template fragments and grouping elements.

## ng-template Basics

### Creating Fragments

```html
<ng-template #myFragment>
  <h3>Template content</h3>
  <p>Not rendered until explicitly instantiated</p>
</ng-template>
```

### Rendering with NgTemplateOutlet

```typescript
import { NgTemplateOutlet } from '@angular/common';

@Component({
  imports: [NgTemplateOutlet],
  template: `
    <ng-template #greeting><h1>Hello</h1></ng-template>
    <ng-container *ngTemplateOutlet="greeting"></ng-container>
  `
})
```

### Passing Context

```html
<ng-template #userCard let-user="user" let-index="idx">
  <div>#{{index}}: {{user.name}}</div>
</ng-template>

<ng-container
  *ngTemplateOutlet="userCard; context: {user: currentUser(), idx: 0}">
</ng-container>
```

**$implicit for default parameter:**

```html
<ng-template #simple let-value>
  <p>{{value}}</p>
</ng-template>

<ng-container *ngTemplateOutlet="simple; context: {$implicit: 'Hello'}">
</ng-container>
```

## Accessing Templates

### ViewChild

```typescript
@Component({
  template: `
    <ng-template #myTemplate><p>Content</p></ng-template>
    <button (click)="render()">Render</button>
  `
})
export class MyComponent {
  myTemplate = viewChild<TemplateRef<unknown>>('myTemplate');
  viewContainer = inject(ViewContainerRef);

  render() {
    this.viewContainer.createEmbeddedView(this.myTemplate()!);
  }
}
```

### ContentChild

```typescript
@Component({
  selector: 'ui-dialog',
  template: `<ng-container *ngTemplateOutlet="contentTemplate()"></ng-container>`
})
export class DialogComponent {
  contentTemplate = contentChild<TemplateRef<unknown>>('content');
}
```

**Usage:**
```html
<ui-dialog>
  <ng-template #content>
    <h2>Dialog Content</h2>
  </ng-template>
</ui-dialog>
```

## Programmatic Rendering

### ViewContainerRef

```typescript
@Component({
  template: `
    <ng-template #dynamic let-title>
      <h2>{{title}}</h2>
    </ng-template>
    <button (click)="addView()">Add</button>
  `
})
export class DynamicComponent {
  dynamic = viewChild<TemplateRef<{ $implicit: string }>>('dynamic');
  viewContainer = inject(ViewContainerRef);
  views: EmbeddedViewRef<any>[] = [];

  addView() {
    const view = this.viewContainer.createEmbeddedView(
      this.dynamic()!,
      { $implicit: `View ${this.views.length + 1}` }
    );
    this.views.push(view);
  }
}
```

### Custom Directive

```typescript
@Directive({ selector: '[appDynamicHost]', standalone: true })
export class DynamicHostDirective {
  viewContainer = inject(ViewContainerRef);

  render(template: TemplateRef<any>, context?: any) {
    this.viewContainer.clear();
    this.viewContainer.createEmbeddedView(template, context);
  }
}
```

## ng-container Patterns

Groups elements without DOM node:

```html
<!-- Without extra wrapper -->
<p>
  Hero's name is
  <ng-container @if="hero()">{{hero().name}}</ng-container>.
</p>
```

### Use Cases

**1. Structural directives without wrappers:**
```html
<div>
  <ng-container @if="showSection()">
    <h2>Title</h2>
    <p>Content</p>
  </ng-container>
</div>
```

**2. Grouping multiple elements:**
```html
<ul>
  @for (category of categories(); track category.id) {
    <ng-container>
      <li class="header">{{category.name}}</li>
      @for (item of category.items; track item.id) {
        <li>{{item.name}}</li>
      }
    </ng-container>
  }
</ul>
```

**3. Conditional options:**
```html
<select [(ngModel)]="value">
  @for (group of groups(); track group.id) {
    <optgroup [label]="group.label">
      @for (opt of group.options; track opt.id) {
        <ng-container @if="opt.isEnabled">
          <option [value]="opt.value">{{opt.label}}</option>
        </ng-container>
      }
    </optgroup>
  }
</select>
```

**4. Template outlets:**
```html
<div>
  <ng-container *ngTemplateOutlet="header()"></ng-container>
  <main><ng-container *ngTemplateOutlet="content()"></ng-container></main>
  <ng-container *ngTemplateOutlet="footer()"></ng-container>
</div>
```

**5. ViewContainerRef injection:**
```typescript
@Directive({ selector: '[appDynamic]', standalone: true })
export class DynamicDirective {
  viewContainer = inject(ViewContainerRef); // Injects at ng-container
}
```

```html
<ng-container appDynamic></ng-container>
```

## Advanced Patterns

### Reusable Repeater

```typescript
@Component({
  selector: 'ui-repeater',
  imports: [NgTemplateOutlet],
  template: `
    @for (item of items(); track trackBy(item)) {
      <ng-container
        *ngTemplateOutlet="itemTemplate(); context: { $implicit: item, index: $index }">
      </ng-container>
    }
  `
})
export class RepeaterComponent<T> {
  items = input.required<T[]>();
  itemTemplate = contentChild.required<TemplateRef<{ $implicit: T; index: number }>>('item');
  trackBy = input<(item: T) => any>((item: any) => item);
}
```

### Template Polymorphism

```typescript
@Component({
  selector: 'ui-card-list',
  imports: [NgTemplateOutlet],
  template: `
    @for (item of items(); track item.id) {
      @switch (item.type) {
        @case ('product') {
          <ng-container *ngTemplateOutlet="productTpl(); context: { $implicit: item }"></ng-container>
        }
        @case ('service') {
          <ng-container *ngTemplateOutlet="serviceTpl(); context: { $implicit: item }"></ng-container>
        }
        @default {
          <ng-container *ngTemplateOutlet="defaultTpl(); context: { $implicit: item }"></ng-container>
        }
      }
    }
  `
})
export class CardListComponent {
  items = input.required<Item[]>();
  productTpl = contentChild.required<TemplateRef<{ $implicit: Item }>>('product');
  serviceTpl = contentChild.required<TemplateRef<{ $implicit: Item }>>('service');
  defaultTpl = contentChild.required<TemplateRef<{ $implicit: Item }>>('default');
}
```

## Context Scoping

Templates evaluate in **declaration context**, not render context:

```typescript
@Component({
  selector: 'parent',
  template: `
    <ng-template #tpl>
      <p>{{parentValue()}}</p> <!-- Evaluates in parent -->
    </ng-template>
    <child [template]="tpl"></child>
  `
})
export class ParentComponent {
  parentValue = signal('Parent');
}

@Component({
  selector: 'child',
  imports: [NgTemplateOutlet],
  template: `<ng-container *ngTemplateOutlet="template()"></ng-container>`
})
export class ChildComponent {
  template = input.required<TemplateRef<void>>();
}
```

**Override with context:**
```typescript
<ng-container
  *ngTemplateOutlet="template(); context: { childData: childValue() }">
</ng-container>
```

## Common Pitfalls

1. **Forgetting context:** `<ng-container *ngTemplateOutlet="tpl"></ng-container>` without context won't pass data
2. **Styling ng-container:** Not in DOM, can't be styled
3. **Template timing:** Access templates in `ngAfterViewInit`, not constructor
4. **Confusing ng-template vs ng-content:** Template = reusable fragment, Content = projects parent content
