Unable to bind data to Angular Material Data Table - json

Issue
I'm having an issue binding JSON data to an Angular Material data table.
Background
I'm developing a small application which is designed to provide users with film information. An API call is initiated following the user triggering a search. This should then populate the data table with the response data.
Whilst I can successfully make the API call, no data is passed into the data table:
API Response in Dev Tools
Furthermore, no errors are shown in the console and I can populate the table with test data.
Here is the code:
api-calls.service.ts
import { Injectable } from '#angular/core';
import { HttpClient, HttpResponse } from '#angular/common/http';
import { Observable, of } from 'rxjs';
#Injectable()
export class ApiService {
constructor(private http:HttpClient){}
public getFilms(searchTerm): Observable<any> {
const apiUrl = 'http://www.omdbapi.com/?apikey=b1464edd&s=';
const fullLink = apiUrl + searchTerm
return this.http.get(fullLink)
}}
app.component.ts
import { Component, OnInit } from '#angular/core';
import { Films } from './models/films.model';
import { ApiService } from './services/api-calls.service';
import { MatTableDataSource } from '#angular/material';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit{
constructor(private apiService:ApiService) {}
displayedColumns: string[] = ['title', 'year', 'imdbID', 'poster', 'type']
dataSource: MatTableDataSource<any[]>;
searchTerm = '';
handleSearch(event) {
if(event.action === 'SEARCH') {
this.searchTerm = event.query
this.apiService.getFilms(this.searchTerm).subscribe(
data => this.dataSource = new MatTableDataSource<Films[]>(data)
)}
}
ngOnInit() {
}
}
app.component.html (the search function outlined in the container class is handled in another component)
<div class = "container">
<mat-card>
<h2>Lightweight IMDb Search Engine</h2>
<app-search (searchEvent)="handleSearch($event)"></app-search>
</mat-card>
<div>
<mat-table [dataSource] = "dataSource">
<ng-container matColumnDef="title">
<mat-header-cell *matHeaderCellDef> Title </mat-header-cell>
<mat-cell *matCellDef="let films"> {{ films.title }}</mat-cell>
</ng-container>
<ng-container matColumnDef="year">
<mat-header-cell *matHeaderCellDef> Year </mat-header-cell>
<mat-cell *matCellDef="let films"> {{ films.year }}</mat-cell>
</ng-container>
<ng-container matColumnDef="imdbID">
<mat-header-cell *matHeaderCellDef> imdbID </mat-header-cell>
<mat-cell *matCellDef="let films"> {{ films.imdbID }}</mat-cell>
</ng-container>
<ng-container matColumnDef="poster">
<mat-header-cell *matHeaderCellDef> Poster </mat-header-cell>
<mat-cell *matCellDef="let films"> {{ films.poster }}</mat-cell>
</ng-container>
<ng-container matColumnDef="type">
<mat-header-cell *matHeaderCellDef> Type </mat-header-cell>
<mat-cell *matCellDef="let films"> {{ films.type }}</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
</mat-table>
</div>
</div>
film.model.ts
export interface Films {
title: string;
year: string;
imdbID: string;
poster: string;
type: string;
}

The JSON returned by the API has the following shape
{
"Search": [
{"Title":"Hello, My Name Is Doris","Year":"2015","imdbID":"tt3766394","Type":"movie","Poster":"https://m.media-amazon.com/images/M/MV5BMTg0NTM3MTI1MF5BMl5BanBnXkFtZTgwMTAzNTAzNzE#._V1_SX300.jpg"},
// etc.
]
}
Therefore you need to make some adjustments.
Firstly, you need to project the response, extracting the Search property which contains the array of films. This should be done in your service (note the improved use of types)
api-calls.service.ts
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import Film from './models/film.model';
#Injectable()
export class ApiService {
constructor(private http:HttpClient){}
getFilms(searchTerm): Observable<Film[]> {
const apiUrl = 'http://www.omdbapi.com/?apikey=b1464edd&s=';
const fullLink = apiUrl + searchTerm;
type Response = { Search: Film[] };
return this.http.get<Response> (fullLink)
.pipe(map(response => response.Search));
}
}
Then we need to declare the property names in the model interface to correctly describe the shape of the films in the response
film.model.ts
export default interface Film {
Title: string;
Year: string;
imdbID: string;
Poster: string;
Type: string;
}
Now let's adjust the component itself to improve the types a bit
app.component.ts
import { Component } from '#angular/core';
import { ApiService } from './services/api-calls.service';
import { MatTableDataSource } from '#angular/material';
import Film from './models/film.model';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
constructor(private apiService:ApiService) {}
displayedColumns: (keyof Film)[] = ['Title', 'Year', 'imdbID', 'Poster', 'Type'];
dataSource?: MatTableDataSource<Film[]>;
searchTerm = '';
handleSearch({ action, query }) {
if (action === 'SEARCH' && query) {
this.searchTerm = query;
this.apiService.getFilms(this.searchTerm)
.subscribe(films => this.dataSource = new MatTableDataSource(films));
}
}
}
Note how the use of types has been improved to constrain the names of the columns, that they stay in sync between the component and the service. Also note that redundant type information has been improved to take advantage of the type inference flowing from the improved type signature of the service method.

