Angular 2 date pipe inside a FormControl input

14,814

One way to do such a thing would be to create a component for your input that implements ControlValueAccessor

A bridge between a control and a native element.

A ControlValueAccessor abstracts the operations of writing a new value to a DOM element representing an input control.

Please see DefaultValueAccessor for more information.

Something like this should do the trick (not tested):

export const DATE_VALUE_ACCESSOR: any = {
  provide: NG_VALUE_ACCESSOR,
  useExisting: forwardRef(() => MyDateInput),
  multi: true
};

@Component({
    template:`<input #input (input)="onChange($event)" (blur)="touchCallback()" type="date" [attr.disabled]="disabled?true:null">`
    selector:"my-input",
    styles:[],
    providers:[DATE_VALUE_ACCESSOR]
})
export class MyDateInput implements ControlValueAccessor{
    @ViewChild("input")
    input:ElementRef;
    disabled=false;
    changeCallback=(data:any)=>{};
    touchCallback=()=>{};

    onChange(event){
        let timestamp=this.convertToTimestamp(event.target.value);
        this.changeCallback(timestamp);
    }

    convertToTimestamp(formatedDate){
        //TODO:implement
    }

    convertFromTimestamp(timestamp){
        //TODO:implement
    }

    writeValue(obj: any){
        let formatedDate=this.convertFromTimestamp(obj);
        this.input.nativeElement.value=formatedDate;
    }

    registerOnChange(fn: any){
        this.changeCallback=fn;
    }

    registerOnTouched(fn: any){
        this.touchCallback=fn;
    }

    setDisabledState(isDisabled: boolean){
        this.disabled=isDisabled;
    }
}

then you should be able to use it like this:

<my-input class="form-control" [formControlName]="question.key"></my-input>

or

<my-input [(ngModel)]="myModel"></my-input>
Share:
14,814

Related videos on Youtube

ktsangop
Author by

ktsangop

Web applications, HTML5 games, Destkop applications (Windows) and Linux administration.

Updated on September 15, 2022

Comments

  • ktsangop
    ktsangop over 1 year

    I have a dynamically generated Angular 2 FormGroup with multiple FormControl input fields. Some of the inputs are Dates, which are fetched from the server as unix timestamps.

    What i would like to do is :

    1. to be able to translate the unix timestamp to a human readable form, when my FormGroup is populated, and also
    2. translate the human representation of the date to a unix timestamp when the form is submitted.

    Part 1 is somewhat simple, using Angular's date pipe like this :

    <input class="form-control" [formControlName]="question.key"
    [value]="this.form.controls[this.question.key].value | date:'dd/MM/yyyy'">
    

    Where this.form is a reference to the FormGroup and this.question is a custom wrapper class based on the official tutorial about dynamic forms :

    https://angular.io/docs/ts/latest/cookbook/dynamic-form.html

    Trying to change the date input that way won't work because the pipe will constantly try to transform the input value, thus making the input unusable if not throwing an Invalid argument for pipe 'DatePipe' exception.

    To clarify, i fill my form using the FormGroup.patchValue() api, and submit the form data using the FormGroup.getRawValue() api.

    I have tried to use an Angular 2 date picker component, but they made my huge forms pretty slow, so i would like to do it without custom date pickers or any jQuery dependent widgets.

    Thanks in advance.

  • ktsangop
    ktsangop about 7 years
    Thanks i will try this approach, and come back to you as soon as possible.
  • n00dl3
    n00dl3 about 7 years
    Oops I just realized that I forgot an important part in the @Component declaration. I'll edit asap.
  • ktsangop
    ktsangop about 7 years
    changeCallback and touchCallback need to be initialized i suppose like this touchCallback : any = () => {}; Other than that, and after a lot of reading i think i understand how it works now! Will accept your answer shortly, if i have no other questions.Thanks!
  • n00dl3
    n00dl3 about 7 years
    You're right, they need to be initialized, I edited.