In need of assigning the content of a variable filled with an array from a Firebase subscription, I encountered an issue where I couldn't access the value outside of the subscription in my component class. While I can use the created variable inside the .html file, it's crucial for me to have access to it within the component class as well. (Please note: these files were generated using the Angular Schematics "ng generate @angular/material:table")
//table-datasource.ts
import { DataSource } from '@angular/cdk/collections';
import { MatPaginator } from '@angular/material/paginator';
import { MatSort } from '@angular/material/sort';
import { map } from 'rxjs/operators';
import { Observable, of as observableOf, merge } from 'rxjs';
import { AuthService } from "../../services/auth.service";
// Define data model type
export interface TableItem {
email: string;
displayName: string;
photoURL: string;
emailVerified: boolean;
}
const EXAMPLE_DATA: TableItem[] = [ // Hardcoded data is visible but needs to be dynamic
{...},
];
/**
* Data source for the Table view. This class should
* encapsulate all logic for fetching and manipulating the displayed data
* (including sorting, pagination, and filtering).
*/
export class TableDataSource extends DataSource<TableItem> {
//data: TableItem[] = EXAMPLE_DATA; //works with hardcoded data
data: TableItem[] = []; // Need data to be the result of the subscription
constructor(public authService: AuthService) {
super();
this.getUsersData();
this.printUserData(); // Works only with hardcoded EXAMPLE_DATA, else shows empty Array
}
printUserData() {
console.log("this.data", this.data);
}
getUsersData() {
this.authService
.getCollection("users")
.subscribe((res: any[]) => {
this.data = res; // Assigning values from subscription to this.data
console.log("table-datasource", this.data); // Works here only
})
}
...
}
//table.component.ts
import { AfterViewInit, Component, ViewChild } from '@angular/core';
import { MatPaginator } from '@angular/material/paginator';
import { MatSort } from '@angular/material/sort';
import { MatTable } from '@angular/material/table';
import { AuthService } from "../../services/auth.service";
import { TableDataSource, TableItem } from './table-datasource';
@Component({
selector: 'app-table',
templateUrl: './table.component.html',
styleUrls: ['./table.component.scss']
})
export class TableComponent implements AfterViewInit {
@ViewChild(MatPaginator) paginator!: MatPaginator;
@ViewChild(MatSort) sort!: MatSort;
@ViewChild(MatTable) table!: MatTable<TableItem>;
dataSource: TableDataSource;
/** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
displayedColumns = ['id', 'name'];
constructor(public authService: AuthService) {
this.dataSource = new TableDataSource(authService);
}
ngAfterViewInit(): void {
this.dataSource.sort = this.sort;
this.dataSource.paginator = this.paginator;
this.table.dataSource = this.dataSource;
}
}
//table.component.html
<div class="mat-elevation-z8">
<table mat-table class="full-width-table" matSort aria-label="Elements">
<!-- Id Column -->
<ng-container matColumnDef="id">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Id</th>
<td mat-cell *matCellDef="let row ">{{row.uid}}</td>
</ng-container>
<!-- Name Column -->
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Name</th>
<td mat-cell *matCellDef="let row">{{row.email}}</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
<mat-paginator #paginator
[length]="dataSource?.data?.length"
[pageIndex]="0"
[pageSize]="10"
[pageSizeOptions]="[5, 10, 20]"
aria-label="Select page">
</mat-paginator>
</div>