Угловой материал MatTableDataSource с Firestore

В настоящее время у меня есть таблица данных, которая заполняется данными из Firestore. Я также использовал MatTableDataSource для реализации разбиения на страницы, сортировки и фильтрации. Все 3 работают нормально, но по какой-то причине мои данные загружаются только один раз при обновлении страницы. Если я перейду на другую страницу и вернусь к таблице, данные исчезнут. Я в недоумении относительно того, почему это происходит. Ниже мой код.

Сервис

import { Injectable } from '@angular/core';
import { AngularFirestore, AngularFirestoreCollection, AngularFirestoreDocument } from 'angularfire2/firestore';
import { Account } from './../models/account.model';
import { Observable } from 'rxjs/Observable';

@Injectable()
export class AccountService {
  accountsCollection: AngularFirestoreCollection<Account>;
  accounts: Observable<Account[]>;

  constructor(public afs: AngularFirestore) {
    this.accountsCollection = afs.collection('accounts');

    this.accounts = this.accountsCollection.snapshotChanges().map(changes => {
      return changes.map(a => {
        const data = a.payload.doc.data() as Account;
        data.id = a.payload.doc.id;
        return data;
      });
    });

  }

  getAccounts() {
    return this.accounts;
  }

}

Компонент

import { Account } from './../../../models/account.model';
import { Component, ViewChild, OnInit } from '@angular/core';
import { MatPaginator, MatSort, MatTableDataSource } from '@angular/material';
import { AccountService } from '../../../services/account.service';
import { AfterViewInit } from '@angular/core/src/metadata/lifecycle_hooks';

@Component({
  selector: 'app-account-table',
  templateUrl: './account-table.component.html',
  styleUrls: ['./account-table.component.css']
})
export class AccountTableComponent implements AfterViewInit {
  dataSource = new MatTableDataSource<Account>();
  displayedColumns = [
    'salesStep',
    'status',
    'idn',
    'hospital',
    'state',
    'regionalManager',
    'accountExecutive',
    'clientLiaison',
    'gpo'
  ];

  @ViewChild(MatPaginator) paginator: MatPaginator;
  @ViewChild(MatSort) sort: MatSort;

  constructor(private accountService: AccountService) {}

  ngAfterViewInit() {
    this.accountService.getAccounts().subscribe(data => {
      this.dataSource.data = data;
      console.log(this.dataSource.data);
    });
    this.dataSource.paginator = this.paginator;
    this.dataSource.sort = this.sort;
  }

  applyFilter(filterValue: string) {
    filterValue = filterValue.trim(); // Remove whitespace
    filterValue = filterValue.toLowerCase(); // Datasource defaults to lowercase matches
    this.dataSource.filter = filterValue;
  }

}

HTML

<div class="example-header">
  <mat-form-field>
    <input matInput #filter (keyup)="applyFilter($event.target.value)" placeholder="Search">
  </mat-form-field>
</div>

<mat-card class="example-container">

  <mat-table #table [dataSource]="dataSource" matSort>

    <!--- Note that these columns can be defined in any order.
          The actual rendered columns are set as a property on the row definition" -->

    <!-- Sales Step Column -->
    <ng-container matColumnDef="salesStep">
      <mat-header-cell *matHeaderCellDef mat-sort-header> Sales Step </mat-header-cell>
      <mat-cell *matCellDef="let row"> {{row.salesStep}} </mat-cell>
    </ng-container>

    <!-- Status Column -->
    <ng-container matColumnDef="status">
      <mat-header-cell *matHeaderCellDef mat-sort-header> Status </mat-header-cell>
      <mat-cell *matCellDef="let row"> {{row.status}} </mat-cell>
    </ng-container>

    <!-- IDN Column -->
    <ng-container matColumnDef="idn">
      <mat-header-cell *matHeaderCellDef mat-sort-header> IDN </mat-header-cell>
      <mat-cell *matCellDef="let row"> {{row.idn}} </mat-cell>
    </ng-container>

    <!-- Hospital Column -->
    <ng-container matColumnDef="hospital">
      <mat-header-cell *matHeaderCellDef mat-sort-header> Hospital </mat-header-cell>
      <mat-cell *matCellDef="let row"> {{row.hospital}} </mat-cell>
    </ng-container>

    <!-- State Column -->
    <ng-container matColumnDef="state">
      <mat-header-cell *matHeaderCellDef mat-sort-header> State </mat-header-cell>
      <mat-cell *matCellDef="let row"> {{row.state}} </mat-cell>
    </ng-container>

    <!-- Regional Manager Column -->
    <ng-container matColumnDef="regionalManager">
      <mat-header-cell *matHeaderCellDef mat-sort-header> RM </mat-header-cell>
      <mat-cell *matCellDef="let row"> {{row.regionalManager}} </mat-cell>
    </ng-container>

    <!-- Account Executive Column -->
    <ng-container matColumnDef="accountExecutive">
      <mat-header-cell *matHeaderCellDef mat-sort-header> AE </mat-header-cell>
      <mat-cell *matCellDef="let row"> {{row.accountExecutive}} </mat-cell>
    </ng-container>

    <!-- Client Liaison Column -->
    <ng-container matColumnDef="clientLiaison">
      <mat-header-cell *matHeaderCellDef mat-sort-header> CL </mat-header-cell>
      <mat-cell *matCellDef="let row"> {{row.clientLiaison}} </mat-cell>
    </ng-container>

    <!-- GPO Column -->
    <ng-container matColumnDef="gpo">
      <mat-header-cell *matHeaderCellDef mat-sort-header> GPO </mat-header-cell>
      <mat-cell *matCellDef="let row"> {{row.gpo}} </mat-cell>
    </ng-container>



    <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
    <mat-row *matRowDef="let row; columns: displayedColumns;">
    </mat-row>
  </mat-table>

  <!-- <div class="example-no-results"
       [style.display]="(accountService.accounts | async)?.length">
    No accounts found matching filter.
  </div> -->

  <mat-paginator #paginator
                [pageSize]="10"
                [pageSizeOptions]="[5, 10, 20]">
  </mat-paginator>
