I have created the following project https://stackblitz.com/edit/angular-agzqbf You can see in the console the variable x
is undefined
from the beginning, even after initializing the variable in ngOnInit
The function that prints out the value of x
is format()
which is a function inherited from the parent class, and it is called every time a date is selected in the input
field with calendar. But it is always undefined
even after changing its value with a button calling changeValue()
Is this the normal behavior of providers? or how can I make sure the format()
function has access to the variable class?
app.component.html
<form class="form-inline">
<div class="form-group">
<div class="input-group">
<input class="form-control" placeholder="yyyy-mm-dd"
(focus)="d.open()" name="dp" [(ngModel)]="model" ngbDatepicker #d="ngbDatepicker">
<div class="input-group-append">
<button class="btn btn-outline-secondary calendar" (click)="d.toggle()" type="button"></button>
</div>
</div>
</div>
</form>
<button (click)="changeValue()"> Change X value</button>
app.component.ts
import { Component, OnInit } from '@angular/core';
import { NgbDateParserFormatter, NgbDateStruct } from "@ng-bootstrap/ng-bootstrap";
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: []
})
export class AppComponent extends NgbDateParserFormatter implements OnInit {
title = 'test-project';
x: number;
model;
constructor() {
super();
}
ngOnInit() {
this.x = 9;
}
changeValue() {
this.x = 5;
console.log('x changed', this.x);
}
private padNumber(value: number) {
if (this.isNumber(value)) {
return `0${value}`.slice(-2);
} else {
return "";
}
}
private isNumber(value: any): boolean {
return !isNaN(this.toInteger(value));
}
private toInteger(value: any): number {
return parseInt(`${value}`, 10);
}
parse(value: string): NgbDateStruct {
if (value) {
const dateParts = value.trim().split('/');
if (dateParts.length === 1 && this.isNumber(dateParts[0])) {
return {year: this.toInteger(dateParts[0]), month: null, day: null};
} else if (dateParts.length === 2 && this.isNumber(dateParts[0]) && this.isNumber(dateParts[1])) {
return {year: this.toInteger(dateParts[1]), month: this.toInteger(dateParts[0]), day: null};
} else if (dateParts.length === 3 && this.isNumber(dateParts[0]) && this.isNumber(dateParts[1]) && this.isNumber(dateParts[2])) {
return {year: this.toInteger(dateParts[2]), month: this.toInteger(dateParts[1]), day: this.toInteger(dateParts[0])};
}
}
return null;
}
format(date: NgbDateStruct): string {
console.log('x value', this.x);
let stringDate: string = "";
if(date) {
stringDate += this.isNumber(date.year) ? date.year + "/" : "";
stringDate += this.isNumber(date.month) ? this.padNumber(date.month) + "/" : "";
stringDate += this.isNumber(date.day) ? this.padNumber(date.day) : "";
}
return stringDate;
}
}
PS: both parse()
and format()
functions are inherited from the parent class to set the correct format in the input field after selecting a date
lets look at NgModule description
providers: [{ provide: NgbDateParserFormatter, useClass: AppComponent}]
this string means that when something tries to inject NgbDateParserFormatter
angular will create AppComponent
and passes it instead. To achieve what you are trying to achieve add providers section to app component with useExisting: AppComponent
like this:
@Component({
...
providers: [{ provide: NgbDateParserFormatter, useExisting: AppComponent }]
})
export class AppComponent{
...