Angular 2: How to use JavaScript Date Object with NgModel two way binding

后端 未结 7 1742
醉酒成梦
醉酒成梦 2020-12-02 10:01

I\'m working with Angular 2 and I have this code:

JS, this code initiates the employee-variable for the template:

handleEmployee(employee : Employee)         


        
7条回答
  •  感情败类
    2020-12-02 10:26

    FormControls (both template-driven and reactive) subscribe for values and write values via Directives that implement ControlValueAccessor. Take a look at the relevant method selectValueAccessor, which is used in all necessary directives. Normal input controls (e.g. ) or textareas are handled by the DefaultValueAccessor. Another example is the CheckboxValueAccessor which is applied to checkbox input controls.

    The job isn't complicated at all. We just need to implement a new value accessor for date input controls.
    DateValueAccessor is a nice name:

    // date-value-accessor.ts
    
    import { Directive, ElementRef, HostListener, Renderer, forwardRef } from '@angular/core';
    import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
    
    export const DATE_VALUE_ACCESSOR: any = {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => DateValueAccessor),
      multi: true
    };
    
    /**
     * The accessor for writing a value and listening to changes on a date input element
     *
     *  ### Example
     *  ``
     */
    @Directive({
      selector: '[useValueAsDate]',
      providers: [DATE_VALUE_ACCESSOR]
    })
    export class DateValueAccessor implements ControlValueAccessor {
    
      @HostListener('input', ['$event.target.valueAsDate']) onChange = (_: any) => { };
      @HostListener('blur', []) onTouched = () => { };
    
      constructor(private _renderer: Renderer, private _elementRef: ElementRef) { }
    
      writeValue(value: Date): void {
        this._renderer.setElementProperty(this._elementRef.nativeElement, 'valueAsDate', value);
      }
    
      registerOnChange(fn: (_: any) => void): void { this.onChange = fn; }
      registerOnTouched(fn: () => void): void { this.onTouched = fn; }
    
      setDisabledState(isDisabled: boolean): void {
        this._renderer.setElementProperty(this._elementRef.nativeElement, 'disabled', isDisabled);
      }
    }
    

    We attach the DateValueAccessor to the multi-provider DATE_VALUE_ACCESSOR, so that selectValueAccessor can find it.

    The only question is, which selector should be used. I decided for an opt-in solution.
    Here the DateValueAccessor selects on the attribute "useValueAsDate".

    
    
    OR
    
    
    
    OR
    
    
    

    It is also possible to fix the default implementation.
    The following selector would activate the feature magically.

    // this selector changes the previous behavior silently and might break existing code
    selector: 'input[type=date][formControlName],input[type=date][formControl],input[type=date][ngModel]'
    

    But please be aware, that this might break existing implementations that rely of the old behaviour. So I would go for the opt-in version!

    It's all on NPM and Github

    For your convenience, I created the project angular-data-value-accessor on Github.
    There is also a NPM package available:

    npm install --save angular-date-value-accessor
    

    Then just import the module via NgModule:

    // app.module.ts
    
    import { DateValueAccessorModule } from 'angular-date-value-accessor';
    
    @NgModule({
      imports: [
        DateValueAccessorModule
      ]
    })
    export class AppModule { }
    

    Now you can apply the "useValueAsDate" to your date input controls.

    Demo

    Of course, there is a demo at: http://johanneshoppe.github.io/angular-date-value-accessor/

提交回复
热议问题