2016-12-20 6 views
2

Нелегко с этим. Я новичок в работе с RxJs Observables, поэтому мне нужно руководствоваться.Настроить наблюдаемое, чтобы вернуть все предыдущие значения в виде массива при нажатии нового значения?

Я пытаюсь создать Наблюдаемый поток ведения журнала, который выполняет две вещи.

  1. Всякий раз, когда новая строка/значение записывается в файл журнала, нажмите это новое значение в поток.
  2. Начните предварительно заполненные значения из файла журнала.

Я выполнил оба вышеуказанных критерия. Теперь проблема заключается в использовании * ngFor.

* ngFor требует массив из наблюдаемого, поэтому он может делать сравнение с добавлением/удалением (мое лучшее предположение). Но мой наблюдаемый возвращает только массив последнего элемента, проталкиваемого.

//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, сантехника все работает, а значение увольняют по наблюдаемой последовательности правильно. Но my * ngFor только обновления с одним значением. Он не сохраняет историю всех предыдущих записей журнала. Только последний массив вернулся, что имеет смысл.

Как заставить мою наблюдаемую последовательность всегда возвращать массив всех значений. Я могу заставить его возвращать одну запись за раз, но мне нужна полная история, чтобы удовлетворить * ngFor

У меня было отсутствие понимания * ngFor и асинхронной трубы. Я думал, что он подписывается на наблюдаемый и автоматически добавляет новые записи в ngFor, но это не так.

ответ

1

Попробуйте использовать scan оператор:

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; 
     }, []); 
+0

Вау, спасибо так много. – Matt