Related

Angular Material Table is not showing data. How do I achieve this? I get 'undefined' w/ console.log(data.items). I receive data w/ console.log(data)

I am receiving an object when I enter console.log(data) but undefined
when I enter console.log(items). I am trying to enter the data in the
interface then display the entries in the table.
component.ts
import {HttpClient} from '#angular/common/http';
import {Component, ViewChild, AfterViewInit} from '#angular/core';
import {MatPaginator} from '#angular/material/paginator';
import {MatSort, SortDirection} from '#angular/material/sort';
import {merge, Observable, of as observableOf} from 'rxjs';
import {catchError, map, startWith, switchMap} from 'rxjs/operators';
import { MatTable } from '#angular/material/table';
import { AssetTableDataSource, AssetTableItem } from './asset-table-datasource';
import { AssetTableModule } from './asset-table.module';
#Component({
selector: 'app-asset-table',
templateUrl: './asset-table.component.html',
styleUrls: ['./asset-table.component.scss']
})
export class AssetTableComponent implements AfterViewInit {
displayedColumns: string[] = ['client_id','periodenddate', 'dataitemname', 'dataitemvalue'];
assetDatabase!: AssetRecHttpDatabase | null;
data: ClientidAssetData[] = [];
items: any[] =[];
resultsLength = 0;
isLoadingResults = true;
isRateLimitReached = false;
#ViewChild(MatPaginator)
paginator!: MatPaginator;
#ViewChild(MatSort)
sort!: MatSort;
constructor(private _httpClient: HttpClient) {}
ngAfterViewInit() {
this.assetDatabase = new AssetRecHttpDatabase(this._httpClient);
// If the user changes the sort order, reset back to the first page.
this.sort.sortChange.subscribe(() => (this.paginator.pageIndex = 0));
merge(this.sort.sortChange, this.paginator.page)
.pipe(
startWith({}),
switchMap(() => {
this.isLoadingResults = true;
return this.assetDatabase!.getAssetresults(
this.sort.active,
this.sort.direction,
this.paginator.pageIndex,
).pipe(catchError(() => observableOf(null)));
}),
map(data => {
// Flip flag to show that loading has finished.
this.isLoadingResults = false;
this.isRateLimitReached = data === null;
if (data === null) {
return [];
}
// Only refresh the result length if there is new data. In case of rate
// limit errors, we do not want to reset the paginator to zero, as that
// would prevent users from re-triggering requests.
this.resultsLength = data.total_count;
console.log(data);
console.log(data.items);
return data;
}),
)
.subscribe(data => (data = data));
}
}
export interface GetAssetApi {
items: ClientidAssetData[];
total_count: number;
}
export interface ClientidAssetData{
Clientid: string;
PeriodEndDate: string;
DataItemName: string;
DataItemValue: string;
}
/** The database that the data source uses to retrieve data for the table. */
export class AssetRecHttpDatabase {
constructor(private _httpClient: HttpClient) {}
getAssetresults(sort: string, order: SortDirection, page: number): Observable<GetAssetApi> {
const href = 'http://localhost:3000/institutionasset/assetresults/';
const requestUrl = `${href}?fldinstid=3&flddataitem=Data Item:angular/material&sort=${sort}&order=${order}&page=${
page + 1
}`;
return this._httpClient.get<GetAssetApi>(requestUrl);
}
}
html
<div class="example-container mat-elevation-z8">
<div class="example-loading-shade"
*ngIf="isLoadingResults || isRateLimitReached">
<mat-spinner *ngIf="isLoadingResults"></mat-spinner>
<div class="example-rate-limit-reached" *ngIf="isRateLimitReached">
The rate limit has been reached. It will be reset in one minute.
</div>
</div>
<div class="example-table-container">
<table mat-table [dataSource]="data" class="example-table"
matSort matSortActive="client_id" matSortDisableClear matSortDirection="desc">
<!-- Period End Date Column -->
<ng-container matColumnDef="periodenddate">
<th mat-header-cell *matHeaderCellDef>Period End Date</th>
<td mat-cell *matCellDef="let row">{{row.PeriodEndDate | date}}</td>
</ng-container>
<!-- Data Item Value Column -->
<ng-container matColumnDef="dataitemvalue">
<th mat-header-cell *matHeaderCellDef>Data Item Value</th>
<td mat-cell *matCellDef="let row">{{row.DataItemValue}}</td>
</ng-container>
<!-- Data Item Column -->
<ng-container matColumnDef="dataitemname">
<th mat-header-cell *matHeaderCellDef>Data Item Name</th>
<td mat-cell *matCellDef="let row">{{row.DataItemName}}</td>
</ng-container>
<!-- Client id Column -->
<ng-container matColumnDef="client_id">
<th mat-header-cell *matHeaderCellDef mat-sort-header disableClear>
Client id
</th>
<td mat-cell *matCellDef="let row">{{row.Clientid}}</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
</div>
<mat-paginator [length]="resultsLength" [pageSize]="30" aria-label="Select page of Asset"></mat-paginator>
</div>
I get my data from the api and this works.. I get four items in the
array and in console it says object and within the dropdown of objects
in the console it says the field and it's values.
export class InstitutionassetService {
constructor(#InjectDataSource() private dataSource: DataSource) {}
async find(fldinstid: string, flddataitem: string) {
const instassets = await this.dataSource.query(
"dbo.WebGetClientCallSheet #Clientid='" +
fldinstid +
"'," +
"#DataItemName='" +
flddataitem +
"'",
);
return instassets;
}
}
import { Controller, Get, Query } from '#nestjs/common';
import { InstitutionassetService } from './institutionasset.service';
controller from nestjs
#Controller('institutionasset')
export class InstitutionassetController {
constructor(private institutionassetService: InstitutionassetService) {}
#Get('/assetresults')
async find(
#Query('fldinstid') fldinstid: string,
#Query('flddataitem') flddataitem: string,
) {
console.log(fldinstid + ' ' + flddataitem);
return await this.institutionassetService.find(fldinstid, flddataitem);
}
}

Pagination, Sort, Filter fails in Angular Material Table for big JSON file

I am trying to send JSON with more than 50K entries via an express server to Angular. In the deployment I can see all the entries in the format of Angular Material table. However the pagination, sort and filter feature of the tables are not working at all.
Here is the ts file
import { MatPaginator } from '#angular/material/paginator';
import { MatSort } from '#angular/material/sort';
import { Component, ViewChild } from '#angular/core';
import { MatTable, MatTableDataSource } from '#angular/material/table';
import { ViewDataService } from './modules/view-data.service';
import { ThrowStmt } from '#angular/compiler';
import { DataSource } from '#angular/cdk/collections';
import { BehaviorSubject } from 'rxjs';
export interface DataEntries {
key: string;
value: String;
}
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
title = 'TD';
dataSource: any; //MatTableDataSource<Student>;
displayedColumns: string[] = ['key', 'value'];
//columns: string[] = ['id','name','email','gender']
public orderByKey(a: any, b: any) {
return a.key;
}
private paginator: MatPaginator;
private sort: MatSort;
#ViewChild(MatSort) set matSort(ms: MatSort) {
this.sort = ms;
this.setDataSourceAttributes();
}
#ViewChild(MatPaginator) set matPaginator(mp: MatPaginator) {
this.paginator = mp;
this.setDataSourceAttributes();
}
setDataSourceAttributes() {
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
}
//#ViewChild(MatSort, { static: false }) sort: MatSort;
//#ViewChild(MatPaginator, { static: false }) paginator: MatPaginator;
dataEntries: DataEntries[] = []
constructor(private viewdata: ViewDataService) {
}
ngOnInit(): void {
this.viewdata.getData().then(response => {
this.dataEntries = response.data;
console.log(this.dataEntries);
this.dataSource = new MatTableDataSource(this.dataEntries);
console.log(this.dataSource);
this.dataSource = this.dataSource.filteredData;
this.dataSource.sort = this.sort;
setTimeout(() => this.dataSource.paginator = this.paginator);
})
//Called after the constructor, initializing input properties, and the first call to ngOnChanges.
//Add 'implements OnInit' to the class.
}
applyFilter(event: Event) {
const filterValue = (event.target as HTMLInputElement).value;
this.dataSource.filter = filterValue.trim().toLowerCase();
}
}
Here is the template
<h1>Placeholder Table</h1>
<mat-form-field>
<mat-label>Filter</mat-label>
<input matInput formControlName="formControlName"
type="text"
placeholder="Search" (keyup)="applyFilter($event)">
</mat-form-field>
<mat-table [dataSource]="dataSource | keyvalue:orderByKey" class="mat-elevation-z4" matSort>
<ng-container matColumnDef="key">
<mat-header-cell *matHeaderCellDef mat-sort-header> Key
</mat-header-cell>
<mat-cell *matCellDef="let element"> {{element.key}} </mat-cell>
</ng-container>
<ng-container matColumnDef="value">
<mat-header-cell *matHeaderCellDef mat-sort-header> value</mat-header-cell>
<mat-cell *matCellDef="let element"> {{element.value}} </mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
</mat-table>
<mat-paginator [length]="dataEntries.length"
[pageSize]="100"
[pageSizeOptions]="[2, 5, 25, 100]">
</mat-paginator>
<router-outlet></router-outlet>
Here is the express file:
var express = require('express');
var router = express.Router();
const jason = require('../public/jsons/en-GB.json');
router.get('/', function(req, res, next) {
res.json(JSON.parse(JSON.stringify(jason)));
console.log('Test');
});
module.exports = router;
Please let me know why they are failing
In your app.component.ts
async ngOnInit(): void {
const response = await this.viewdata.getData();
this.dataEntries = response.data;
console.log(this.dataEntries);
this.dataSource = new MatTableDataSource(this.dataEntries);
console.log(this.dataSource);
this.dataSource = await this.dataSource.filteredData;
this.dataSource.sort = this.sort;
this.dataSource.paginator = this.paginator
}
}
In your http-service
getData(){
return http.get('/').toPromise();
}

