Skip to content

Commit

Permalink
Merge pull request #536 from RomkeVdMeulen/feat-535-configure-trigger
Browse files Browse the repository at this point in the history
feat(config): support global config option for default validation trigger
  • Loading branch information
EisenbergEffect authored Nov 22, 2019
2 parents d3a2998 + bd118a6 commit 5b09f86
Show file tree
Hide file tree
Showing 6 changed files with 109 additions and 52 deletions.
30 changes: 4 additions & 26 deletions src/aurelia-validation.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Exports

export * from './config';
export * from './controller-validate-result';
export * from './get-target-dom-element';
export * from './property-info';
Expand All @@ -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';
Expand All @@ -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.
Expand All @@ -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);
}
Expand Down
40 changes: 40 additions & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
@@ -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);
}
}
4 changes: 3 additions & 1 deletion src/validation-controller-factory.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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);
}

/**
Expand Down
15 changes: 12 additions & 3 deletions src/validation-controller.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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<Binding, BindingInfo>();
Expand Down Expand Up @@ -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<any> = 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
Expand Down
50 changes: 28 additions & 22 deletions test/validation-controller-factory.ts
Original file line number Diff line number Diff line change
@@ -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);
});
});
22 changes: 22 additions & 0 deletions test/validation-controller.ts
Original file line number Diff line number Diff line change
@@ -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);
});
});

0 comments on commit 5b09f86

Please sign in to comment.