diff --git a/src/aurelia-validation.ts b/src/aurelia-validation.ts index 24ac3568..ec205115 100644 --- a/src/aurelia-validation.ts +++ b/src/aurelia-validation.ts @@ -1,5 +1,6 @@ // Exports +export * from './config'; export * from './controller-validate-result'; export * from './get-target-dom-element'; export * from './property-info'; @@ -26,8 +27,7 @@ export * from './implementation/validation-rules'; // Configuration import { Container } from 'aurelia-dependency-injection'; -import { Validator } from './validator'; -import { StandardValidator } from './implementation/standard-validator'; +import { GlobalValidationConfiguration } from './config'; import { ValidationMessageParser } from './implementation/validation-message-parser'; import { PropertyAccessorParser } from './property-accessor-parser'; import { ValidationRules } from './implementation/validation-rules'; @@ -41,35 +41,13 @@ import { import { ValidationErrorsCustomAttribute } from './validation-errors-custom-attribute'; import { ValidationRendererCustomAttribute } from './validation-renderer-custom-attribute'; -/** - * Aurelia Validation Configuration API - */ -export class AureliaValidationConfiguration { - private validatorType: { new (...args: any[]): Validator } = StandardValidator; - - /** - * Use a custom Validator implementation. - */ - public customValidator(type: { new (...args: any[]): Validator }) { - this.validatorType = type; - } - - /** - * Applies the configuration. - */ - public apply(container: Container) { - const validator = container.get(this.validatorType); - container.registerInstance(Validator, validator); - } -} - /** * Configures the plugin. */ export function configure( // tslint:disable-next-line:ban-types frameworkConfig: { container: Container, globalResources?: (...resources: any[]) => any }, - callback?: (config: AureliaValidationConfiguration) => void + callback?: (config: GlobalValidationConfiguration) => void ) { // the fluent rule definition API needs the parser to translate messages // to interpolation expressions. @@ -78,7 +56,7 @@ export function configure( ValidationRules.initialize(messageParser, propertyParser); // configure... - const config = new AureliaValidationConfiguration(); + const config = new GlobalValidationConfiguration(); if (callback instanceof Function) { callback(config); } diff --git a/src/config.ts b/src/config.ts new file mode 100644 index 00000000..934d4377 --- /dev/null +++ b/src/config.ts @@ -0,0 +1,40 @@ +import { Container } from 'aurelia-dependency-injection'; +import { Validator } from './validator'; +import { StandardValidator } from './implementation/standard-validator'; +import { validateTrigger } from './validate-trigger'; + +/** + * Aurelia Validation Configuration API + */ +export class GlobalValidationConfiguration { + public static DEFAULT_VALIDATION_TRIGGER = validateTrigger.blur; + + private validatorType: { new (...args: any[]): Validator } = StandardValidator; + private validationTrigger = GlobalValidationConfiguration.DEFAULT_VALIDATION_TRIGGER; + + /** + * Use a custom Validator implementation. + */ + public customValidator(type: { new (...args: any[]): Validator }) { + this.validatorType = type; + return this; + } + + public defaultValidationTrigger(trigger: validateTrigger) { + this.validationTrigger = trigger; + return this; + } + + public getDefaultValidationTrigger() { + return this.validationTrigger; + } + + /** + * Applies the configuration. + */ + public apply(container: Container) { + const validator = container.get(this.validatorType); + container.registerInstance(Validator, validator); + container.registerInstance(GlobalValidationConfiguration, this); + } +} diff --git a/src/validation-controller-factory.ts b/src/validation-controller-factory.ts index 15a25ba9..3dff5177 100644 --- a/src/validation-controller-factory.ts +++ b/src/validation-controller-factory.ts @@ -1,4 +1,5 @@ import { Container } from 'aurelia-dependency-injection'; +import { GlobalValidationConfiguration } from './config'; import { ValidationController } from './validation-controller'; import { Validator } from './validator'; import { PropertyAccessorParser } from './property-accessor-parser'; @@ -21,7 +22,8 @@ export class ValidationControllerFactory { validator = this.container.get(Validator) as Validator; } const propertyParser = this.container.get(PropertyAccessorParser) as PropertyAccessorParser; - return new ValidationController(validator, propertyParser); + const config = this.container.get(GlobalValidationConfiguration) as GlobalValidationConfiguration; + return new ValidationController(validator, propertyParser, config); } /** diff --git a/src/validation-controller.ts b/src/validation-controller.ts index 24683658..42657778 100644 --- a/src/validation-controller.ts +++ b/src/validation-controller.ts @@ -1,4 +1,5 @@ import { Binding, Expression } from 'aurelia-binding'; +import { GlobalValidationConfiguration } from './config'; import { Validator } from './validator'; import { validateTrigger } from './validate-trigger'; import { getPropertyInfo } from './property-info'; @@ -15,7 +16,7 @@ import { ValidateEvent } from './validate-event'; * Exposes the current list of validation results for binding purposes. */ export class ValidationController { - public static inject = [Validator, PropertyAccessorParser]; + public static inject = [Validator, PropertyAccessorParser, GlobalValidationConfiguration]; // Registered bindings (via the validate binding behavior) private bindings = new Map(); @@ -47,14 +48,22 @@ export class ValidationController { /** * The trigger that will invoke automatic validation of a property used in a binding. */ - public validateTrigger = validateTrigger.blur; + public validateTrigger: validateTrigger; // Promise that resolves when validation has completed. private finishValidating: Promise = Promise.resolve(); private eventCallbacks: ((event: ValidateEvent) => void)[] = []; - constructor(private validator: Validator, private propertyParser: PropertyAccessorParser) { } + constructor( + private validator: Validator, + private propertyParser: PropertyAccessorParser, + config?: GlobalValidationConfiguration, + ) { + this.validateTrigger = config instanceof GlobalValidationConfiguration + ? config.getDefaultValidationTrigger() + : GlobalValidationConfiguration.DEFAULT_VALIDATION_TRIGGER; + } /** * Subscribe to controller validate and reset events. These events occur when the diff --git a/test/validation-controller-factory.ts b/test/validation-controller-factory.ts index 0c6ca977..d74d6af9 100644 --- a/test/validation-controller-factory.ts +++ b/test/validation-controller-factory.ts @@ -1,22 +1,28 @@ -import { Container, Optional } from 'aurelia-dependency-injection'; -import { - ValidationControllerFactory, - ValidationController, - Validator -} from '../src/aurelia-validation'; - -describe('ValidationControllerFactory', () => { - it('createForCurrentScope', () => { - const container = new Container(); - const standardValidator = {}; - container.registerInstance(Validator, standardValidator); - const childContainer = container.createChild(); - const factory = childContainer.get(ValidationControllerFactory); - const controller = factory.createForCurrentScope(); - expect(controller.validator).toBe(standardValidator); - expect(container.get(Optional.of(ValidationController))).toBe(null); - expect(childContainer.get(Optional.of(ValidationController))).toBe(controller); - const customValidator = {}; - expect(factory.createForCurrentScope(customValidator).validator).toBe(customValidator); - }); -}); +import { Container, Optional } from 'aurelia-dependency-injection'; +import { + GlobalValidationConfiguration, + ValidationControllerFactory, + ValidationController, + Validator, + validateTrigger +} from '../src/aurelia-validation'; + +describe('ValidationControllerFactory', () => { + it('createForCurrentScope', () => { + const container = new Container(); + const standardValidator = {}; + container.registerInstance(Validator, standardValidator); + const config = new GlobalValidationConfiguration(); + config.defaultValidationTrigger(validateTrigger.manual); + container.registerInstance(GlobalValidationConfiguration, config); + const childContainer = container.createChild(); + const factory = childContainer.get(ValidationControllerFactory); + const controller = factory.createForCurrentScope(); + expect(controller.validator).toBe(standardValidator); + expect(controller.validateTrigger).toBe(validateTrigger.manual); + expect(container.get(Optional.of(ValidationController))).toBe(null); + expect(childContainer.get(Optional.of(ValidationController))).toBe(controller); + const customValidator = {}; + expect(factory.createForCurrentScope(customValidator).validator).toBe(customValidator); + }); +}); diff --git a/test/validation-controller.ts b/test/validation-controller.ts new file mode 100644 index 00000000..d1c20c97 --- /dev/null +++ b/test/validation-controller.ts @@ -0,0 +1,22 @@ +import { + GlobalValidationConfiguration, + PropertyAccessorParser, + ValidationController, + Validator, + validateTrigger, +} from '../src/aurelia-validation'; + +describe('ValidationController', () => { + it('takes a validator, a PropertyAccessorParser, and optional config', () => { + const validator = {} as any as Validator; + const parser = {} as any as PropertyAccessorParser; + const controller = new ValidationController(validator, parser); + expect(controller.validateTrigger).toBe(GlobalValidationConfiguration.DEFAULT_VALIDATION_TRIGGER); + + const trigger = validateTrigger.changeOrBlur; + const config = new GlobalValidationConfiguration(); + config.defaultValidationTrigger(trigger); + const controllerWithConfig = new ValidationController(validator, parser, config); + expect(controllerWithConfig.validateTrigger).toBe(trigger); + }); +});