</mat-card>
7 голосов | спросил Kyle 13 12017vEurope/Moscow11bEurope/MoscowMon, 13 Nov 2017 12:40:52 +0300 2017, 12:40:52

3 ответа


0

Это может работать лучше для метода getAccounts:

  getAccountsX() {
    return this.afs.collection<Account[]>('accounts').snapshotChanges().map((accounts) => {
      return accounts.map(a => {
        const data = a.payload.doc.data() as Account;
        const id = a.payload.doc.id;
        return { id, ...data }
      });
    });
  }

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

Таким образом, в компоненте вы можете иметь объект accounts: Observable<Account[]>, который имеет тип Observable<Account[]> и установите его равным getAccountsX (). Тогда в вашей разметке я бы * ng, если вся таблица выглядит так: *ngIf="(accounts | async) as acts". Тогда источником данных будет фактически acts. Я еще никогда не использовал DataTable, но это всего лишь подход, который я бы использовал, чтобы попытаться сохранить подписку на данные активной. Если вы хотите, я могу отредактировать ваш вопрос с этим.

РЕДАКТИРОВАТЬ:

Вот объяснение двух отдельных способов обработки этой подписки:

Итак, здесь, в моем компоненте, я получаю Observable, а затем подписываюсь на него, чтобы сохранить массив любой модели данных, которую вы выбираете:

  accountsObservable: Observable<Account[]>;
  accountsArray: Account[];

  constructor(
    private ds: DatabaseService
  ) {}

  ngOnInit() {
    this.accountsObservable = this.ds.getAccountsX();

    this.accountsObservable.subscribe(accounts => {
      this.accountsArray = accounts;
    });
  }

Тогда здесь, в моей разметке, вы можете создать подписку, используя * ngFor и канал ASYNC, или просто перебрать массив после того, как он будет подтвержден подпиской:

<!-- This div below is subscribing to the Observable in markup using the 'async' pipe to make sure it waits for data -->
<div id="markup-subscription" *ngFor="let act of (accountsObservable | async)">
  <p>{{ act?.id }}</p>
</div>

<!-- This div below is looping through the array that was pulled from the subscription of the Observable -->
<div id="component-subscription" *ngFor="let act of accountsArray">
  <p>{{ act?.id }}</p>
</div>

Одной из причин ожидания подписки в коде компонента является необходимость манипулирования данными перед их выпуском в пользовательский интерфейс. Я полагаю, что если вы используете второй вариант подписки в коде компонента вместо разметки, вы должны убедиться, что * ngFor не пытается перебрать пустой массив, так как подписка может не задавать массив перед содержимым хочет загрузить на DOM. Поэтому я бы *ngIf accountArray, чтобы убедиться, что он установлен первым, вот так:

<div id="component-subscription" *ngIf="accountsArray" *ngFor="let act of accountsArray">

Конечно, это не использует MatDataTable, так как я хотел показать пример работы этих подписок, и цель состоит в том, чтобы использовать одну подписку

Что касается отказа от подписки, причина, по которой этот вариант недоступен, заключается в том, что необходимо установить подписку Observable для такой переменной:

    const subscription = this.accountsObservable.subscribe(accounts => {
      this.accountsArray = accounts;
    });

    subscription.unsubscribe();

Надеюсь, это поможет объяснить состояние подписки, когда вы просматриваете коллекцию или документ в пользовательском интерфейсе.

ответил Nicholas Pesa 14 22017vEurope/Moscow11bEurope/MoscowTue, 14 Nov 2017 01:24:46 +0300 2017, 01:24:46
0

попробуй самый простой брат. Вот.

constructor(public afs: AngularFirestore) {
    this.accountsCollection = afs.collection('accounts');
}

getAccounts() {
    return this.accounts = this.accountsCollection.snapshotChanges().map(changes => {
      return changes.map(a => {
        const data = a.payload.doc.data() as Account;
        data.id = a.payload.doc.id;
        return data;
      });
    });
  }

надеюсь, это поможет.

ответил Joshua Fabillar 26 72017vEurope/Moscow11bEurope/MoscowSun, 26 Nov 2017 11:01:35 +0300 2017, 11:01:35
0

Сохраните подписку, которую вы получаете от getAccounts (). subscribe, и вызовите unsubscribe () для нее в ngOnDestroy. Я не тестировал, но это может помочь, если af2 кэширует подписки, поскольку наблюдаемое никогда не завершается само по себе. Необходимая и хорошая практика для предотвращения утечек памяти в любом случае.

ответил funkizer 13 12017vEurope/Moscow11bEurope/MoscowMon, 13 Nov 2017 23:58:42 +0300 2017, 23:58:42

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132