Token导航 LogoToken导航TokenDH.com
研究检索操作浏览器github未标认证来源可访问clear审计未展示

angular-20-control-flowAngular 20 control flow 搜索

Agent Skill

angular-20-control-flow 用于查找、检索和筛选相关信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要根据关键词、任务场景或来源线索快速定位候选结果时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

总安装

643

周安装

26

GitHub Stars

公开资料未说明

下载量

202
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

2

许可证

MIT

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:angular-20-control-flow(Angular 20 control flow 搜索)
来源仓库:https://github.com/7spade/black-tortoise
仓库路径:skills/angular-20-control-flow
安装命令:
npx skills add 7spade/black-tortoise --skill "angular-20-control-flow"
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

AgentSkills.tonpx skills
npx skills add 7spade/black-tortoise --skill "angular-20-control-flow"

简介

angular-20-control-flow 用于查找、检索和筛选相关信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要根据关键词快速定位候选结果时使用。

  • 它支持基于任务场景或来源线索进行信息聚合与筛选,适用于研究类工作流。
  • 通过 npx skills add 7spade/black-tortoise --skill "angular-20-control-flow" 命令安装。
  • 安装前建议确认权限范围、维护状态,以及是否会触发联网或文件读写操作。
  • 适用宿主包括 Codex、Claude、Cursor、Gemini CLI,接入前应确认版本、权限和运行环境要求。

SKILL.md

name
angular-20-control-flow
description
Angular 20 built-in control flow syntax (@if, @for, @switch, @defer) for modern template programming. Use when writing templates with conditional rendering, loops, switch statements, or lazy loading components. Replaces *ngIf, *ngFor, *ngSwitch with new block syntax for better performance and type safety.
license
MIT

Angular 20 Control Flow Skill

Rules

Control Flow Syntax

  • Use @if / @else / @else if for conditional rendering
  • Use @for with mandatory track expression for list iteration
  • Use @switch / @case / @default for multi-branch conditionals
  • Use @defer for lazy loading and code splitting
  • MUST NOT use structural directives: *ngIf, *ngFor, *ngSwitch

@for Track Expression

  • Every @for loop MUST include a track expression
  • Track by unique ID: track item.id
  • Track by index for static lists: track $index
  • MUST NOT track by object reference

@defer Loading States

  • Use appropriate trigger: on viewport, on interaction, on idle, on immediate, on timer(Xs), on hover
  • Use @loading (minimum Xms) to prevent UI flashing
  • Use @placeholder (minimum Xms) for minimum display time

Signal Integration

  • Control flow conditions MUST use signal invocation: @if (signal())
  • MUST NOT use plain properties without signal invocation

Context Variables

  • Available in @for: $index, $first, $last, $even, $odd, $count

Context

Purpose

This skill provides comprehensive guidance on Angular 20's built-in control flow syntax, which introduces new template syntax (@if, @for, @switch, @defer) that replaces structural directives with better performance, type safety, and developer experience.

What is Angular Control Flow?

Angular 20 introduces new built-in control flow syntax:

  • @if / @else: Conditional rendering (replaces *ngIf)
  • @for: List iteration with tracking (replaces *ngFor)
  • @switch / @case: Multi-branch conditionals (replaces *ngSwitch)
  • @defer: Lazy loading and code splitting (new feature)
  • @empty: Fallback for empty collections
  • @placeholder / @loading / @error: Defer states

When to Use This Skill

Use Angular 20 Control Flow when:

  • Writing templates with conditional rendering
  • Iterating over lists or arrays
  • Implementing switch/case logic in templates
  • Lazy loading components or content blocks
  • Handling loading states and error boundaries
  • Optimizing bundle size with deferred loading
  • Migrating from *ngIf, *ngFor, *ngSwitch to modern syntax

Core Control Flow Blocks

1. @if - Conditional Rendering

Basic Usage:

@Component({
  template: `
    @if (isLoggedIn()) {
      <div>Welcome back, {{ username() }}!</div>
    }
  `
})
export class WelcomeComponent {
  isLoggedIn = signal(false);
  username = signal('User');
}

@if with @else:

@Component({
  template: `
    @if (user()) {
      <app-dashboard [user]="user()" />
    } @else {
      <app-login />
    }
  `
})
export class AppComponent {
  user = signal<User | null>(null);
}

@if with @else if:

@Component({
  template: `
    @if (status() === 'loading') {
      <app-spinner />
    } @else if (status() === 'error') {
      <app-error [message]="errorMessage()" />
    } @else if (status() === 'success') {
      <app-content [data]="data()" />
    } @else {
      <app-empty-state />
    }
  `
})
export class DataComponent {
  status = signal<'loading' | 'error' | 'success' | 'idle'>('idle');
  errorMessage = signal('');
  data = signal<any[]>([]);
}

Type Narrowing:

@Component({
  template: `
    @if (item(); as currentItem) {
      <!-- currentItem is type-narrowed here -->
      <div>{{ currentItem.name }}</div>
      <div>{{ currentItem.description }}</div>
    }
  `
})
export class ItemComponent {
  item = signal<Item | null>(null);
}

