Template Syntax Examples

Practical examples of AngularDart template syntax.

Example 1: User Profile Card

@Component(
  selector: 'user-card',
  template: '<div class="card" [class.admin]="user.isAdmin">'
      '<img [src]="user.avatarUrl" [alt]="user.name">'
      '<h2>{{ user.name }}</h2>'
      '<p>{{ user.bio }}</p>'
      '<span *ngIf="user.isAdmin" class="badge">Admin</span>'
      '<button (click)="onContact()">Contact</button>'
      '</div>',
  styles: ['.card { padding: 16px; border: 1px solid #ddd; border-radius: 8px; }'
      '.card.admin { border-color: gold; }'
      '.badge { background: gold; padding: 2px 8px; border-radius: 4px; }'],
)
class UserCardComponent {
  @Input()
  User? user;

  @Output()
  final contact = StreamController<User>.broadcast();

  void onContact() {
    if (user != null) contact.add(user!);
  }
}

Example 2: Shopping Cart with ngFor

@Component(
  selector: 'shopping-cart',
  template: '<h2>Shopping Cart ({{ items.length }} items)</h2>'
      '<ul class="cart-items">'
      '<li *ngFor="let item of items; let i = index; trackBy: trackByItemId">'
      '<span class="item-name">{{ item.name }}</span>'
      '<span class="item-qty">'
      '<button (click)="decrement(i)">-</button>'
      '{{ item.quantity }}'
      '<button (click)="increment(i)">+</button>'
      '</span>'
      '<span class="item-price">{{ item.price | currency:\'EUR\' }}</span>'
      '<button (click)="remove(i)" class="remove-btn">Remove</button>'
      '</li>'
      '</ul>'
      '<div class="total">'
      '<strong>Total: {{ total | currency:\'EUR\' }}</strong>'
      '</div>'
      '<button (click)="checkout()" [disabled]="items.isEmpty">Checkout</button>',
)
class ShoppingCartComponent {
  List<CartItem> items = [];

  String trackByItemId(int index, CartItem item) => item.id;

  double get total => items.fold(0, (sum, item) => sum + item.price * item.quantity);

  void increment(int index) => items[index].quantity++;
  void decrement(int index) {
    if (items[index].quantity > 1) items[index].quantity--;
  }
  void remove(int index) => items.removeAt(index);
  void checkout() { /* ... */ }
}

Example 3: Form with Validation Feedback

@Component(
  selector: 'registration-form',
  template: '<form #form="ngForm" (ngSubmit)="onSubmit(form)">'
      '<div class="form-group">'
      '<label for="name">Name</label>'
      '<input id="name" ngModel name="name" #nameField="ngModel" required minlength="2" maxlength="50">'
      '<div class="errors" *ngIf="nameField.invalid && nameField.touched">'
      '<span *ngIf="nameField.errors?[\'required\']">Name is required</span>'
      '<span *ngIf="nameField.errors?[\'minlength\']">Name must be at least 2 characters</span>'
      '</div>'
      '</div>'
      '<div class="form-group">'
      '<label for="email">Email</label>'
      '<input id="email" ngModel name="email" #emailField="ngModel" required type="email">'
      '<div class="errors" *ngIf="emailField.invalid && emailField.touched">'
      '<span *ngIf="emailField.errors?[\'required\']">Email is required</span>'
      '<span *ngIf="emailField.errors?[\'email\']">Please enter a valid email</span>'
      '</div>'
      '</div>'
      '<button type="submit" [disabled]="form.invalid">Register</button>'
      '</form>',
  directives: [formDirectives],
)
class RegistrationFormComponent {
  void onSubmit(NgForm form) {
    print('Form submitted: ${form.value}');
  }
}

Example 4: Dynamic Styling with ngClass and ngStyle

@Component(
  selector: 'theme-demo',
  template: '<div [ngClass]="themeClasses" [ngStyle]="themeStyles">'
      '<h1>{{ title }}</h1>'
      '<p>{{ content }}</p>'
      '</div>'
      '<button (click)="toggleTheme()">Toggle Theme</button>',
)
class ThemeDemoComponent {
  String title = 'Themed Content';
  String content = 'This content changes appearance based on the theme.';
  bool isDark = false;

  Map<String, bool> get themeClasses => {
    'dark-theme': isDark,
    'light-theme': !isDark,
    'large-text': true,
  };

  Map<String, String> get themeStyles => {
    'background-color': isDark ? '#1a1a2e' : '#ffffff',
    'color': isDark ? '#ffffff' : '#333333',
    'padding': '20px',
    'border-radius': '8px',
  };

  void toggleTheme() {
    isDark = !isDark;
  }
}

Example 5: ngSwitch for Status Display

@Component(
  selector: 'order-status',
  template: '<div class="status-badge" [ngSwitch]="order.status">'
      '<span *ngSwitchCase="\'pending\'" class="pending">Pending</span>'
      '<span *ngSwitchCase="\'processing\'" class="processing">Processing</span>'
      '<span *ngSwitchCase="\'shipped\'" class="shipped">Shipped ({{ order.trackingNumber }})</span>'
      '<span *ngSwitchCase="\'delivered\'" class="delivered">Delivered</span>'
      '<span *ngSwitchCase="\'cancelled\'" class="cancelled">Cancelled</span>'
      '<span *ngSwitchDefault class="unknown">Unknown Status</span>'
      '</div>',
)
class OrderStatusComponent {
  @Input()
  Order? order;
}

Example 6: Template Reference Variables

@Component(
  selector: 'search-box',
  template: '<input #searchInput (input)="onSearch(searchInput.value)" '
      '(keyup.enter)="onSubmit(searchInput.value)" placeholder="Search...">'
      '<button (click)="onSubmit(searchInput.value)">Search</button>'
      '<button (click)="clear(searchInput)">Clear</button>'
      '<div *ngIf="results.isNotEmpty">'
      '<h3>Results for "{{ lastQuery }}":</h3>'
      '<ul>'
      '<li *ngFor="let result of results">{{ result }}</li>'
      '</ul>'
      '</div>',
)
class SearchBoxComponent {
  List<String> results = [];
  String lastQuery = '';

  void onSearch(String query) {
    lastQuery = query;
    if (query.length >= 3) {
      results = ['Result 1 for $query', 'Result 2 for $query'];
    } else {
      results = [];
    }
  }

  void onSubmit(String query) {
    print('Searching for: $query');
  }

  void clear(HtmlInputElement input) {
    input.value = '';
    results = [];
    lastQuery = '';
    input.focus();
  }
}

Example 7: Two-Way Binding with ngModel

@Component(
  selector: 'profile-editor',
  template: '<h2>Edit Profile</h2>'
      '<div class="form-group">'
      '<label>Name:</label>'
      '<input [(ngModel)]="user.name">'
      '<p>Preview: {{ user.name }}</p>'
      '</div>'
      '<div class="form-group">'
      '<label>Email:</label>'
      '<input [(ngModel)]="user.email" type="email">'
      '<p>Preview: {{ user.email }}</p>'
      '</div>'
      '<button (click)="save()">Save</button>'
      '<button (click)="reset()">Reset</button>'
      '<pre>{{ user | json }}</pre>',
  directives: [formDirectives],
)
class ProfileEditorComponent {
  User user = User(
    name: 'John Doe',
    email: 'john@example.com',
    newsletter: true,
    role: 'user',
  );

  late User _originalUser;

  ProfileEditorComponent() {
    _originalUser = user.clone();
  }

  void save() {
    _originalUser = user.clone();
    print('Saved: ${user.toJson()}');
  }

  void reset() {
    user = _originalUser.clone();
  }
}