服务数据 getter 在 Angular 中返回未定义

Service data getter returning undefined in Angular

我无法找出为什么在管道访问数据时我的 ShopManagerService 一直返回 undefined。这是 ShopManagerService:

@Injectable({ providedIn: 'root' })
export class ShopManagerService {
    private shopPreferences: ShopPreferences = null;

    setPreferences(shopPreferences: ShopPreferences) {
        this.shopPreferences = shopPreferences;
    }

    getDateFormat(){
        if(this.shopPreferences == null || this.shopPreferences.time_format.date == null) return;
        return this.shopPreferences.time_format.date;
    }
    ...
    // more data getters
}

之前的字段shopPreferences是在服务ApiManagerService中设置的,像这样:

@Injectable({ providedIn: 'root' })
export class ApiManagerService {

    private token = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6MjcwMjA3MiwidGltZXN0YW1wIjoiMjAyMS0wNC0wOSAwOToxNToxNS4';
    private webzine_id: string = "2702072";

    constructor(private http: HttpClient, private shopManager: ShopManagerService) {
        // We want to keep shop preferences updated throughout execution
        timer(0, 5000).pipe(
            filter(() => this.webzine_id && this.webzine_id !== ""),
            switchMap(() => this.fetchShopPreferences().pipe(first()))
        )
        .subscribe(preferences => this.shopManager.setPreferences(preferences)); 
    }

    fetchShopPreferences() {
        const url = "https://commerce.ww-api.com/commerceapi/v1/front/front_url/" + this.webzine_id + "/";
        return this.http
            .get<ShopPreferences>(url, {
                headers: new HttpHeaders({
                    token: this.token,
                }),
            });
    }
    ...
    // more api requests
}

组件如下所示:

@Component({
  selector: 'app-order-details',
  templateUrl: './order-details.component.html',
  styleUrls: ['./order-details.component.css']
})
export class OrderDetailsComponent {

      constructor(private apiManager: ApiManagerService, private shopPreferencesService: ShopManagerService){ }

      closeDetails(){
          /* implement close details functionality */
      }
}

在 .html 中调用管道,如下所示:

<div id="details-container">
    <div id="details-header">
        <div class="header-text">
            <!-- hard coded for now -->
            <label>#3172</label>
            <label>{{"01/18/2021" | addOrderDateHourFormat:"date"}}</label>
        </div>
        <div class="close-button" (click)="closeDetails()">
            <img src="../../../assets/my-orders/close-icon.svg">
        </div>
    </div>
   <app-order-properties></app-order-properties>
   <app-order-channel></app-order-channel>
</div>

在管道内部,代码如下所示:

@Pipe({
    name: 'addOrderDateHourFormat',
})
export class OrderDateFormatPipe implements PipeTransform {

    constructor(private formatService: FormatManagerService){}

    transform(value: string, type: string, trigger: number) {
        if(type === "hour"){
            return this.formatService.formatTime(value);
        }
        else if(type === "date"){
            return this.formatService.formatDate(value);
        }
        else if(type === "date+hour"){
            return this.formatService.formatDateAndTime(value)
        }
    }

}

最后,这是 FormatManagerService:

里面的样子
@Injectable({ providedIn: 'root' })
export class FormatManagerService {

    constructor(private datePipe: DatePipe, private shopPrefencesService: ShopManagerService) {}

    formatDate(date: string){
        let dateFormat = this.shopPrefencesService.getDateFormat(); // returning undefined
        if(dateFormat === "GBCOMMERCE_DATEFORMAT_1"){
            return this.datePipe.transform(date, 'EEEE, LLLL d yyyy');
        }
        else if(dateFormat === "GBCOMMERCE_DATEFORMAT_2"){
            return this.datePipe.transform(date, 'LLLL d yyyy');
        }
        else if(dateFormat === "GBCOMMERCE_DATEFORMAT_3"){
            return this.datePipe.transform(date, 'MM/d/yyyy');
        }
        else if(dateFormat === "GBCOMMERCE_DATEFORMAT_4"){
            return this.datePipe.transform(date, 'MM.d.yyyy');
        }
        else if(dateFormat === "GBCOMMERCE_DATEFORMAT_5"){
            return this.datePipe.transform(date, 'MM-d-yyyy');
        }
    }
    ...
    // more format methods
}

为什么formatDate()方法中的调用this.shopPrefencesService.getDateFormat()一直返回undefined?我在这里错过了什么?

在此先感谢您的帮助。

编辑:添加。html 和管道代码。

我会说这是因为异步。我认为您在 REST 调用 returns 值之前很久就调用了日期管道。而且管道只被发射一次。

我的建议如下。

使您的 ShopPreferences 成为 BehaviorSubject 类型的 Observable,并等待在 OrderDetailsComponent 中设置值。仅当该值存在时才渲染 div.

您的 ShopManagerService

@Injectable({ providedIn: 'root' })
export class ShopManagerService {
  private shopPreferences: BehaviorSubject<ShopPreferences> = new BehaviorSubject<ShopPreferences>(null);

  setPreferences(shopPreferences: ShopPreferences): void {
    this.shopPreferences.next(shopPreferences);
  }

  getPreferencesAsObservable(): Observable<ShopPreferences> {
    return this.shopPreferences.asObservable();
  }

  getDateFormat(): Date{
    if (this.shopPreferences.getValue() === null || this.shopPreferences.getValue().time_format.date === null) {
      return;
    }
    
    return this.shopPreferences.getValue().time_format.date;
  }

  // more data getters
}

您的 OrderDetailsComponent

@Component({
  selector: 'app-order-details',
  templateUrl: './order-details.component.html',
  styleUrls: ['./order-details.component.css']
})
export class OrderDetailsComponent {
    shopPreferencesArePresent = false;        

      constructor(private apiManager: ApiManagerService, private shopPreferencesService: ShopManagerService){
          this.shopPreferencesService.getPreferencesAsObservable().subscribe( value => {
              if (value) {
                  this.shopPreferencesArePresent = true;
              } 
          });

      }

      closeDetails(){
          /* implement close details functionality */
      }
}

以及您的 OrderDetailsComponent 的 HTML

    <div id="details-container">
    <div id="details-header">
        <div *ngIf="shopPreferencesArePresent" class="header-text">
            <!-- hard coded for now -->
            <label>#3172</label>
            <label>{{"01/18/2021" | addOrderDateHourFormat:"date"}}</label>
        </div>
        <div class="close-button" (click)="closeDetails()">
            <img src="../../../assets/my-orders/close-icon.svg">
        </div>
    </div>
   <app-order-properties></app-order-properties>
   <app-order-channel></app-order-channel>
</div>