首页 > 解决方案 > 如何解决 Ionic Angular 应用程序中的“数字”类型错误不存在属性订阅?

问题描述

以下代码在 Ionic 5 / Angular 教程中用于更新Place对象。我正在尝试将相同的代码应用于我更新Conversation对象的项目:

地方服务:

private _places = new BehaviorSubject<Place[]>([
    new Place(
      'p1',
      'Manhattan Mansion',
      'In the heart of New York City.',
      'https://lonelyplanetimages.imgix.net/mastheads/GettyImages-538096543_medium.jpg?sharp=10&vib=20&w=1200',
      149.99,
      new Date('2019-01-01'),
      new Date('2019-12-31'),
      'abc'
    )
  ]);

  get places() {
    return this._places.asObservable();
  }

updatePlace(placeId: string, title: string, description: string) {
    return this.places.pipe(
      take(1),
      delay(1000),
      tap(places => {
        const updatedPlaceIndex = places.findIndex(pl => pl.id === placeId);
        const updatedPlaces = [...places];
        const oldPlace = updatedPlaces[updatedPlaceIndex];
        updatedPlaces[updatedPlaceIndex] = new Place(
          oldPlace.id,
          title,
          description,
          oldPlace.imageUrl,
          oldPlace.price,
          oldPlace.availableFrom,
          oldPlace.availableTo,
          oldPlace.userId
        );
        this._places.next(updatedPlaces);
      })
    );
  }

这是Place模型:

export class Place {
  constructor(
    public id: string,
    public title: string,
    public description: string,
    public imageUrl: string,
    public price: number,
    public availableFrom: Date,
    public availableTo: Date,
    public userId: string
  ) {}
}

如您所见,上述updatePlace()方法在调用时可以订阅。

我正在尝试创建一个addMessageToConversation()也可以订阅的方法,就像上面一样。

到目前为止,这是我的代码:

对话服务:

private _conversations = new BehaviorSubject<Conversation[]>([
    new Conversation(
      'conversation1',
      'user3',
      'user1',
      [
        new Message('message1', 'Test message', 'user3', new Date(2018, 0O5, 0O5, 17, 23, 42, 11)),
        new Message('message2', 'Another message', 'user1', new Date(2018, 0O6, 0O5, 17, 23, 42, 11))
      ])
  ]);

  get conversations() {
    return this._conversations.asObservable();
  }

addMessageToConversation(conversationId: string, message: string) {
    this._conversations.getValue().find(conversation => conversation.id === conversationId)
      .messages.push(
        new Message(
          Math.random().toString(),
          message,
          this.authService.userId,
          new Date(Date.now())
        ));
  }

这里是Conversation&Message模型:

export class Conversation {
    constructor(
        public id: string,
        public userId: string,
        public mechanicId: string,
        public messages: Message[]
    ) { }
}

export class Message {
    constructor(
        public id: string,
        public text: string,
        public userId: string,
        public timestamp: Date
    ) { }
}

上面的代码确实更新conversations了,但我无法订阅该方法。有人可以告诉我我需要做哪些改变才能做到这一点吗?

如果我return在其中addMessageToConversation()并尝试使用subscribe它,我会收到以下错误消息:

subscribe类型“数字”上不存在属性

另外,如果我尝试删除_from this._conversations.getValue().find(conversation => ...,则会收到以下错误消息:

“可观察”类型上不存在属性“getValue”

标签: angulartypescriptionic-framework

解决方案


BehaviorSubject您可以从开箱即用中获取对话数组,因为它总是将最后一个值重新发送给新订阅者。然后剩下的就很简单了。

import {switchMap} from 'rxjs/operators';
import {empty} from 'rxjs';

// Obs: notice we're returning a void observable (the empty() at the end),
//    to avoid returning an out-of-date value for the modified conversation.

addMessageToConversation(
  conversationId: string, 
  message: string
): Observable<Conversation> {
  return this._conversations.pipe(
      take(1),
      map((conversations) => conversations.find(c => c.id === conversationId)),
      tap((c: Conversation) => {
        // return case c or messages is falsey
        if(!c?.messages) {return;}

        c.messages.push(
          new Message(
            Math.random().toString(),
            message,
            this.authService.userId,
            new Date(Date.now())
          ));

        // Re-emit conversations array (with new reference)
        this._conversations.next(JSON.parse(JSON.stringify(this._conversations])));
      }),

      // This step is optional, just to avoid returning an out-of-date conversation
      switchMap((_oldConversation: Conversation) => empty())
  );
}

你可以像这样使用它:

addMessageToConversation('conversation1', 'Hey, look! A new message')
  .subscribe();

推荐阅读