import {View, Component, Decorator, Ancestor, onChange, ElementRef} from 'angular2/angular2'; import {Optional} from 'angular2/di'; import {Renderer} from 'angular2/src/render/api'; import {isBlank, isPresent, isString, CONST} from 'angular2/src/facade/lang'; import {StringMapWrapper, ListWrapper} from 'angular2/src/facade/collection'; import {ControlGroup, Control} from './model'; import {Validators} from './validators'; //export interface ControlValueAccessor { // writeValue(value):void{} // set onChange(fn){} //} /** * The default accessor for writing a value and listening to changes that is used by a {@link Control} directive. * * This is the default strategy that Angular uses when no other accessor is applied. * * # Example * ``` * * ``` * * @exportedAs angular2/forms */ @Decorator({ selector: '[control]', hostListeners: { 'change' : 'onChange($event.target.value)', 'input' : 'onChange($event.target.value)' }, hostProperties: { 'value' : 'value' } }) export class DefaultValueAccessor { value; onChange:Function; constructor() { this.onChange = (_) => {}; } writeValue(value) { this.value = value } } /** * The accessor for writing a value and listening to changes on a checkbox input element. * * * # Example * ``` * * ``` * * @exportedAs angular2/forms */ @Decorator({ selector: 'input[type=checkbox][control]', hostListeners: { 'change' : 'onChange($event.target.checked)' }, hostProperties: { 'checked' : 'checked' } }) export class CheckboxControlValueAccessor { _elementRef:ElementRef; _renderer:Renderer; checked:boolean; onChange:Function; constructor(cd:ControlDirective, elementRef:ElementRef, renderer:Renderer) { this.onChange = (_) => {}; this._elementRef = elementRef; this._renderer = renderer; cd.valueAccessor = this; //ControlDirective should inject CheckboxControlDirective } writeValue(value) { this._renderer.setElementProperty(this._elementRef.hostView.render, this._elementRef.boundElementIndex, 'checked', value) } } /** * Binds a control to a DOM element. * * # Example * * In this example, we bind the control to an input element. When the value of the input element changes, the value of * the control will reflect that change. Likewise, if the value of the control changes, the input element reflects that * change. * * Here we use {@link FormDirectives}, rather than importing each form directive individually, e.g. * `ControlDirective`, `ControlGroupDirective`. This is just a shorthand for the same end result. * * ``` * @Component({selector: "login-comp"}) * @View({ * directives: [FormDirectives], * inline: "" * }) * class LoginComp { * loginControl:Control; * * constructor() { * this.loginControl = new Control(''); * } * } * * ``` * * @exportedAs angular2/forms */ @Decorator({ lifecycle: [onChange], selector: '[control]', properties: { 'controlOrName' : 'control' } }) export class ControlDirective { _groupDirective:ControlGroupDirective; controlOrName:any; valueAccessor:any; //ControlValueAccessor validator:Function; constructor(@Optional() @Ancestor() groupDirective:ControlGroupDirective, valueAccessor:DefaultValueAccessor) { this._groupDirective = groupDirective; this.controlOrName = null; this.valueAccessor = valueAccessor; this.validator = Validators.nullValidator; } // TODO: vsavkin this should be moved into the constructor once static bindings // are implemented onChange(_) { this._initialize(); } _initialize() { if(isPresent(this._groupDirective)) { this._groupDirective.addDirective(this); } var c = this._control(); c.validator = Validators.compose([c.validator, this.validator]); this._updateDomValue(); this._setUpUpdateControlValue(); } _updateDomValue() { this.valueAccessor.writeValue(this._control().value); } _setUpUpdateControlValue() { this.valueAccessor.onChange = (newValue) => this._control().updateValue(newValue); } _control() { if (isString(this.controlOrName)) { return this._groupDirective.findControl(this.controlOrName); } else { return this.controlOrName; } } } /** * Binds a control group to a DOM element. * * # Example * * In this example, we bind the control group to the form element, and we bind the login and password controls to the * login and password elements. * * Here we use {@link FormDirectives}, rather than importing each form directive individually, e.g. * `ControlDirective`, `ControlGroupDirective`. This is just a shorthand for the same end result. * * ``` * @Component({selector: "login-comp"}) * @View({ * directives: [FormDirectives], * inline: "
" * }) * class LoginComp { * loginForm:ControlGroup; * * constructor() { * this.loginForm = new ControlGroup({ * login: new Control(""), * password: new Control("") * }); * } * * onLogin() { * // this.loginForm.value * } * } * * ``` * * @exportedAs angular2/forms */ @Decorator({ selector: '[control-group]', properties: { 'controlGroup' : 'control-group' } }) export class ControlGroupDirective { _groupDirective:ControlGroupDirective; _controlGroupName:string; _controlGroup:ControlGroup; _directives:List