Angular Material table: can't bind to 'matRowDefColumn' - html

I am trying to use an Angular Material table. I imported the module but I get a template parse error.
HTML:
<mat-table [dataSource]="dataSource">
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef> Name </mat-header-cell>
<mat-cell *matCellDef="let project">{{project.name}}</mat-cell>
</ng-container>
<ng-container matColumnDef="key">
<mat-header-cell *matHeaderCellDef> Key </mat-header-cell>
<mat-cell *matCellDef="let project">{{project.Key}}</mat-cell>
</ng-container>
<ng-container matColumnDef="reason">
<mat-header-cell *matHeaderCellDef> reason </mat-header-cell>
<mat-cell *matCellDef="let project">{{project.reason}}</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; column: displayedColumns;"></mat-row>
</mat-table>
Imports in the component:
import { Component, OnInit } from '#angular/core';
import {Observable} from "rxjs"
import { HttpClient, HttpErrorResponse } from '#angular/common/http';
import { ProjectService } from '../services/project.service';
import { UserService } from '../services/user.service';
import { Subject } from 'rxjs/Subject';
import { DataSource } from '#angular/cdk/collections';
DataSource: I return an Array as an Observable with the returnDeadProjectList()
export class ProjectDataSource extends DataSource<any>{
constructor(private project:ProjectComponent){
super();
}
connect(): Observable<Project[]>{
return this.project.returnDeadProjectList();
}
disconnect(){}
Imports from app.module.ts:
import { BrowserModule } from '#angular/platform-browser';
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '#angular/core';
import { HttpClientModule } from '#angular/common/http';
import { CommonModule } from "#angular/common";
import 'hammerjs';
import { ProjectService } from './services/project.service';
import { UserService } from './services/user.service';
import { BrowserAnimationsModule } from '#angular/platform-browser/animations';
import { FormsModule } from '#angular/forms';
import { MatInputModule, MatButtonModule, MatExpansionModule, MatDatepickerModule, MatNativeDateModule, MatToolbarModule, MatListModule, MatIconModule, MatProgressSpinnerModule, MatSlideToggleModule, MatTableModule, MatPaginatorModule } from '#angular/material';
import { AppComponent } from './app.component';
import { MyFormComponent } from './my-form/my-form.component';
import { BitbucketComponent } from './bitbucket/bitbucket.component';
import { UserComponent } from './user/user.component';
import { ProjectComponent } from './project/project.component';
import { CdkTableModule } from '#angular/cdk/table';
The error I get is:
compiler.js:466 Uncaught Error: Template parse errors:
Can't bind to 'matRowDefColumn' since it isn't a known property of 'mat-row'.
1. If 'mat-row' is an Angular component and it has 'matRowDefColumn' input, then verify that it is part of this module.
2. If 'mat-row' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '#NgModule.schemas' of this component to suppress this message.
3. To allow any property add 'NO_ERRORS_SCHEMA' to the '#NgModule.schemas' of this component.
If I write the CUSTOM_ELEMENTS_SCHEMA in schemas: [ ], I get an different error:
compiler.js:466 Uncaught Error: Template parse errors:
Property binding matRowDefColumn not used by any directive on an embedded template. Make sure that the property name is spelled correctly and all directives are listed in the "#NgModule.declarations". ("` `<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
[ERROR ->]<mat-row *matRowDef="let row; column: displayedColumns;"></mat-row>
Has someone an idea what I am missing? I should have all the imports I need but somehow it can't find the elements. Furthermore, I don't even use matHeaderRowDef

The code snippet
<mat-row *matRowDef="let row; column: displayedColumns;"></mat-row>
has a issue with the property name. MatRowDef has property columns not column.
Change it to
<mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row> and it should work after that.

Add this code in your .component.ts and in app.module.shared.ts.
It works for me
import {
MatPaginator, MatSort, MatTable, MatTableModule, MatTabHeader,
MatHeaderRow, MatHeaderCell, MatHeaderCellDef, MatHeaderRowDef,
MatSortHeader, MatRow, MatRowDef, MatCell, MatCellDef,
_MatCell, _MatCellDef, _MatHeaderCellDef, _MatHeaderRowDef
} from '#angular/material';
#NgModule({
imports: [MatPaginator, MatSort, TableDataSource,
CdkTableModule, MatTable, MatTableModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA],
declarations: [
MatTabHeader,
MatHeaderRow,
MatHeaderCell,
MatHeaderCellDef,
MatHeaderRowDef,
MatSortHeader,
MatRow,
MatRowDef,
MatCell,
MatCellDef,
_MatCell,
_MatCellDef,
_MatHeaderCellDef,
_MatHeaderRowDef
]
})

Related

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;
}
);
}

Table Paginator is not working as expected

