網站搜尋

angular - 當推入新值時,如何配置一個 Observable 以返回所有先前的值作為陣列?


這方面有點困難。我剛開始使用 RxJs Observables,所以需要一些指導。

我正在嘗試建立一個 Observable 日誌流,它做兩件事。

  1. 每當有新的行/值被寫入日誌文件時,將該新值推送到流中。
  2. 開始時使用日誌檔案中的值進行預填充。

我已經完成了上述兩個標準。現在的挑戰是如何在 *ngFor 中使用它。

*ngFor 需要從 Observable 中取得一個陣列,以便它可以進行比較來新增/移除(我的最佳猜測)。但是我的 Observable 只返回最後一個被推送的項目的陣列。

//logviewer.page.ts constructor()
this.logs = Subject.create();
this.logs$ = this.logs.asObservable()
            .startWith("logs\\error.log")
            .flatMap((fileName: string) => {
                //start by reading the existing log files as a string
                return this.$localStorageService.readAsStringAsync(fileName);
            })
            .map((contents: string) => {
                //this part splits up the log file line-by-line into an log entry
                let logs = contents.split(/\r\n|\r|\n/).filter(n => n.length > 0);
                logs.forEach((s, ix, parent) => {
                    let x = JSON.parse(s);
                    parent[ix] = { timestamp: new Date(parseFloat(x[0])), message: x[1] };
                })
                return logs; //an array of objects { timestamp, message }
            })
            //merge the existing application log stream
            //throughout the application we log errors, info, etc
            //if a new entry is made it will appear here
            .merge(this.$loggerService.applicationLog$.map((x) => {                    
                //return an array with one object { timestamp, message }
                return [{ timestamp: new Date(parseFloat(x[0])), message: x[1] }];
            }))

現在我的模板目前非常簡單。

//logviewer.template.ts
<div *ngFor="let entry of logs$ | async">
    {{entry|json}}
</div>

現在要測試它,我有一個按鈕可以添加一個條目

//logviewer.page.ts
addEntry() {
    this.$loggerService.error("this is a test");
}

//LoggerService.service.ts
private applicationLog: ReplaySubject<any[]>;
get applicationLog$(): Observable<any[]> {
    return this.applicationLog.asObservable();
}

error(...args) {
    let data = [Date.now().toString()].concat(args.map<string>((n, ix) => { return toString(n); }));

    // ... write to file

    // fire the subject
    this.applicationLog.next(data);
}

現在當我點擊 addEntry 時,整個流程都能正常運作,值也會正確地通過可觀察序列傳遞。但我的 *ngFor 只會更新單一值。它不會保留之前所有日誌條目的歷史。只會顯示最後返回的陣列,這是合理的。

我如何讓我的可觀察序列總是返回所有值的陣列。我可以讓它一次返回一個條目,但我需要完整的歷史紀錄以滿足 *ngFor

我對 *ngFor 和 async 管道缺乏了解。我以為它會訂閱 observable,並自動將任何新的條目添加到 ngFor,但事實並非如此。

答案#1

嘗試使用掃描操作符:

this.logs$ = this.logs.asObservable()
        ...
        .merge(this.$loggerService.applicationLog$.map((x) => {                    
            //return an array with one object { timestamp, message }
            return [{ timestamp: new Date(parseFloat(x[0])), message: x[1] }];
        }))
        .scan((acc, x) => {
            acc.push(...x);
            return acc;
        }, []);