LogoLogo
HomeDiscourseBlogDiscord
  • Introduction
  • Introduction
    • Quick start
    • Aurelia for new developers
    • Hello world
      • Creating your first app
      • Your first component - part 1: the view model
      • Your first component - part 2: the view
      • Running our app
      • Next steps
  • Templates
    • Template Syntax
      • Attribute binding
      • Event binding
      • Text interpolation
      • Template promises
      • Template references
      • Template variables
      • Globals
    • Custom attributes
    • Value converters (pipes)
    • Binding behaviors
    • Form Inputs
    • CSS classes and styling
    • Conditional Rendering
    • List Rendering
    • Lambda Expressions
    • Local templates (inline templates)
    • SVG
  • Components
    • Component basics
    • Component lifecycles
    • Bindable properties
    • Styling components
    • Slotted content
    • Scope and context
    • CustomElement API
    • Template compilation
      • processContent
      • Extending templating syntax
      • Modifying template parsing with AttributePattern
      • Extending binding language
      • Using the template compiler
      • Attribute mapping
  • Getting to know Aurelia
    • Routing
      • @aurelia/router
        • Getting Started
        • Creating Routes
        • Routing Lifecycle
        • Viewports
        • Navigating
        • Route hooks
        • Router animation
        • Route Events
        • Router Tutorial
        • Router Recipes
      • @aurelia/router-lite
        • Getting started
        • Router configuration
        • Configuring routes
        • Viewports
        • Navigating
        • Lifecycle hooks
        • Router hooks
        • Router events
        • Navigation model
        • Transition plan
    • App configuration and startup
    • Enhance
    • Template controllers
    • Understanding synchronous binding
    • Dynamic composition
    • Portalling elements
    • Observation
      • Observing property changes with @observable
      • Effect observation
      • HTML observation
      • Using observerLocator
    • Watching data
    • Dependency injection (DI)
    • App Tasks
    • Task Queue
    • Event Aggregator
  • Developer Guides
    • Animation
    • Testing
      • Overview
      • Testing attributes
      • Testing components
      • Testing value converters
      • Working with the fluent API
      • Stubs, mocks & spies
    • Logging
    • Building plugins
    • Web Components
    • UI virtualization
    • Errors
      • 0001 to 0023
      • 0088 to 0723
      • 0901 to 0908
    • Bundlers
    • Recipes
      • Apollo GraphQL integration
      • Auth0 integration
      • Containerizing Aurelia apps with Docker
      • Cordova/Phonegap integration
      • CSS-in-JS with Emotion
      • DOM style injection
      • Firebase integration
      • Markdown integration
      • Multi root
      • Progress Web Apps (PWA's)
      • Securing an app
      • SignalR integration
      • Strongly-typed templates
      • TailwindCSS integration
      • WebSockets Integration
      • Web Workers Integration
    • Playground
      • Binding & Templating
      • Custom Attributes
        • Binding to Element Size
      • Integration
        • Microsoft FAST
        • Ionic
    • Migrating to Aurelia 2
      • For plugin authors
      • Side-by-side comparison
    • Cheat Sheet
  • Aurelia Packages
    • Validation
      • Validation Tutorial
      • Plugin Configuration
      • Defining & Customizing Rules
      • Architecture
      • Tagging Rules
      • Model Based Validation
      • Validation Controller
      • Validate Binding Behavior
      • Displaying Errors
      • I18n Internationalization
      • Migration Guide & Breaking Changes
    • i18n Internationalization
    • Fetch Client
      • Overview
      • Setup and Configuration
      • Response types
      • Working with forms
      • Intercepting responses & requests
      • Advanced
    • Event Aggregator
    • State
    • Store
      • Configuration and Setup
      • Middleware
    • Dialog
  • Tutorials
    • Building a ChatGPT inspired app
    • Building a realtime cryptocurrency price tracker
    • Building a todo application
    • Building a weather application
    • Building a widget-based dashboard
    • React inside Aurelia
    • Svelte inside Aurelia
    • Synthetic view
    • Vue inside Aurelia
  • Community Contribution
    • Joining the community
    • Code of conduct
    • Contributor guide
    • Building and testing aurelia
    • Writing documentation
    • Translating documentation
Powered by GitBook
On this page
  • Injecting a controller instance
  • validate and reset
  • revalidateErrors
  • addObject and removeObject
  • addError and removeError
  • addSubscriber and removeSubscriber

Was this helpful?

Export as PDF
  1. Aurelia Packages
  2. Validation

Validation Controller

So far, the functionalities of the @aurelia/validation have been discussed. The part regarding the integration with a view has been kept out of the discussion so far. This section starts addressing that.

The validation controller is the implementation of IValidationController interface. It acts as a bridge between the validator and the other related components, such as view, binding, and subscribers. The capabilities of the validation controller are discussed below.

Injecting a controller instance

An instance of the validation controller can be injected using resolve(newInstanceForScope(IValidationController)), and resolve(IValidationController). The newInstanceForScope(IValidationController) resolver creates a new instance of the validation controller and registers the instance with the dependency injection container. This same instance can later be made available to the child components using resolve(IValidationController).

// parent-ce.ts
import { customElement } from '@aurelia/runtime';
import { newInstanceForScope, resolve } from '@aurelia/kernel';
import { IValidationController } from '@aurelia/validation-html';

@customElement({name:'parent-ce', template:`<child-ce></child-ce>`})
export class ParentCe {
  public constructor(
    // new instance of validation controller; let us name it c1
    private controller: IValidationController = resolve(newInstanceForScope(IValidationController))
  ) { }
}

// child-ce.ts
import { resolve } from '@aurelia/kernel';
import { IValidationController } from '@aurelia/validation';

export class Parent {
  public constructor(
    // the c1 instance is injected here
    private controller: IValidationController = resolve(IValidationController)
  ) { }
}

A new instance of validation controller can always be injected using the newInstanceOf(IValidationController) resolver. See this action in the demo below.

validate and reset

The validate method can be used to explicitly/manually perform the validation. The usage examples are as follows.

// validate all registered objects and bindings.
await validationController.validate();

// validate specific instruction
await validationController.validate(new ValidateInstruction(person));
await validationController.validate(new ValidateInstruction(person, 'name'));

The reset method on the other hand removes the errors from the validation controller. It also has an optional argument of type ValidateInstruction which when provided instructs the controller to remove errors for specific object, and/or properties. Note that other properties of the instruction object has no effect on resetting the errors.

revalidateErrors

With the revalidateErrors method, verifying whether the current errors are still there is possible. It does not validate all objects and bindings, as it is done in validate method. It is useful when you don't want to get a new set of errors and rather check on the current status of the existing set of errors.

await validationController.revalidateErrors();

addObject and removeObject

The method addObject registers an object explicitly to the validation controller. The validation controller automatically validates the object every time the validate method is called. This is useful when you can validate some object in your view model that does not have any direct reference to the view.

The object can be unregistered by calling the removeObject method. This also removes the associated errors of the object.

// add object
validationController.addObject(person);

// remove object
validationController.removeObject(person);

addError and removeError

Use the addError method to manually add an error to the controller. The signature of this method is as follows.

addError(message: string, object: any, propertyName?: string): ValidationResult;

Note that this method returns an instance of ValidationResult which later can be used with removeError to clear the error.

// add error
const result= validationController.addError("Some critical error", person);

// remove error
validationController.removeError(result);

Note that the errors added by the addError method, never gets revalidated when revalidateErrors is called. If the error needs to be removed, it must be done using removeError method.

addSubscriber and removeSubscriber

The subscribers can be added or removed using addSubscriber and removeSubscriber methods respectively. Whenever the validation controller performs validation or resets errors, the registered subscribers are notified of the change in validation results. To unsubscribe from the validation results notification, the subscriber needs to be removed.

The subscriber interface is rather simple, consisting of only one method.

interface ValidationResultsSubscriber {
  handleValidationEvent(event: ValidationEvent): void;
}

The notification event data looks loosely like the following.

class ValidationEvent {
  public kind: 'validate' | 'reset';
  public addedResults: ValidationResultTarget[];
  public removedResults: ValidationResultTarget[];
}

class ValidationResultTarget {
  public result: ValidationResult;
  public targets: Element[];
}

class ValidationResult<TRule extends BaseValidationRule = BaseValidationRule> {
    public valid: boolean;
    public message: string | undefined;
    public propertyName: string | undefined;
    public object: any;
    public rule: TRule | undefined;
    public propertyRule: PropertyRule | undefined;
    // `true` if the validation result is added manually.
    public isManual: boolean = false;
}

What the subscribers do with the event data depends on the subscribers. An obvious use case is to present the errors to the end users. In fact, the out-of-the-box subscribers are used for that purpose only. Below is one example of how you can create a custom subscriber.

PreviousModel Based ValidationNextValidate Binding Behavior

Last updated 1 year ago

Was this helpful?

The design decision is made keeping the following frequent use case in mind. The manual/final validation happens in the "root"/"parent" component/custom element. The child components, such as other custom elements, define the necessary validation rules at the custom element level, as well as uses the validate binding behavior to mark the validation targets in the view/markup. This helps show the validation messages near the validation targets. Creating a new instance of the validation controller and registering the instance with the dependency injection container makes the same instance available to the child components level. The instance can then be used for registering the validation targets (see ), which makes it possible to execute all the validation rules defined in the children with a single instance of the controller.

This method is in essence similar to the validate method in validator. However, there are some differences. If the method is called with an instruction, the instruction is executed. Otherwise all the , as well as the are validated. After the validation, all the are notified of the change. Refer the to understand it better. To know more about ValidateInstruction refer .

validate binding behavior
registered bindings
registered subscribers
visual representation of the workflow
this
registered objects