提供程序在 Angular 中初始化后无法访问 class 变量
Provider has no access to class variables after being initialized in Angular
我创建了以下项目https://stackblitz.com/edit/angular-agzqbf你可以在控制台中看到变量x
从一开始就是undefined
,即使在ngOnInit
中初始化变量之后
打印出x
值的函数是format()
,它是继承父class的函数,每次选择日期时都会调用它input
带有日历的字段。但它始终是 undefined
,即使在通过调用 changeValue()
的按钮更改其值之后也是如此
这是提供商的正常行为吗?或者如何确保 format()
函数可以访问变量 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: parse()
和 format()
函数都继承自父 class 以在选择日期后在输入字段中设置正确的格式
让我们看看 NgModule 的描述
providers: [{ provide: NgbDateParserFormatter, useClass: AppComponent}]
这个字符串意味着当某些东西试图注入 NgbDateParserFormatter
时,angular 将创建 AppComponent
并传递它。要实现您想要实现的目标,请使用 useExisting: AppComponent
将提供程序部分添加到应用程序组件,如下所示:
@Component({
...
providers: [{ provide: NgbDateParserFormatter, useExisting: AppComponent }]
})
export class AppComponent{
...
1.You需要添加服务
我将其命名为 data.service.ts,只要您使用 xValueChange 方法,此服务就会更新您的 x 值。
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs/BehaviorSubject'
@Injectable()
export class DataService {
private x = new BehaviorSubject<number>(3);
valueOfx = this.x.asObservable();
constructor() { }
xValueChange(newValue: number) {
this.x.next(newValue);
}
}
Stackblizt会要求你安装rxjs,当出现选项时你就可以接受了。
- 您必须在 app.module.ts
中添加服务
这里是完整的代码
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { FormsModule } from '@angular/forms';
import { NgbModule, NgbActiveModal, NgbDatepicker, NgbDateParserFormatter } from '@ng-bootstrap/ng-bootstrap';
import { DataService } from './services/data.service';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
NgbModule,
FormsModule
],
providers: [{ provide: NgbDateParserFormatter, useClass: AppComponent}, DataService],
bootstrap: [AppComponent]
})
export class AppModule { }
- 最后,您需要将服务添加到 app.component.ts
中的构造函数
这是部分代码:
import { Component, OnInit } from '@angular/core';
import { NgbDateParserFormatter, NgbDateStruct } from "@ng-bootstrap/ng-bootstrap";
import { DataService } from './services/data.service';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: []
})
export class AppComponent extends NgbDateParserFormatter implements OnInit {
title = 'test-project';
x: number;
model;
constructor(private data :DataService) {
super();
this.data.valueOfx.subscribe(xValue => this.x = xValue);
}
ngOnInit() {
this.x = 9;
}
changeValue() {
this.x = 5;
this.data.xValueChange(5);
console.log('x changed', this.x);
}
之后你会看到x值并没有失去他改变后的值。今天晚些时候我会上传 stackblitz,这样你就可以看到它在那里工作。
我创建了以下项目https://stackblitz.com/edit/angular-agzqbf你可以在控制台中看到变量x
从一开始就是undefined
,即使在ngOnInit
中初始化变量之后
打印出x
值的函数是format()
,它是继承父class的函数,每次选择日期时都会调用它input
带有日历的字段。但它始终是 undefined
,即使在通过调用 changeValue()
这是提供商的正常行为吗?或者如何确保 format()
函数可以访问变量 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: parse()
和 format()
函数都继承自父 class 以在选择日期后在输入字段中设置正确的格式
让我们看看 NgModule 的描述
providers: [{ provide: NgbDateParserFormatter, useClass: AppComponent}]
这个字符串意味着当某些东西试图注入 NgbDateParserFormatter
时,angular 将创建 AppComponent
并传递它。要实现您想要实现的目标,请使用 useExisting: AppComponent
将提供程序部分添加到应用程序组件,如下所示:
@Component({
...
providers: [{ provide: NgbDateParserFormatter, useExisting: AppComponent }]
})
export class AppComponent{
...
1.You需要添加服务
我将其命名为 data.service.ts,只要您使用 xValueChange 方法,此服务就会更新您的 x 值。
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs/BehaviorSubject'
@Injectable()
export class DataService {
private x = new BehaviorSubject<number>(3);
valueOfx = this.x.asObservable();
constructor() { }
xValueChange(newValue: number) {
this.x.next(newValue);
}
}
Stackblizt会要求你安装rxjs,当出现选项时你就可以接受了。
- 您必须在 app.module.ts 中添加服务
这里是完整的代码
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { FormsModule } from '@angular/forms';
import { NgbModule, NgbActiveModal, NgbDatepicker, NgbDateParserFormatter } from '@ng-bootstrap/ng-bootstrap';
import { DataService } from './services/data.service';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
NgbModule,
FormsModule
],
providers: [{ provide: NgbDateParserFormatter, useClass: AppComponent}, DataService],
bootstrap: [AppComponent]
})
export class AppModule { }
- 最后,您需要将服务添加到 app.component.ts 中的构造函数
这是部分代码:
import { Component, OnInit } from '@angular/core';
import { NgbDateParserFormatter, NgbDateStruct } from "@ng-bootstrap/ng-bootstrap";
import { DataService } from './services/data.service';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: []
})
export class AppComponent extends NgbDateParserFormatter implements OnInit {
title = 'test-project';
x: number;
model;
constructor(private data :DataService) {
super();
this.data.valueOfx.subscribe(xValue => this.x = xValue);
}
ngOnInit() {
this.x = 9;
}
changeValue() {
this.x = 5;
this.data.xValueChange(5);
console.log('x changed', this.x);
}
之后你会看到x值并没有失去他改变后的值。今天晚些时候我会上传 stackblitz,这样你就可以看到它在那里工作。