Search code examples
angularformsdate

Binding with [(ngModel)] an Input of type Date not showing the date


I'm trying to display (Angular 15), in a form, a preset date that I created in the component this way:

defaultOpening: Opening = new Opening(1, new Date(), new Date());
ngOnInit() {
    this.HotelModel.openings.push(this.defaultOpening);
}

The field is showing correctly in the ngFor loop:

<tr *ngFor="let opening of HotelModel.openings">
  <td>{{ opening.start | date : 'yyyy-MM-dd' }}</td>
  <td>{{ opening.end | date : 'yyyy-MM-dd' }}</td>
</tr>

enter image description here

But show as empty date fields in this loop:

<tr *ngFor="let opening of HotelModel.openings; let i = index">
  <td><input [(ngModel)]="opening.start" name="startMonth{{i}}" type="date"></td>
  <td><input [(ngModel)]="opening.end" name="startDay{{i}}" type="date"></td>
</tr>

Like this: enter image description here

Is there a way to show it?


Solution

  • Updated Answer:

    Despite the old answer still being valid, there is a better way of doing this using signals.

    You can use 2 signals, a dateString WritableSignal and a date ComputedSignal.

    // .html
    <input [(ngModel)]="dateString" type="date" />
    
    // .ts
    @Component({
        selector: 'some-selector',
        template: `<input [(ngModel)]="dateString" type="date" />`,
    })
    export class SomeComponent {
        protected readonly dateString = signal('');
        protected readonly date = computed(() => {
            const [year, month, day] = this.dateString().split("-").map(Number);
            return new Date(year, month - 1, day);
        });
    }
    
    

    Old Answer:

    The type="date" tells the browser to render a date picker instead of a text field and the actual value of the input is just text string with yyyy-MM-dd format (see input type="date"), so, for two way binding to work you need to pass a string in the correct format.

    You can do as @DEV suggests and do:

    <input 
        [ngModel]="opening.start | date:'yyyy-MM-dd'" 
        (ngModelChange)="opening.start = $event" 
        type="date" 
        name="opening.start"
    />
    

    but be mindful that the moment you change the value, instead of an object you will have a string which will need to be converted back to an object. This conversion can happen during the ngModelChange event, just do opening.start = toDate($event) where toDate takes a string in yyyy-MM-dd format and returns a date.