2. @for - List Iteration

Basic @for Loop:

@Component({
  template: `
    <ul>
      @for (item of items(); track item.id) {
        <li>{{ item.name }}</li>
      }
    </ul>
  `
})
export class ListComponent {
  items = signal([
    { id: 1, name: 'Item 1' },
    { id: 2, name: 'Item 2' },
    { id: 3, name: 'Item 3' }
  ]);
}

@for with Index and Context:

@Component({
  template: `
    <div class="items">
      @for (item of items(); track item.id; let idx = $index, first = $first, last = $last) {
        <div class="item" [class.first]="first" [class.last]="last">
          <span class="index">{{ idx + 1 }}.</span>
          <span class="name">{{ item.name }}</span>
        </div>
      }
    </div>
  `
})
export class IndexedListComponent {
  items = signal<Item[]>([]);
}

Available Context Variables:

  • $index - Current index (0-based)
  • $first - True if first item
  • $last - True if last item
  • $even - True if even index
  • $odd - True if odd index
  • $count - Total number of items

@for with @empty:

@Component({
  template: `
    <div class="product-list">
      @for (product of products(); track product.id) {
        <app-product-card [product]="product" />
      } @empty {
        <div class="empty-state">
          <p>No products available</p>
          <button (click)="loadProducts()">Refresh</button>
        </div>
      }
    </div>
  `
})
export class ProductListComponent {
  products = signal<Product[]>([]);
}

Track By Best Practices:

// ✅ Good - Track by unique ID
@for (user of users(); track user.id) {
  <app-user-card [user]="user" />
}

// ✅ Good - Track by index for static lists
@for (tab of tabs; track $index) {
  <button>{{ tab }}</button>
}

// ❌ Bad - Track by object reference (will cause unnecessary re-renders)
@for (item of items(); track item) {
  <div>{{ item.name }}</div>
}

3. @switch - Multi-branch Conditionals

Basic @switch:

@Component({
  template: `
    @switch (userRole()) {
      @case ('admin') {
        <app-admin-panel />
      }
      @case ('moderator') {
        <app-moderator-panel />
      }
      @case ('user') {
        <app-user-panel />
      }
      @default {
        <app-guest-panel />
      }
    }
  `
})
export class RoleBasedComponent {
  userRole = signal<'admin' | 'moderator' | 'user' | 'guest'>('guest');
}

@switch with Complex Conditions:

@Component({
  template: `
    @switch (connectionStatus()) {
      @case ('connected') {
        <div class="status online">
          <mat-icon>check_circle</mat-icon>
          Connected
        </div>
      }
      @case ('connecting') {
        <div class="status pending">
          <mat-spinner diameter="20"></mat-spinner>
          Connecting...
        </div>
      }
      @case ('disconnected') {
        <div class="status offline">
          <mat-icon>error</mat-icon>
          Disconnected
        </div>
      }
      @case ('error') {
        <div class="status error">
          <mat-icon>warning</mat-icon>
          Connection Error
        </div>
      }
      @default {
        <div class="status unknown">Unknown Status</div>
      }
    }
  `
})
export class ConnectionStatusComponent {
  connectionStatus = signal<'connected' | 'connecting' | 'disconnected' | 'error'>('disconnected');
}

4. @defer - Lazy Loading and Code Splitting

Basic Deferred Loading:

@Component({
  template: `
    @defer {
      <app-heavy-component />
    } @placeholder {
      <div class="skeleton">Loading...</div>
    }
  `
})
export class DeferredComponent {}

Defer with Loading State:

@Component({
  template: `
    @defer {
      <app-video-player [src]="videoUrl" />
    } @loading (minimum 500ms) {
      <div class="loading-spinner">
        <mat-spinner></mat-spinner>
        <p>Loading video player...</p>
      </div>
    } @placeholder {
      <div class="video-placeholder">
        <mat-icon>play_circle</mat-icon>
      </div>
    } @error {
      <div class="error-state">
        <p>Failed to load video player</p>
        <button (click)="retry()">Retry</button>
      </div>
    }
  `
})
export class VideoComponent {
  videoUrl = signal('https://example.com/video.mp4');
}

Defer Triggers:

// Viewport trigger - Load when visible
@defer (on viewport) {
  <app-below-fold-content />
}

// Interaction trigger - Load on click
@defer (on interaction) {
  <app-modal-content />
}

// Idle trigger - Load when browser is idle
@defer (on idle) {
  <app-analytics-widget />
}

// Immediate trigger - Load immediately
@defer (on immediate) {
  <app-critical-content />
}

// Timer trigger - Load after delay
@defer (on timer(5s)) {
  <app-delayed-content />
}

// Hover trigger - Load on hover
@defer (on hover) {
  <app-tooltip-content />
}

// Combined triggers
@defer (on viewport; on idle) {
  <app-content />
}

Prefetching:

// Prefetch when idle
@defer (on viewport; prefetch on idle) {
  <app-article-content />
}

// Prefetch on hover
@defer (on interaction; prefetch on hover) {
  <app-modal />
}