Merge two Observables and pass into dataSource as a single Observable for Angular material table

I am fairly new to Web development and am stuck on this problem from past some days, Would appreciate a heck lot if the community could help me out here
I want to merge two observables coming out of firebase database, I want to join them concurrently i.e
3 rows of the first observable to be mapped with the three rows from the other observable. I want to use this observable into my dataSource for Angular Mat Table. and extract fields from both the observable here
This is the Component.ts
import { Component, OnInit } from '#angular/core';
import { ProductService } from 'src/app/product.service';
import { Observable, observable } from 'rxjs';
import "rxjs/add/observable/zip";
import "rxjs/add/observable/forkJoin";
#Component({
selector: 'app-admin-products',
templateUrl: './admin-products.component.html',
styleUrls: ['./admin-products.component.css']
})
export class AdminProductsComponent implements OnInit {
products$:Observable<any[]>
productsKey$:Observable<any[]>
finalProduct$
list:[]
constructor(private productService:ProductService) {
this.products$ = this.productService.getAll().valueChanges();
this.productsKey$ = this.productService.getAll().snapshotChanges();
//this.finalProduct$ = (this.products$).pipe(merge(this.productsKey$));
}
displayedColumns = ['title','price','edit'];
// dataSource = this.products$
ngOnInit(): void {
}
}
This is the service.ts
import { Injectable } from '#angular/core';
import { AngularFireDatabase } from 'angularfire2/database';
#Injectable({
providedIn: 'root'
})
export class ProductService {
constructor(private db:AngularFireDatabase) { }
create(product){
console.log(product)
return this.db.list('/products').push(product);
}
getAll(){
return this.db.list('/products')
}
}
this is the final HTML markup
<p style="padding: 50px;">
<button mat-flat-button color="primary" routerLink="/admin/products/new" > Add New Product</button>
</p>
<mat-table [dataSource]="finalProduct$ | async" class="mat-elevation-z8">
<!-- Position Column -->
<ng-container matColumnDef="title">
<mat-header-cell *matHeaderCellDef> Title </mat-header-cell>
<mat-cell *matCellDef="let element"> {{ element.title }} </mat-cell>
</ng-container>
<!-- Name Column -->
<ng-container matColumnDef="price">
<mat-header-cell *matHeaderCellDef> Price </mat-header-cell>
<mat-cell *matCellDef="let element"> {{element.price}}</mat-cell>
</ng-container>
<ng-container matColumnDef="edit">
<mat-header-cell *matHeaderCellDef> </mat-header-cell>
<mat-cell *matCellDef="let element"> {{element | json}} </mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
</mat-table>
The first Observable products$ has data in this format
{category: "bread", imageUrl: "https://pixabay.com/photos/bread-food-isolated-croissant-loaf-4592483/", price: 50, title: "Freshly Baked Bread"}
the Second observable productsKey$ has data in this format
{payload: DataSnapshot, type: "value", prevKey: null, key: "-M9HwZl_WYfgTchxanrb"}
I wish to extract the Price, title and key value from these observables and display them in a table.
I would suggest using zip which does exactly what you want, i.e merge 2 observables.
ngOnInit(): void {
zip(this.products$, this.productsKey$).pipe(
map(reponse => { return {...reponse[0], ...response[1]}})
).subscribe(
reponse => {
this.dataSource = reponse;
});
You can also use combineLatest as Michael suggested with slight modifications. Change map(reponse => [...reponse[0], ...response[1]]) to map(reponse => { return {...reponse[0], ...response[1]}})
If the observables are independent of each other you could use RxJS combineLatest() function to combine multiple observables.
displayedColumns = ['title', 'price', 'edit'];
constructor(private productService: ProductService) {
this.products$ = this.productService.getAll().valueChanges();
this.productsKey$ = this.productService.getAll().snapshotChanges();
}
ngOnInit(): void {
combineLatest(this.products$, this.productsKey$).pipe(
take(1), // <-- remove it if the data stream needs to persist
map(reponse => [...reponse[0], ...response[1]])
).subscribe(
reponse => {
this.dataSource = reponse;
}
);
}

Angular dynamically populate table

I'm trying to dynamically populate a table using the following code:
teams.component.ts
import { Component, OnInit } from '#angular/core';
import { first } from 'rxjs/operators';
import { TeamService } from 'src/app/services/team.service';
export interface PeriodicElement {
name: string;
position: number;
weight: number;
symbol: string;
}
#Component({
selector: 'app-teams',
templateUrl: './teams.component.html',
styleUrls: ['./teams.component.scss']
})
export class TeamsComponent implements OnInit {
public teams : any;
tableCols = ['id', 'name'];
constructor(private teamService : TeamService) { }
ngOnInit(): void {
this.teamService.getTeams().pipe(first()).subscribe(
data => {
this.teams = data.results
},
error => {
console.log(error.error)
}
)
}
}
teams.component.html
<app-table [tableData]="teams" [tableColumns]="tableCols"></app-table>
table.component.ts
import { Component, OnInit, Input, ViewChild } from '#angular/core';
import { MatSort } from '#angular/material/sort';
import { MatPaginator } from '#angular/material/paginator';
import { MatTableDataSource } from '#angular/material/table';
#Component({
selector: 'app-table',
templateUrl: './table.component.html',
styleUrls: ['./table.component.scss']
})
export class TableComponent implements OnInit {
tableDataSrc: any;
// tslint:disable-next-line: no-input-rename
#Input('tableColumns') tableCols: string[];
#Input() tableData: {}[] = [];
#ViewChild(MatSort, { static: true }) sort: MatSort;
#ViewChild(MatPaginator, { static: true }) paginator: MatPaginator;
constructor() { }
ngOnInit() {
this.tableDataSrc = new MatTableDataSource(this.tableData);
this.tableDataSrc.sort = this.sort;
this.tableDataSrc.paginator = this.paginator;
}
}
table.component.html
<div class="mat-elevation-z8">
<table mat-table [dataSource]="tableDataSrc" matSort class="mat-elevation-z8">
<ng-container *ngFor="let col of tableCols">
<ng-container matColumnDef="{{ col }}">
<th mat-header-cell *matHeaderCellDef mat-sort-header>
{{ col | titlecase }}
</th>
<td mat-cell *matCellDef="let profile">{{ profile }}</td>
</ng-container>
</ng-container>
<tr mat-header-row *matHeaderRowDef="tableCols"></tr>
<tr mat-row *matRowDef="let row; columns: tableCols"></tr>
</table>
<mat-paginator [pageSizeOptions]="[1, 2, 3, 5, 10, 20]" showFirstLastButtons></mat-paginator>
</div>
A 'team' object looks like the following:
{'id': 9, 'name': 'FC Barcelona'} and the teams variable is a list of these objects.
When I navigate to the teams page the table is rendered and stays empty, what am I doing wrong here?
try replacing this part in table.component.ts
ngOnInit() {
this.tableDataSrc = new MatTableDataSource(this.tableData);
this.tableDataSrc.sort = this.sort;
this.tableDataSrc.paginator = this.paginator;
}
with this
ngOnChanges(changes: SimpleChanges) {
if(changes.tableData.currentValue) {
this.tableDataSrc = new MatTableDataSource(this.tableData);
this.tableDataSrc.sort = this.sort;
this.tableDataSrc.paginator = this.paginator;
}
}
The problem is teams field in TeamsComponent gets initialized after (due to async operation) TableComponents OnInit phase. If you change ngOnInit with ngOnChanges whenever teams field changes TableComponent becomes aware of it.
Further reading: https://angular.io/guide/lifecycle-hooks#using-change-detection-hooks

