提供程序在 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,当出现选项时你就可以接受了。

  1. 您必须在 app.module.ts
  2. 中添加服务

这里是完整的代码

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 { }
  1. 最后,您需要将服务添加到 app.component.ts
  2. 中的构造函数

这是部分代码:

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,这样你就可以看到它在那里工作。