Angular 2: JavaScript-datumobject gebruiken met NgModel bidirectionele binding

Ik werk met Angular 2 en ik heb deze code:

JS, deze code initieert de werknemer-variabele voor de sjabloon:

handleEmployee(employee : Employee){
        this.employee = employee;
        this.employee.startDate = new Date('2005/01/01');
        console.log(this.employee);
    }

Sjabloon:

...
<div>
    <label>Start date: </label>
    <input [(ngModel)]="employee.startDate" type="date" name="startDate"/>
  </div>
  <div>
...

Andere gegevens zoals voornaam worden correct weergegeven. Maar voor de datum krijg ik gewoon:

mm/dd/yyyy

In het invoerelement, dat een datum zou moeten zijn.

Hoe kan ik dit doen?


Antwoord 1, autoriteit 100%

UPDATE:

StackBlitz

toen ik dit antwoord schreef DatePipebestond niet, nu kun je dit gewoon doen

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

`


Oud antwoord:

PLUNKER

U moet date objectconverteren in het input type="date"formaat dat yyyy-mm-ddis, dit is hoe het zal werken

Sjabloon:

<input [(ngModel)]="humanDate" type="date" name="startDate"/>

Onderdeel (TS):

export class App {
  startDate: any;
  constructor() {
    this.startDate = new Date(2005, 1, 4);
  }
  set humanDate(e){
    e = e.split('-');
    let d = new Date(Date.UTC(e[0], e[1]-1, e[2]));
    this.startDate.setFullYear(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate());
  }
  get humanDate(){
    return this.startDate.toISOString().substring(0, 10);
  }
}

Antwoord 2, autoriteit 17%

Lees pipesen ngModel
en mijn besluit:

<input type="date" class="form-control" id="myDate" [ngModel]="myDate | date:'y-MM-dd'" (ngModelChange)="myDate = $event" name="birthday">

Antwoord 3, autoriteit 7%

FormControls (zowel sjabloongestuurd als reactief) abonneren op waarden en schrijven waarden via richtlijnen die ControlValueAccessorimplementeren. Bekijk de relevante methode selectValueAccessor, die in alle noodzakelijke richtlijnen wordt gebruikt. Normale invoerbesturingselementen (bijv. <input type="text">) of tekstgebieden worden afgehandeld door de DefaultValueAccessor. Een ander voorbeeld is de CheckboxValueAccessordie wordt toegepast op invoerbesturingselementen voor selectievakjes.

Het werk is helemaal niet ingewikkeld. We moeten alleen een nieuwe waarde-accessor implementeren voor besturingselementen voor datuminvoer.
DateValueAccessoris een mooie naam:

// 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
 *  `<input type="date" name="myBirthday" ngModel useValueAsDate>`
 */
@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 koppelen de DateValueAccessoraan de multi-provider DATE_VALUE_ACCESSOR, zodat selectValueAccessorkan het vinden.

De enige vraag is welke selector moet worden gebruikt. Ik heb gekozen voor een opt-in-oplossing.
Hier selecteert de DateValueAccessor op het attribuut “useValueAsDate”.

<input type="date" name="myBirthday" ngModel useValueAsDate>
OR
<input type="date" name="myBirthday" [(ngModel)]="myBirthday" useValueAsDate>
OR
<input type="date" formControlName="myBirthday" useValueAsDate>

Het is ook mogelijk om de standaardimplementatie te herstellen.
De volgende selector zou de functie op magische wijze activeren.

// 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]'

Maar houd er rekening mee dat dit bestaande implementaties kan doorbreken die afhankelijk zijn van het oude gedrag. Dus ik zou voor de opt-in versie gaan!

Het staat allemaal op NPM en Github

Voor uw gemak heb ik het project angular-data-value-accessorop Github.
Er is ook een NPM pakket beschikbaar:

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

Importeer vervolgens de module via NgModule:

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

Je kunt nu de “useValueAsDate” toepassen op je datuminvoeropties.

Demo

Natuurlijk is er een demo op:
http://johanneshoppe.github.io/angular-date-value-accessor/


Antwoord 4, autoriteit 3%

Ik begon de oplossing van Ankit Singh te implementeren en liep tegen een paar problemen aan met validatie en tijdzone-dingen. (Zelfs na het proberen van de suggesties in het commentaargedeelte van dat antwoord)

In plaats daarvan koos ik ervoor om moment.js te gebruiken om de transformatie tussen string en datum af te handelen met behulp van ISO8601-datumstrings. Ik heb in het verleden geweldige resultaten behaald met moment.js, dus dit was geen moeilijke beslissing. Lijkt goed te werken voor mij, hopelijk vindt iemand anders dit nuttig.

Voor mijn Angular 2-app heb ik npm install –save moment uitgevoerd en vervolgens de oplossing van Ankit omgezet in een wrapper rond een js Date-object:

import * as moment from 'moment';
export class NgDate {
    date: any;
    constructor() {
        this.date = new Date();
    }
    set dateInput(e) {
        if (e != "") {
            var momentDate = moment(e, moment.ISO_8601).toDate();
            this.date = momentDate;
        }
        else {
            this.date = null;
        }
    }
    get dateInput() {
        if(this.date == null)
        {
            return "";
        }
        var stringToReturn = moment(this.date).format().substring(0, 10);
        return stringToReturn;
    }
}

Dan voor de HTML:

<input type="date" name="someDate" [(ngModel)]="ngDateModel.dateInput"/>

Antwoord 5, autoriteit 2%

Opgelost met deze code:

handleEmployee(employee : Employee){
        this.employee = employee;
        let dateString : string = employee.startDate.toString();
        let days : number = parseInt(dateString.substring(8, 10));
        let months : number = parseInt(dateString.substring(5, 7));
        let years : number = parseInt(dateString.substring(0, 5));
        let goodDate : Date = new Date(years + "/" + months + "/" + days);
        goodDate.setDate(goodDate.getDate() + 2);
        this.date = goodDate.toISOString().substring(0, 10);
    }

Html:

<div>
    <label>Start date: </label>
    <input [(ngModel)]="date" type="date" name="startDate"/>
  </div>

Antwoord 6, autoriteit 2%

Ik denk dat het geaccepteerde antwoord een functieaanroep mist om de invoerdatumreeks om te zetten in een Date-object. Dus dit:

(ngModelChange)="startDate = $event"

Zou zoiets moeten zijn als:

(ngModelChange)="startDate = toDate($event)"

Ik gebruik Moment.js, wat het VEEL eenvoudiger maakt:

mijn.component.ts

...
import * as moment from 'moment';
...
@Component ({
  ...
})
export class MyComponent implements OnInit {
  public fromDate: moment.Moment;
  public toDate: moment.Moment;
  ngOnInit() {
    this.toDate = moment();
    this.fromDate = moment().subtract(1, 'week');
  }
  dateStringToMoment(dateString: string): moment.Moment {
    return moment(dateString);
  }

Snippet uitvouwen


Antwoord 7

Een lokale tekenreeksvariabele gemaakt

dateField: string;

En dat bind ik aan mijn formulier

Datuminvoer

<input type="text" class="form-control" required [(ngModel)]="dateField" />

Wijs dat later gewoon weer toe aan de eigenschap Date net voordat u een API-aanroep doet

insert() {
    this.myObjet.date = new Date(this.dateField);
    ... call api
update() {
    this.myObjet.date = new Date(this.dateField);
    ... call api

Other episodes