Defer with Minimum Loading Time:

@Component({
  template: `
    @defer (on viewport) {
      <app-chart [data]="chartData()" />
    } @loading (minimum 1s) {
      <!-- Show loading for at least 1 second to avoid flashing -->
      <div class="chart-skeleton"></div>
    } @placeholder (minimum 500ms) {
      <!-- Show placeholder for at least 500ms -->
      <div class="chart-placeholder"></div>
    }
  `
})
export class ChartComponent {
  chartData = signal<ChartData[]>([]);
}

Migration from Old Syntax

ngIf → @if

// Before (Angular 19 and earlier)
<div *ngIf="isVisible">Content</div>
<div *ngIf="user; else loading">{{ user.name }}</div>

// After (Angular 20+)
@if (isVisible()) {
  <div>Content</div>
}

@if (user(); as currentUser) {
  <div>{{ currentUser.name }}</div>
} @else {
  <ng-container [ngTemplateOutlet]="loading" />
}

ngFor → @for

// Before
<li *ngFor="let item of items; trackBy: trackById">{{ item.name }}</li>

// After
@for (item of items(); track item.id) {
  <li>{{ item.name }}</li>
}

ngSwitch → @switch

// Before
<div [ngSwitch]="status">
  <div *ngSwitchCase="'success'">Success!</div>
  <div *ngSwitchCase="'error'">Error!</div>
  <div *ngSwitchDefault>Loading...</div>
</div>

// After
@switch (status()) {
  @case ('success') {
    <div>Success!</div>
  }
  @case ('error') {
    <div>Error!</div>
  }
  @default {
    <div>Loading...</div>
  }
}

Best Practices

1. Use Signals with Control Flow

// ✅ Good - Reactive with signals
export class Component {
  items = signal<Item[]>([]);
  isLoading = signal(false);
}

@Component({
  template: `
    @if (isLoading()) {
      <spinner />
    } @else {
      @for (item of items(); track item.id) {
        <item-card [item]="item" />
      }
    }
  `
})

2. Always Use track in @for

// ✅ Good - Proper tracking
@for (user of users(); track user.id) {
  <user-card [user]="user" />
}

// ❌ Bad - Missing track (will cause error)
@for (user of users()) {
  <user-card [user]="user" />
}

3. Leverage @defer for Performance

// ✅ Good - Defer heavy components
@defer (on viewport) {
  <app-complex-chart />
} @placeholder {
  <div class="chart-skeleton"></div>
}

// ✅ Good - Defer analytics
@defer (on idle) {
  <app-analytics-tracker />
}

4. Use @empty for Better UX

// ✅ Good - Handle empty state
@for (item of items(); track item.id) {
  <item-card [item]="item" />
} @empty {
  <empty-state message="No items found" />
}

5. Type Narrowing with @if

// ✅ Good - Type narrowing
@if (user(); as currentUser) {
  <!-- currentUser is guaranteed non-null here -->
  <div>{{ currentUser.email }}</div>
}

🔧 Advanced Patterns

Nested Control Flow

@Component({
  template: `
    @if (data(); as currentData) {
      @for (category of currentData.categories; track category.id) {
        <div class="category">
          <h3>{{ category.name }}</h3>
          @for (item of category.items; track item.id) {
            <div class="item">{{ item.title }}</div>
          } @empty {
            <p>No items in this category</p>
          }
        </div>
      }
    } @else {
      <app-loading />
    }
  `
})

Conditional Deferred Loading

@Component({
  template: `
    @if (shouldLoadHeavyComponent()) {
      @defer (on viewport) {
        <app-heavy-component [config]="config()" />
      } @loading {
        <skeleton-loader />
      }
    }
  `
})

🐛 Troubleshooting

IssueSolution
Syntax error with @ blocksEnsure Angular 20+ and update compiler
@for without track errorAlways add track expression to @for
@defer not lazy loadingCheck bundle config and verify component is in separate chunk
Type errors with @ifUse as alias for type narrowing
@empty not showingEnsure collection signal returns empty array, not undefined

📖 References


📂 Recommended Placement

Project-level skill:

/.github/skills/angular-20-control-flow/SKILL.md

Copilot will load this when working with Angular 20 control flow syntax.

适合场景

01

用户想查找某类 Agent Skill 时

02

需要根据任务场景推荐可安装能力包时

03

需要对比不同来源的安装命令和来源信息时

04

需要参考平台分布和安装热度时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

能力 4

补充不同宿主或平台的使用分布数据

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

Antigravity

32.13%
按下载量换算65

OpenCode

25.6%
按下载量换算52

Claude Code

16.77%
按下载量换算34

Codex

11.88%
按下载量换算24

Gemini CLI

8.16%
按下载量换算16

windsurf

3.4%
按下载量换算7

安全审计

暂无安全审计结果可展示。

权限和风险

操作浏览器

该 Skill 可能涉及浏览器控制能力,使用时可能读取或操作网页内容,需要在受控环境中确认权限边界。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。当前只有一个来源,正式发布前建议补源仓库或其他目录站核验。

来源信息

继续浏览同类 Skills