【问题标题】:Angular 2 array after subscribe has elements but length is 0订阅后的Angular 2数组有元素但长度为0
【发布时间】:2019-01-31 21:20:21
【问题描述】:

我正在使用 Angular 2,但我注意到了一个意外行为。

我有一个数据源类,它扩展了 DataSource,有两个变量:

private archives = new BehaviorSubject<MyArchive[]>([]);
public archives$: Observable<MyArchive[]> = this.archives.asObservable();
private filteredArchive: MyArchive[];

我在课堂上以这种方式更新档案:

this.archives.next(this.filteredArchive);

在另一个班级之外,我尝试订阅 observable 但它不起作用:

ngAfterViewInit(): void {

    this.dataSource.archives$.subscribe((archive: Array<MyArchive>) => {

        console.log(archive.length);
        console.log(archive);
        console.log(archive.length);
    }
}

在控制台日志中打印:

0
<THE ARCHIVE WITH AN OBJECT INSIDE AS IT SHOULD BE, WITH LENGTH = 1>
0

所以我不能迭代存档变量,因为它的长度是 0。这是怎么回事?

【问题讨论】:

  • 对于第二个 console.log 语句,请尝试:console.log(archive.toString())console.log(JSON.stringify(archive))。你可能会看到数组是空的。
  • 不知道为什么在你已经拥有private archives = new BehaviorSubject&lt;MyArchive[]&gt;([]); 的情况下重复创建public archives$: Observable&lt;MyArchive[]&gt; = this.archives.asObservable();
  • 你确定filteredArchive不为空吗?
  • @ConnorsFan 我试过了,是的,数组是空的。这意味着当我执行 console.log(archive) 时,我正在打印对象的实时值。那是什么错误?我的意思是,当我确定调用了 subscribe 方法时,我也尝试在订阅后更新 observable。
  • @SiddharthAjmera 我这样做是一种模式。 observable 应该只可读,因此我将其声明为 public,而不是 BehaviourSubject 是可写的,因此它是私有的,并且只有它的类才能更新它。我遵循了这个官方 Angular 指南:blog.angular-university.io/angular-material-data-table

标签: javascript angular typescript rxjs observable


【解决方案1】:

这个值在您订阅之前已经发出的问题。想想电视流之类的可观察对象,如果您在节目结束后打开电视(推送数据后订阅),您的数据就像该流上的节目,您将永远看不到节目。如果你希望你的 observable 保持最后一个值,你可以像这样使用 Scan 运算符:

export const reducer = () =>

   scan<MyArchive[]>((archive, update) => {
    //update your Archive or simply overwrite the value
    archive = update

    return archive

    }, []);

export class datasource {

   archives$ : Observable<MyArchive[]>;

   archives : Subject<MyArchive[]> = new Subject([]);

   update(newMyArchive: MyArchive[]) {
     this.archives.next(newMyArchive);
    }

   constructor(public http: HttpClient) {

   this.archives$ = this.archives.pipe(
     reducer(),
   //use the shareReplay so all your subscribers get the same values
     shareReplay(1)
     );
  this.archives$.subscribe();
}

您可以使用数据源类中的更新方法更新 Arcjive,例如:

this.update(filteredArchive)

【讨论】:

  • 我不确定 this.actions 和 this.state 变量是什么意思。
  • 但是我尝试在调用订阅方法后推送数据。问题依然存在
  • 对不起,状态应该是档案$,动作应该是档案
  • @Davide stackblitz.com/edit/array-update 我确实将代码放入了stackblitz,希望这会有所帮助。
【解决方案2】:

我不确定您为什么要重复创建 archives$archives。只需一个 BehaviorSubject 即可。

我认为你应该这样做:

// Create a BehaviorSubject for MyArchive[]
public archives$: BehaviorSubject<MyArchive[]> = new BehaviorSubject<MyArchive[]>([]);
// Create a private filtered Array for MyArchive.
private filteredArchive: MyArchive[];

然后,

this.archives$.next(this.filteredArchive);

【讨论】:

    【解决方案3】:

    当你使用这个语句时:

    console.log(archive);
    

    archive 对象的引用显示在控制台中(请参阅the MDN documentation)。当您在控制台中检查对象(通过单击箭头)时,对象的内容可能与执行 console.log 语句时的内容不同。

    为了查看特定时刻的实际内容是什么,您应该输出对象的字符串表示形式:

    console.log(archive.toString());
    console.log(JSON.stringify(archive));
    

    您可以使用this stackblitz 进行实验以查看各种控制台输出。

    【讨论】:

    • 感谢您的回复。至少现在我知道如何正确检查 subscribe 方法给出的结果是否有效。
    【解决方案4】:

    我解决了这个问题。 我忘记了 this.filteredArchive 是由 HTTP GET 请求更新的。我试图使用 forEach 在 this.filteredArchive 中推送数据,但是在收到所有数据后我忘记调用 then()。 因此,我尝试使用 subscribe 访问尚未准备好的结果。

    感谢大家的回复!

    【讨论】:

      猜你喜欢
      • 2018-12-02
      • 2017-04-18
      • 2019-11-23
      • 1970-01-01
      • 1970-01-01
      • 2020-08-27
      • 1970-01-01
      • 1970-01-01
      • 2018-12-10
      相关资源
      最近更新 更多