From 3eff7be9a652e65f4cc464c6ff4f481948f8fca4 Mon Sep 17 00:00:00 2001 From: vsavkin Date: Fri, 5 Jun 2015 15:27:25 -0700 Subject: [PATCH] examples(forms): added an example of using template-driven forms --- .../directives/default_value_accessor.ts | 5 +- .../src/template_driven_forms/index.html | 19 +++ .../src/template_driven_forms/index.ts | 157 ++++++++++++++++++ 3 files changed, 179 insertions(+), 2 deletions(-) create mode 100644 modules/examples/src/template_driven_forms/index.html create mode 100644 modules/examples/src/template_driven_forms/index.ts diff --git a/modules/angular2/src/forms/directives/default_value_accessor.ts b/modules/angular2/src/forms/directives/default_value_accessor.ts index d8b8546672..98c6a9ad18 100644 --- a/modules/angular2/src/forms/directives/default_value_accessor.ts +++ b/modules/angular2/src/forms/directives/default_value_accessor.ts @@ -1,6 +1,7 @@ import {Directive} from 'angular2/angular2'; import {ControlDirective} from './control_directive'; import {ControlValueAccessor} from './control_value_accessor'; +import {isBlank} from 'angular2/src/facade/lang'; /** * The default accessor for writing a value and listening to changes that is used by a @@ -34,7 +35,7 @@ import {ControlValueAccessor} from './control_value_accessor'; } }) export class DefaultValueAccessor implements ControlValueAccessor { - value = null; + value: string = null; onChange: Function; onTouched: Function; @@ -44,7 +45,7 @@ export class DefaultValueAccessor implements ControlValueAccessor { cd.valueAccessor = this; } - writeValue(value) { this.value = value; } + writeValue(value) { this.value = isBlank(value) ? "" : value; } registerOnChange(fn): void { this.onChange = fn; } diff --git a/modules/examples/src/template_driven_forms/index.html b/modules/examples/src/template_driven_forms/index.html new file mode 100644 index 0000000000..79ca5b3efb --- /dev/null +++ b/modules/examples/src/template_driven_forms/index.html @@ -0,0 +1,19 @@ + + + + Template Driven Forms + + + + + + Loading... + + + $SCRIPTS$ + + diff --git a/modules/examples/src/template_driven_forms/index.ts b/modules/examples/src/template_driven_forms/index.ts new file mode 100644 index 0000000000..61ca94737d --- /dev/null +++ b/modules/examples/src/template_driven_forms/index.ts @@ -0,0 +1,157 @@ +import {bootstrap, onChange, NgIf, Component, Directive, View, Ancestor} from 'angular2/angular2'; +import { + formDirectives, + ControlDirective, + Validators, + TemplateDrivenFormDirective +} from 'angular2/forms'; + +import {ObservableWrapper} from 'angular2/src/facade/async'; +import {RegExpWrapper, print, isPresent} from 'angular2/src/facade/lang'; + +import {reflector} from 'angular2/src/reflection/reflection'; +import {ReflectionCapabilities} from 'angular2/src/reflection/reflection_capabilities'; + +/** + * A domain model we are binding the form controls to. + */ +class CheckoutModel { + firstName: string; + middleName: string; + lastName: string; + + creditCard: string; + amount: number; + email: string; + comments: string; +} + +/** + * Custom validator. + */ +@Directive({selector: '[credit-card]'}) +class CreditCardValidator { + constructor(c: ControlDirective) { + c.validator = Validators.compose([c.validator, CreditCardValidator.validate]); + } + + static validate(c): StringMap { + if (isPresent(c.value) && RegExpWrapper.test(new RegExp("^\\d{16}$"), c.value)) { + return null; + } else { + return {"invalidCreditCard": true}; + } + } +} + +/** + * This is a component that displays an error message. + * + * For instance, + * + * + * + * Will display the "is required" error if the control is empty, and "invalid credit card" if the + * control is not empty + * but not valid. + * + * In a real application, this component would receive a service that would map an error code to an + * actual error message. + * To make it simple, we are using a simple map here. + */ +@Component({selector: 'show-error', properties: ['controlPath: control', 'errorTypes: errors']}) +@View({ + template: ` + {{errorMessage}} + `, + directives: [NgIf] +}) +class ShowError { + formDir; + controlPath: string; + errorTypes: List; + + constructor(@Ancestor() formDir: TemplateDrivenFormDirective) { this.formDir = formDir; } + + get errorMessage() { + var c = this.formDir.form.find(this.controlPath); + for (var i = 0; i < this.errorTypes.length; ++i) { + if (isPresent(c) && c.touched && c.hasError(this.errorTypes[i])) { + return this._errorMessage(this.errorTypes[i]); + } + } + return null; + } + + _errorMessage(code) { + var config = {'required': 'is required', 'invalidCreditCard': 'is invalid credit card number'}; + return config[code]; + } +} + + +@Component({selector: 'template-driven-forms'}) +@View({ + template: ` +

Checkout Form

+ +
+

+ + + +

+ +

+ + +

+ +

+ + + +

+ +

+ + + +

+ +

+ + + +

+ +

+ + + +

+ +

+ + +

+ + +
+ `, + directives: [formDirectives, CreditCardValidator, ShowError] +}) +class TemplateDrivenForms { + model = new CheckoutModel(); + + onSubmit() { + print("Submitting:"); + print(this.model); + } +} + +export function main() { + reflector.reflectionCapabilities = new ReflectionCapabilities(); + bootstrap(TemplateDrivenForms); +}