I'm getting a "this.container is undefined" error when using mat-paginator

I have a mat-table that has a list of users called from a database using a spring REST API which works perfectly but when I wanted to add a paginator to help go through the whole list of users I started getting a "this.container is undefined" error when trying to click on the paginator.
Also, for some reason It showing "Items per page: 5" only even though I have almost 27 users.
Here's my html code:
<mat-form-field>
<input matInput (keyup)="applyFilter($event.target.value)" placeholder="Filter" style="width: 500px !important">
</mat-form-field>
<mat-table class="lessons-table mat-elevation-z8" [dataSource]="dataSource">
<ng-container matColumnDef="id" class=".mat-column-id">
<mat-header-cell *matHeaderCellDef>#</mat-header-cell>
<mat-cell *matCellDef="let user">{{user.id}}</mat-cell>
</ng-container>
<ng-container matColumnDef="username" class=".mat-column-username">
<mat-header-cell *matHeaderCellDef>Username</mat-header-cell>
<mat-cell class="description-cell" *matCellDef="let user">{{user.username}}</mat-cell>
</ng-container>
<ng-container matColumnDef="email" class=".mat-column-email">
<mat-header-cell *matHeaderCellDef>Email</mat-header-cell>
<mat-cell class="duration-cell" *matCellDef="let user">{{user.email}}</mat-cell>
</ng-container>
<ng-container matColumnDef="firstname" class=".mat-column-name">
<mat-header-cell *matHeaderCellDef>firstname</mat-header-cell>
<mat-cell class="duration-cell" *matCellDef="let user">{{user.firstName}}</mat-cell>
</ng-container>
<ng-container matColumnDef="lastname"class=".mat-column-name">
<mat-header-cell *matHeaderCellDef>Last Name</mat-header-cell>
<mat-cell class="duration-cell" *matCellDef="let user">{{user.lastName}}</mat-cell>
</ng-container>
<ng-container matColumnDef="enabled" class=".mat-column-enabled">
<mat-header-cell *matHeaderCellDef>Enabled</mat-header-cell>
<mat-cell class="duration-cell" *matCellDef="let user">{{user.enabled}}</mat-cell>
</ng-container>
<ng-container matColumnDef="registeredDate" class=".mat-column-date">
<mat-header-cell *matHeaderCellDef>Registered Date</mat-header-cell>
<mat-cell class="duration-cell" *matCellDef="let user">{{user.registeredDate | date: shortDate}}</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></mat-header-row>
<mat-row class="mat-row" *matRowDef="let row; columns: displayedColumns" (click)="onRowClicked(row)"></mat-row>
</mat-table>
<mat-paginator [pageSizeOptions]="[5, 10, 25, 100]"></mat-paginator>
and the ts file:
import { Component, OnInit, ViewChild } from '#angular/core';
import { ViewEncapsulation } from '#angular/core';
import { HttpClient, HttpHeaders } from '#angular/common/http';
import { UserService } from '../user.service';
import { MatDialog, MatDialogConfig, MatTableDataSource, MatPaginator, MatSort } from '#angular/material';
import { NewDialogComponent } from '../new-dialog/new-dialog.component';
import { DomSanitizer } from '#angular/platform-browser';
import { map } from 'rxjs-compat/operator/map';
import { Observable, Observer } from 'rxjs';
#Component({
selector: 'app-dashboard',
templateUrl: './dashboard.component.html',
styleUrls: ['../app.component.scss', './dashboard.component.scss'],
encapsulation: ViewEncapsulation.None
})
export class DashboardComponent implements OnInit {
loginuser: any = {};
imgSrc: any = {};
users: any[] = [];
imageToShow: any;
public dataSource = new MatTableDataSource<User>();
displayedColumns = ['id', 'username', 'email', 'firstname', 'lastname', 'registeredDate', 'enabled'];
#ViewChild(MatPaginator) paginator: MatPaginator;
#ViewChild(MatSort) sort: MatSort;
constructor(private service: UserService, private http: HttpClient, private sanitizer: DomSanitizer) {
this.loginuser = JSON.parse(localStorage.getItem('currentUser'));
this.service.getAllUsers(this.loginuser.token).subscribe(u => {
this.dataSource.data = u as User[];
this.users = u;
// console.log('user: ', this.users);
});
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
}
ngOnInit() {
}
applyFilter(filterValue: string) {
this.dataSource.filter = filterValue.trim().toLowerCase();
if (this.dataSource.paginator) {
this.dataSource.paginator.firstPage();
}
}
}
The value of this injected member variable is not immediately available at component construction time!
Angular will fill in this property automatically, but only later in the component lifecycle, after the view initialization is completed.
If we want to write component initialization code that uses the references injected by #ViewChild, we need to do it inside the AfterViewInit lifecycle hook.
#Component({
selector: 'app-root',
templateUrl: './app.component.html'
})
export class AppComponent implements AfterViewInit {
#ViewChild(SomeComponent)
someComponent: SomeComponent;
ngAfterViewInit() {
console.log('Values on ngAfterViewInit():');
console.log("someComponent:", this.someComponent);
}
}
In Your case just put these two line in NgAfterViewInit LifeCyle as:
import { Component, OnInit, ViewChild } from '#angular/core';
import { ViewEncapsulation } from '#angular/core';
import { HttpClient, HttpHeaders } from '#angular/common/http';
import { UserService } from '../user.service';
import { MatDialog, MatDialogConfig, MatTableDataSource, MatPaginator, MatSort } from '#angular/material';
import { NewDialogComponent } from '../new-dialog/new-dialog.component';
import { DomSanitizer } from '#angular/platform-browser';
import { map } from 'rxjs-compat/operator/map';
import { Observable, Observer } from 'rxjs';
#Component({
selector: 'app-dashboard',
templateUrl: './dashboard.component.html',
styleUrls: ['../app.component.scss', './dashboard.component.scss'],
encapsulation: ViewEncapsulation.None
})
export class DashboardComponent implements OnInit, AfterViewInit {
loginuser: any = {};
imgSrc: any = {};
users: any[] = [];
imageToShow: any;
public dataSource = new MatTableDataSource<User>();
displayedColumns = ['id', 'username', 'email', 'firstname', 'lastname', 'registeredDate', 'enabled'];
#ViewChild(MatPaginator) paginator: MatPaginator;
#ViewChild(MatSort) sort: MatSort;
constructor(private service: UserService, private http: HttpClient, private sanitizer: DomSanitizer) {
this.loginuser = JSON.parse(localStorage.getItem('currentUser'));
this.service.getAllUsers(this.loginuser.token).subscribe(u => {
this.dataSource.data = u as User[];
this.users = u;
// console.log('user: ', this.users);
});
ngAfterViewInit() {
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
}
}