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
  • validation-errors custom attribute
  • validation-container custom element
  • ValidationResultPresenterService

Was this helpful?

Export as PDF
  1. Aurelia Packages
  2. Validation

Displaying Errors

How to display validation errors in your UI.

PreviousValidate Binding BehaviorNextI18n Internationalization

Last updated 1 year ago

Was this helpful?

The validation controller maintains the active list of validation results which can be iterated to display the errors in UI.

<ul>
  <li repeat.for="result of validationController.results">
    <template if.bind="!result.valid">${result}</template>
  </li>
</ul>

There are also some out-of-the-box components that can be used to display the errors. These are discussed in the following sections.

validation-errors custom attribute

This custom attribute can be used to bind the errors for children the target elements.

<div validation-errors.from-view="nameErrors"> <!--binds all errors for name to the "nameErrors" property-->
  <input value.bind="person.name & validate">
  <div>
    <span repeat.for="error of nameErrors">${error.result.message}</span>
  </div>
</div>
<div validation-errors.from-view="ageErrors"> <!--binds all errors for age to the "ageErrors" property-->
  <input value.bind="person.age & validate">
  <div>
    <span repeat.for="error of ageErrors">${error.result.message}</span>
  </div>
</div>

Note that this in itself does not show any error, unless errors are iterated to be bound with the view. An example can be seen below.

A point to note is that multiple validation targets can also be used for a single validation-errors custom attribute, and the errors for multiple targets will be captured the same way.

<div validation-errors.from-view="errors"> <!--binds all errors for name, and age to the "errors" property-->
  <input value.bind="person.name & validate">
  <input value.bind="person.age & validate">
  <div>
    <span repeat.for="error of errors">${error.result.message}</span>
  </div>
</div>

The usage of this custom element can be deactivated by using UseSubscriberCustomAttribute configuration option.

import { ValidationHtmlConfiguration } from '@aurelia/validation-html';
import Aurelia from 'aurelia';

Aurelia
  .register(ValidationHtmlConfiguration.customize((options) => {
    // customization callback
    options.UseSubscriberCustomAttribute = false;
  }))
  .app(component)
  .start();

This is useful if you have a custom attribute of the same name, and want to use that over this out-of-the-box custom attribute.

validation-container custom element

The validation-containercustom element also has similar goal of capturing the validation errors for the children target elements. Additionally, it provides a template to display the errors as well. This helps in reducing the boilerplate created by the validation-errors custom attribute. For example, using this custom element, displaying the errors reduces to the following.

<validation-container>
  <input value.bind="person.name & validate">
</validation-container>
<validation-container>
  <input value.bind="person.age & validate">
</validation-container>

There are couple of important points to note about the examples shown above. The first validation target shown in the example uses the default template of the custom element. This custom element template is based on two slots as shown below.

<slot>
  <!--meant for validation target-->
</slot>
<slot name='secondary'>
  <!--here goes error-->
</slot>

It is quite understandable that the CSS-containment of the Shadow DOM can come in the way of styling the custom element as per your need. It can be argued that this can be facilitated using CSS variables extensively. However, there is a far easy alternative to reach the same goal is offered by facilitating the customization of the whole template. To this end, use the SubscriberCustomElementTemplate configuration option.

There is another aspect of this configuration option. When a null, undefined, or '' (empty string) is used as the value for this configuration option, it deactivates the usage of this custom element. This is in sense similar to the UseSubscriberCustomAttribute configuration option.

ValidationResultPresenterService

Unlike the previous two approaches, this is a standalone service that manipulates the DOM directly. That it adds elements to DOM for every new errors and removes elements from DOM that are associated with old errors.

To use this, you need to instantiate it and register it with the validation controller.

import { IValidationController, IValidationResultPresenterService } from '@aurelia/validation';

export class MyApp {

  public constructor(
    private readonly validationController: IValidationController = resolve(newInstanceForScope(IValidationController)),
    private readonly presenter: IValidationResultPresenterService = resolve(IValidationResultPresenterService),
  ) {
      this.validationController.addSubscriber(this.presenter);
  }
}

The error rendering process can be completely overridden in the child classes. The use methods for overriding are described below.

  • add: this adds a new error to DOM. Override this if you want to completely change the process of adding new errors.

  • remove: this removes an old error from the DOM. Override this if you want to completely change the process of removing old errors.

  • getValidationMessageContainer: As the name suggests it provides container element with respect to current target. The default behavior is to look for an element with the attribute validation-result-container that is contained by the parent element of the current target element. If there is none found a div is created with the attribute and appended to the parent element.

  • showResults: This is the method that appends the errors to the container. By default a span with the error message is added for every errors whereas the valid results are skipped.

To avoid direct DOM manipulation, it is highly encouraged to use the previously mentioned custom attribute, and custom element.

The results of using the default template may not also suite your app or esthetics. However content can be injected into the slot from Light DOM (in case you are unfamiliar with the concepts, you are encouraged to give this a read) as shown in the example. Although traditionally the default slot is meant for the validation target(s), it can also be used to inject the error template, as shown in the example above.

One commonality across these components is that all these are different implementations of the .

excellent article
ValidationResultsSubscriber interface