Cheatsheet

A quick reference for AngularDart syntax and common patterns.

Component

@Component(
  selector: 'my-component',
  templateUrl: 'my_component.html',
  // or template: '<p>Hello</p>',
  styleUrls: ['my_component.css'],
  // or styles: ['p { color: red; }'],
  directives: [NgIf, NgFor, OtherComponent],
  providers: [ClassProvider(MyService)],
  changeDetection: ChangeDetectionStrategy.OnPush,
)
class MyComponent implements OnInit, OnDestroy {
  // ...
}

Input / Output

@Input()
String? name;

@Input('alias')
String? internalName;

@Output()
final clickStream = StreamController<String>.broadcast();

void onClick() => clickStream.add('clicked');

Template Syntax

Syntax Description
{{ expr }} Interpolation
[prop]="expr" Property binding
(event)="handler()" Event binding
[(ngModel)]="prop" Two-way binding
#ref Template reference variable
*ngIf="cond" Conditional rendering
*ngFor="let x of list" Loop rendering
[ngClass]="{}" CSS class binding
[ngStyle]="{}" Style binding
[ngSwitch]="val" Switch rendering

Built-in Directives

<!-- Conditional -->
<div *ngIf="condition">Shown</div>
<div *ngIf="condition; else other">Shown</div>
<ng-template #other>Other</ng-template>

<!-- Loop -->
<li *ngFor="let item of items; let i = index">{{ i }}: {{ item }}</li>

<!-- Switch -->
<div [ngSwitch]="value">
  <span *ngSwitchCase="'a'">A</span>
  <span *ngSwitchCase="'b'">B</span>
  <span *ngSwitchDefault>Other</span>
</div>

<!-- Class/Style -->
<div [ngClass]="{'active': isActive, 'disabled': isDisabled}">
<div [ngStyle]="{'color': color, 'font-size.px': size}">

<!-- Reference -->
<input #myInput>
<button (click)="myInput.focus()">Focus</button>

Lifecycle Hooks

Hook When
Constructor Always first
ngOnChanges Input changes
ngOnInit After first ngOnChanges
ngDoCheck Every change detection
ngAfterContentInit Content projected
ngAfterContentChecked Content checked
ngAfterViewInit View initialized
ngAfterViewChecked View checked
ngOnDestroy Before destruction

Dependency Injection

@Injectable()
class MyService {
  // ...
}

@Component(
  selector: 'my-component',
  providers: [ClassProvider(MyService)],
  template: '...',
)
class MyComponent {
  final MyService _service;
  MyComponent(this._service);
}

Provider Types

providers: [
  ClassProvider(MyService),
  ClassProvider(BaseService, useClass: RealService),
  ValueProvider(API_URL, 'https://api.example.com'),
  FactoryProvider(CONFIG, (i) => Config.fromEnv()),
  ExistingProvider(Alias, MyService),
]

Routing

import 'package:angulardart/angular.dart';
import 'package:angulardart_router/angulardart_router.dart';

@Component(
  selector: 'my-app',
  template: '<a [routerLink]="[\'/\']">Home</a>'
      '<a [routerLink]="[\'/about\']">About</a>'
      '<router-outlet [routes]="routes"></router-outlet>',
  directives: [routerDirectives],
)
class AppComponent implements OnInit {
  final Router _router;
  List<RouteDefinition> routes = [];

  AppComponent(this._router);

  @override
  void ngOnInit() {
    routes = [
      RouteDefinition(path: '/', component: HomeComponentFactory, useAsDefault: true),
      RouteDefinition(path: '/about', component: AboutComponentFactory),
      RouteDefinition(path: '/users/:id', component: UserComponentFactory),
    ];
  }
}

Route Parameters

class UserComponent implements OnInit {
  String? userId;
  final Router _router;

  UserComponent(this._router);

  @override
  void ngOnInit() {
    userId = _router.current?.queryParameters['id'] ?? 
             _router.current?.path.split('/').last;
  }
}
final Router _router;

void navigateToUser(String userId) {
  _router.navigate('/users/$userId');
}

void navigateWithQuery() {
  _router.navigate('/search', NavigationParams(
    queryParameters: {'q': 'dart'},
  ));
}

Forms

Template-Driven

@Component(
  template: "
    <form #f="ngForm" (ngSubmit)="onSubmit(f)">
      <input ngModel name="name" required>
      <button [disabled]="f.invalid">Submit</button>
    </form>
  ",
  directives: [formDirectives],
)

Reactive Forms

late final FormGroup form;

MyComponent() {
  form = FormGroup({
    'name': FormControl<String>('', Validators.required),
    'email': FormControl<String>('', Validators.email),
  });
}

Pipes

{{ value | date }}
{{ value | date:'fullDate' }}
{{ value | uppercase }}
{{ value | lowercase }}
{{ value | number }}
{{ value | number:'1.2-2' }}
{{ value | percent }}
{{ value | currency:'EUR' }}
{{ value | json }}
{{ value | slice:1:5 }}
{{ value | async }}

Host Bindings

@Directive(selector: '[highlight]')
class HighlightDirective {
  @HostBinding('class.highlighted')
  bool isHighlighted = false;

  @HostBinding('style.backgroundColor')
  String bgColor = 'yellow';

  @HostListener('mouseenter')
  void onEnter() => isHighlighted = true;

  @HostListener('mouseleave')
  void onLeave() => isHighlighted = false;
}

Queries

// Single child element
@ViewChild('myInput')
HtmlInputElement? inputRef;

// Multiple child elements
@ViewChildren(ChildComponent)
List<ChildComponent>? children;

// Projected content
@ContentChild(HeaderComponent)
HeaderComponent? header;

@ContentChildren(ItemDirective)
List<ItemDirective>? items;

Common Patterns

Async Data

<div *ngIf="data$ | async as data">
  {{ data.name }}
</div>

Safe Navigation

{{ user?.name }}
{{ user?.address?.city }}

Non-null Assertion

{{ user!.name }}