angulardatepickerangular-reactive-formsng-bootstrapangular-formly

NgbDatepicker in Reactive Forms with formly: Set Initial Value


I am trying to use the ngbDatepicker in an angular reactive form and would want to be able to display the initial value.

My question in this is very similar to another one with the crucial difference, that I am also using formly, an angular package to automate away form generation. As the answer to the original question is based on generating a new formControl and adding it to the form, which in my case is done by formly, which is why I'm struggling.

The "component" generally functions when you want to enter a new value (because that triggers an event which I use to change the model value), but the initial value isn't displayed properly. While the model always has the value of e.g. "2020-07-05" if inspected with augury, this is never displayed in the input-field. This stays true if I convert the date in the model to an NgbDate ({year, month, day}) in ngOnInit().

Formly calls my custom component (defined below) that contains solely the field and binds the pre-existing formcontrol (including model) and field-configurations to the input field. The component itself doesn't do much, it contains the necessary HTML for the ngbDatepicker and a function that, when a date is chosen, converts it from an NgbDate ({year, month, day}) to a string ("yyyy-mm-dd") and ensures that that is stored in the model instead of the NgbDate. It also opens the datepicker when you click on fa-calendar icon:

//formly-datepicker.component.html

<div class="form-group" [ngClass]="{'d-none': to.hidden}">
    <!-- Heading --> 
    <!-- to = TemplateOptions -->
    <label for="datepicker">
        <strong>
            {{to.label}}
            <span *ngIf="to.required">*</span>
        </strong>
    </label>

    <!-- Input -->
    <div class="input-group">
        <input
        class="form-control" 
        placeholder="yyyy-mm-dd" 
        name="datepicker" 
        [formControl]="formControl" 
        [formlyAttributes]="field" 
        ngbDatepicker 
        #datepickerInput="ngbDatepicker"
        (dateSelect)="inputDateToField($event)"
        >
        <div class="input-group-append">
            <div class="btn btn-outline-light fa fa-calendar" (click)="datepickerInput.toggle()"></div>
        </div>
    </div>
</div>


<ng-template #customDay let-date>
    <div class="datepicker-day btn-light">
        {{ date.day }}
    </div>
</ng-template>



//formly-datepicker.component.ts
import { Component, } from '@angular/core';
import { NgbDate } from '@ng-bootstrap/ng-bootstrap';
import { FieldType } from '@ngx-formly/core';

@Component({
  selector: 'app-formly-datepicker',
  templateUrl: './formly-datepicker.component.html',
  styleUrls: ['./formly-datepicker.component.scss']
})
export class FormlyDatepickerComponent extends FieldType{
  inputDateToField(event: NgbDate){
    this.model.session_date = `${event.year}-${event.month}-${event.day}`;
  }
}

I have tried manipulating the model in ngOnInit() and ngAfterViewInit(), I have tried setting startDate, but nothing seems to help in this case. What am I to do here?


Solution

  • I would urge you to update the configs for both NgBootstrap and Formly (if you haven't already):

    1. Instead of using the inputDateToField method in your component, create these two services (parser and adapter) recommended by NgBootstrap for the NgbDatePicker. The parser will maintain the format you specify in the model and the adapter will display the date in the UI, again as per your customization. E.g. I use the parser to convert the ISO string the backend provides to save it as 'YYYY-MM-DD' in my model and the adapter to display it as 'DD-MM-YYYY'
    2. Wherever you import FormlyModule update the config like so (if it isn't in the AppModule, you may have to use forChild):
    FormlyModule.forRoot({types: [{ name: 'date', component: FormlyDatepickerComponent, extends: 'input'}]})
    
    1. In your FormlyDatepickerComponent's template, add type="text" (optional).