Advanced custom attributes

Advanced patterns for building custom attributes in Aurelia 2, including template controllers, complex bindings, and performance optimization.

This guide covers advanced patterns for building custom attributes in Aurelia 2, focusing on template controllers, complex binding scenarios, and performance optimization techniques.

Template Controllers

Template controllers are custom attributes that control the rendering of their associated template. They're the mechanism behind built-in attributes like if, repeat, with, and switch.

Basic Template Controller Structure

All template controllers follow this pattern:

import { customAttribute, ICustomAttributeController, IViewFactory, IRenderLocation, ISyntheticView } from '@aurelia/runtime-html';
import { resolve } from '@aurelia/kernel';

@customAttribute({
  name: 'my-controller',
  isTemplateController: true,
  bindables: ['value']
})
export class MyController {
  public readonly $controller!: ICustomAttributeController<this>;
  private readonly factory = resolve(IViewFactory);
  private readonly location = resolve(IRenderLocation);
  private view?: ISyntheticView;

  public value: unknown;

  public valueChanged(newValue: unknown): void {
    this.updateView(newValue);
  }

  private updateView(show: boolean): void {
    if (show && !this.view) {
      this.view = this.factory.create().setLocation(this.location);
      this.view.activate(this.view, this.$controller, this.$controller.scope);
    } else if (!show && this.view) {
      this.view.deactivate(this.view, this.$controller);
      this.view = undefined;
    }
  }

  public attaching(): void {
    if (this.value) {
      this.updateView(true);
    }
  }

  public detaching(): void {
    if (this.view) {
      this.view.deactivate(this.view, this.$controller);
      this.view = undefined;
    }
  }
}

Usage:

Real-World Example: Visibility Controller

A practical template controller that shows/hides content based on user permissions:

Usage:

Advanced Template Controller: Loading States

A template controller that manages loading states with caching:

Usage:

Complex Two-Way Binding Attributes

Bi-directional Data Synchronization

Create attributes that can both read and write data:

Usage:

Multi-Value Binding

Handle multiple bindable properties with complex interactions:

Usage:

Performance Optimization Patterns

Lazy Initialization

Defer expensive operations until needed:

Batch Updates

Minimize DOM operations by batching updates:

Error Handling in Custom Attributes

Graceful Degradation

Handle errors gracefully without breaking the application:

Validation and Sanitization

Validate inputs before applying them:

Testing Custom Attributes

Unit Testing Template Controllers

Best Practices

1. Resource Management

Always clean up resources in detached():

2. Performance Considerations

  • Use requestAnimationFrame for DOM updates

  • Batch operations when possible

  • Avoid frequent DOM queries

3. Error Handling

  • Validate inputs before applying changes

  • Provide fallback behaviors

  • Log errors for debugging

4. Type Safety

  • Use TypeScript interfaces for bindable properties

  • Implement proper type guards for runtime validation

These patterns provide a solid foundation for building robust, performant custom attributes that integrate well with Aurelia's architecture while handling edge cases gracefully.

Last updated

Was this helpful?