I am fetching the data from the server, the data is coming well and showing in the but the paginator is not working although it is only showing.
The paginator is showing the webpage but it is not working as the next button, go to page etc.
<div class="container">
<div class="row">
<div class="col my-3">
<div class="mat-elevation-z8">
<app-message></app-message>
<table mat-table [dataSource]="dataSource">
<!-- Position Column -->
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef> Name </th>
<td mat-cell *matCellDef="let element"> {{element.name}}</td>
</ng-container>
<!-- Position Column -->
<ng-container matColumnDef="phone">
<th mat-header-cell *matHeaderCellDef> Phone </th>
<td mat-cell *matCellDef="let element"> {{element.phone}}</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
<mat-paginator [pageSizeOptions]="[5, 10, 20]" showFirstLastButtons></mat-paginator>
</div>
</div>
</div>
</div>
This is the TS code.
export class UsersComponent implements OnInit {
displayedColumns: string[] = ['name', 'phone'];
dataSource = new MatTableDataSource<PeriodicElement>([]);
#ViewChild(MatPaginator, {static: true}) paginator: MatPaginator;
constructor(public data: DataService, private rest: RestApiService) {}
ngOnInit() {
this.getUsers();
this.dataSource.paginator = this.paginator;
}
async getUsers(){
try {
const data =await this.rest.get("http://localhost:3030/user/auth/all/users");
if(data['status']) {
console.log(data['data']);
this.dataSource = data['data'];
} else {
this.data.error(data['message']);
}
} catch (error) {
this.data.error(error['message']);
}
}
}
interface PeriodicElement {
slno:number,
name: string,
phone: string
}
const dataArray: PeriodicElement[] = [];
Can u integrate AfterViewInit and call this
ngAfterViewInit() {
this.dataSource.paginator = this.paginator;
}
and change
this.dataSource = data['data'];
to
this.dataSource.data = data['data'];
Make sure you import MatPaginator from #angular/material/paginator not #angular/material
Seems like you have not added the corresponding table and paginator modules inside your app.module.ts
app.module.ts
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { FormsModule } from '#angular/forms';
import {MatTableModule} from '#angular/material/table';
import {MatPaginatorModule} from '#angular/material/paginator';
import { AppComponent } from './app.component';
import { HelloComponent } from './hello.component';
#NgModule({
imports: [ BrowserModule, FormsModule, MatTableModule,MatPaginatorModule ],
declarations: [ AppComponent, HelloComponent ],
bootstrap: [ AppComponent ]
})
export class AppModule { }
As your code was not working even on stackblitz, so i have added dummy data to show you an example. Please find stackblitz here: https://stackblitz.com/edit/angular-tcgvnu

Unable to bind data to Angular Material Data Table

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.

How to use Mat-Select with property [Selected]

I have a component which allows for translate pipng(by .json files under assets) .That works perfectly with default select box to choose language as we wish to display.Here it is below(That works great)
<select #langSelect (change)="translate.use(langSelect.value)">
<option *ngFor="let lang of translate.getLangs()"
[value]="lang"
[selected]="lang === translate.currentLang">{{ lang }}
</option>
</select>
But to make it look much better,I want to implement this logic with mat-select and here how I tried to implement below.
With Mat-Select
<mat-form-field>
<mat-select #langSelect (change)="translate.use(langSelect.value)"
placeholder="Select offer"
formControlName="promo" [(value)]="selected">
<mat-option *ngFor="let lang of translate.getLangs()"
[value]="lang"
[selected]="lang === translate.currentLang"
>{{ lang }}
<i class="material-icons">info</i>
</mat-option>
</mat-select>
</mat-form-field>
When I run this code Error occurs because of unknown [selected] binding inside mat-option tags.I don't know is there any way to implement it with no error.Here that error in the console occurs below
ERROR
Uncaught Error: Template parse errors:
No provider for NgControl ("">{{ lang }}</option>
</select> -->
[ERROR ->]<select #langSelect (change)="translate.use(langSelect.value)" placeholder="Select offer" formContro"): ng:///AppModule/HeaderComponent.html#17:34
App.Module.ts
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import {BrowserAnimationsModule} from '#angular/platform-browser/animations';
import {FlexLayoutModule} from '#angular/flex-layout';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { MaterialModule } from './material.module';
import { SignupComponent } from './auth/signup/signup.component';
import { LoginComponent } from './auth/login/login.component';
import { TrainingComponent } from './training/training.component';
import { CurrentTrainingComponent } from './training/current-training/current-training.component';
import { NewTrainingComponent } from './training/new-training/new-training.component';
import { PastTrainingComponent } from './training/past-training/past-training.component';
import { WelcomeComponent } from './welcome/welcome.component';
import { FormsModule } from '#angular/forms';
import { HeaderComponent } from './navigation/header/header.component';
import { SidenavListComponent } from './navigation/sidenav-list/sidenav-list.component';
import { StopTrainingComponent } from './training/current-training/stop-training-component';
import { AuthService } from './auth/auth.service';
import {TranslateModule, TranslateLoader} from '#ngx-translate/core';
import {TranslateHttpLoader} from '#ngx-translate/http-loader';
import { HttpClient, HttpClientModule } from '#angular/common/http';
export function HttpLoaderFactory(httpClient: HttpClient) {
return new TranslateHttpLoader(httpClient);
}
#NgModule({
declarations: [
AppComponent,
SignupComponent,
LoginComponent,
TrainingComponent,
CurrentTrainingComponent,
NewTrainingComponent,
PastTrainingComponent,
WelcomeComponent,
HeaderComponent,
StopTrainingComponent,
SidenavListComponent
],
imports: [
BrowserModule,
HttpClientModule,
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useFactory: HttpLoaderFactory,
deps: [HttpClient]
}
}),
FormsModule,
AppRoutingModule,
BrowserAnimationsModule,
MaterialModule,
FlexLayoutModule
],
//To use always same AuthService object
providers: [AuthService],
bootstrap: [AppComponent],
entryComponents:[StopTrainingComponent]
})
export class AppModule { }
You can check documentation and examples here:
https://material.angular.io/components/select/examples
There is also a selected example.
First problem is, selected is not available for mat-option.
What you need to do is, on your component.ts file you need to find selected element from your array, and set it to a variable.
Then in your mat-select, set [(value)] attribute as that variable. It will make it selected.
Example:
<mat-select [(value)]="selected">
<mat-option>None</mat-option>
<mat-option value="option1">Option 1</mat-option>
<mat-option value="option2">Option 2</mat-option>
<mat-option value="option3">Option 3</mat-option>
</mat-select>

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;
}
}