Error in creating a mat table or cdk table in Angular project - html-table

I want to use a material table in my angular application. I went through the official documentation of material to use the table. But I faced several errors in that.
This is my component code:
<div class="container">
<div class="header">
<span style="font-size: 20px;"
>Manage <sub style="font-size: 12px;">Brands</sub></span
>
</div>
<hr style="margin: 10px 0;" />
<button class="btn btn-primary">Add Brand</button>
<br />
<hr />
<cdk-table [dataSource]="dataSource">
<!-- Position Column -->
<ng-container cdkColumnDef="position">
<th cdk-header-cell *cdkHeaderCellDef> No. </th>
<td cdk-cell *cdkCellDef="let element"> {{element.position}} </td>
</ng-container>
<!-- Name Column -->
<ng-container cdkColumnDef="name">
<th cdk-header-cell *cdkHeaderCellDef> Name </th>
<td cdk-cell *cdkCellDef="let element"> {{element.name}} </td>
</ng-container>
<!-- Weight Column -->
<ng-container cdkColumnDef="weight">
<th cdk-header-cell *cdkHeaderCellDef> Weight </th>
<td cdk-cell *cdkCellDef="let element"> {{element.weight}} </td>
</ng-container>
<!-- Symbol Column -->
<ng-container cdkColumnDef="symbol">
<th cdk-header-cell *cdkHeaderCellDef> Symbol </th>
<td cdk-cell *cdkCellDef="let element"> {{element.symbol}} </td>
</ng-container>
<cdk-header-row *cdkHeaderRowDef="displayedColumns"></cdk-header-row>
<cdk-row *cdkRowDef="let row; columns: displayedColumns;"></cdk-row>
</cdk-table>
</div>
This is my imports folder :
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { BrowserAnimationsModule } from '#angular/platform-browser/animations';
import { HeaderComponent } from './header/header.component';
//======================================== material modules==========================
import { MatButtonModule } from '#angular/material/button';
import { MatIconModule } from '#angular/material/icon';
import { MatToolbarModule } from '#angular/material/toolbar';
import { MatInputModule } from '#angular/material/input';
import { MatFormFieldModule } from '#angular/material/form-field'
import { MatDividerModule } from '#angular/material/divider'
import { MatCheckboxModule } from '#angular/material/checkbox';
import { MatSidenavModule } from '#angular/material/sidenav';
import { MatListModule } from '#angular/material/list';
import { CdkTableModule } from '#angular/cdk/table';
import { DataSource } from '#angular/cdk/table'
// ==================================================================================
import { FormsModule, ReactiveFormsModule } from '#angular/forms';
import { LoginPageComponent } from './login-page/login-page.component';
import { ForgotPasswordPageComponent } from './forgot-password-page/forgot-password-page.component';
import { HomePageComponent } from './home-page/home-page.component';
import { DisplayModule } from './display/display-page.module'
#NgModule({
declarations: [
AppComponent,
HeaderComponent,
LoginPageComponent,
ForgotPasswordPageComponent,
HomePageComponent,
],
imports: [
BrowserModule, AppRoutingModule, BrowserAnimationsModule, MatButtonModule,
MatIconModule, MatToolbarModule,
MatInputModule, MatFormFieldModule, FormsModule, ReactiveFormsModule,
MatDividerModule, MatCheckboxModule, MatSidenavModule, MatListModule,
DisplayModule, CdkTableModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
screenshot of the error
ERROR in src/app/display/brands/brands.component.html:12:3 - error NG8001: 'cdk-table' is not a
known element:
1. If 'cdk-table' is an Angular component, then verify that it is part of this module.
2. If 'cdk-table' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '#NgModule.schemas' of
this component to suppress this message.
12 <cdk-table [dataSource]="dataSource">
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/app/display/brands/brands.component.ts:42:16
42 templateUrl: './brands.component.html', ~~~~~~~~~~~~~~~~~~~~~~~~~
Error occurs in the template of component BrandsComponent.
src/app/display/brands/brands.component.html:12:14 - error NG8002: Can't bind to 'dataSource' since
it isn't a known property of 'cdk-table'.
1. If 'cdk-table' is an Angular component and it has 'dataSource' input, then verify that it is part
of this module.
2. If 'cdk-table' 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.
12 <cdk-table [dataSource]="dataSource">
~~~~~~~~~~~~~~~~~~~~~~~~~
src/app/display/brands/brands.component.ts:42:16
42 templateUrl: './brands.component.html', ~~~~~~~~~~~~~~~~~~~~~~~~~
Error occurs in the template of component BrandsComponent.
I've already imported all the required modules and using the latest material and angular versions.
Still I can't get that. Can anyone suggest me how to get rid of this error?

Please import matTableModule like below.
import { MatTableModule } from '#angular/material/table'

Related

[Vue warn]: Failed to resolve component: v-simple-table, despite the table seemingly loading correctly?

I'm using the latest release of vuetify 3 with vue 3, and getting the warning in the title, but optically the table is loading correctly. What might be causing this?
The component containing the table:
<template>
<div class="right-bar text-no-wrap" style="overflow-x: scroll">
<v-simple-table id="myTable">
<template v-slot:default>
<thead>
<tr>
<th class="text-left font-weight-regular">Item</th>
<th class="text-right font-weight-regular font-italic pl-3">Unit</th>
<th class="text-right font-weight-regular pl-3">Total</th>
<th class="text-right font-weight-regular pl-3" v-for="period in dataset.modelPeriods" :key="period">Period {{ period }}</th>
</tr>
</thead>
</template>
</v-simple-table>
</div>
</template>
<script>
import { useStore } from 'vuex'
import { computed } from '#vue/runtime-core'
export default {
setup() {
const store = useStore()
const dataset = computed (
() => store.state.dataset
)
return { dataset }
}
}
</script>
<style>
</style>
My vuetify.js file:
// Styles
import '#mdi/font/css/materialdesignicons.css'
import 'vuetify/styles'
// Vuetify
import { createVuetify } from 'vuetify'
export default createVuetify(
// https://vuetifyjs.com/en/introduction/why-vuetify/#feature-guides
)

Strange behavior in Vue 3 without any error or warning

I have the following Vue 3 component that I am using in 2 pages that are setup like this in vue.config.js:
module.exports = {
// Put this in the ASP.NET Core directory
outputDir: "../wwwroot/app",
pages: {
vehicleDetails: "src/VehicleDetails.js",
driverDetails: "src/DriverDetails.js"
}
};
Both of these pages work and share the same underlying 'Certificates' component that looks like this:
<template>
<div>
<h3 id="Vue_Certificates">Certificates</h3>
<div>
objectId: {{objectId}} test
<table class="table table-striped table-hover table-condensed2" style="clear: both;">
<thead>
<tr>
<th><b>test</b></th>
<th style="text-align: right;">
<a href="#" #click="addCertificate">
<i class="fa fa-plus-square"></i> Add
</a>
</th>
</tr>
</thead>
<tbody>
<tr v-for="certificate in certificates" v-bind:key="certificate">
<td>{{ certificate.CertificateTypeId }}</td>
<td>
<a href="#" #click="removeCertificate(index)" title="Delete" style="float: right;" class="btn btn-default">
<i class="fa fa-trash"></i>
</a>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</template>
<script>
import axios from 'axios';
import { onMounted, ref } from "vue";
import $ from 'jquery';
import _ from 'lodash';
export default {
components: {
},
props: {
objectId: String,
ownerIsVehicle: Boolean
},
data() {
return {
certificates: [],
types: []
}
},
created() {
const requestOne = axios.get("/api/v1.0/CertificateType/GetCertificateTypes");
const requestTwo = axios.get("/api/v1.0/Certificate/GetCertificateByObjectId", { params: { objectId: this.objectId, ownerIsVehicle: this.ownerIsVehicle } });
axios.all([requestOne, requestTwo]).then(axios.spread((...responses) => {
const responseOne = responses[0];
const responseTwo = responses[1];
alert("Axios calls completed 1");
this.types = responseOne.data;
var mappedData = responseTwo.data.map(x => ({
...x,
ValidFrom: new Date(x.ValidFrom),
ValidTill: new Date(x.ValidTill)
}));
this.certificates = mappedData;
alert("Axios calls completed 2");
console.log("succes");
})).catch(errors => {
console.log("fail");
});
},
methods: {
removeCertificate(index) {
this.certificates.splice(index, 1);
},
addCertificate() {
alert("Hello?");
}
}
}
</script>
The above code does NOT render the Vue component, but once I take out the two cells containing the anchors that call addCertificate & removeCertificate it all suddenly works.
For some reason I don't get any error in Chrome dev tools .. npm console .. visual studio console .. nowhere, so I have no clue at all what is going wrong.
Important: If I take out 1 of the 2 lines in vue.config.js it works on the page that is still added. The purpose of this component is that it can be reused.
FYI: I shrank down the code as much as possible to make sure other code bits aren't the cause.
For the record, the data property "certificates" was first a ref([]) but that doesn't seem to help at all.
Thanks in advance!

sorting does not works with Virtual scrolling custom data source

Angular 8 brings really cool feature to implement virtual scroll. They have provide example here regarding usage of it. Although, its really difficult implement with mat-table.
I have been working on to implement virtual scroll on mat-table and found that, we need to have our own custom data source for that. I have create new data source by implementing DataSource class but what I found is that, I loose the sort and other features due to custom data source.
app.component.html
<cdk-virtual-scroll-viewport class="example-viewport">
<table class="table" mat-table #table matSort [dataSource]="dataSource" [multiTemplateDataRows]="true">
<ng-container matColumnDef="id">
<th mat-header-cell *matHeaderCellDef mat-sort-header> id </th>
<td mat-cell *matCellDef="let element"> {{element.id}} </td>
</ng-container>
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Name</th>
<td mat-cell *matCellDef="let element"> {{element.name}} </td>
</ng-container>
<ng-container matColumnDef="age">
<th mat-header-cell *matHeaderCellDef> Age</th>
<td mat-cell *matCellDef="let element"> {{element.age}} </td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></tr>
<!-- cdkVirtualScrollViewport uses transform: translateY to correct for all elements that are removed.
We will use a plcaholder row in the table instead because the translate causes problems with the sticky header -->
<tr [style.height.px]="placeholderHeight" mat-row *matRowDef="let row; let index = index; columns: []; when: placeholderWhen"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
</table>
</cdk-virtual-scroll-viewport>
app.component.ts
import { Component, OnInit, ViewChild, AfterViewInit } from "#angular/core";
import {
CdkVirtualScrollViewport,
FixedSizeVirtualScrollStrategy,
VIRTUAL_SCROLL_STRATEGY
} from "#angular/cdk/scrolling";
import { CollectionViewer } from "#angular/cdk/collections";
import { MatSort } from "#angular/material";
// import { GridTableDataSource } from './gridTable.datasource'
import { GridTableDataSource } from "./gridTableM.datasource";
const ROW_HEIGHT = 48;
/**
* Virtual Scroll Strategy
*/
export class CustomVirtualScrollStrategy extends FixedSizeVirtualScrollStrategy {
constructor() {
super(ROW_HEIGHT, 1000, 2000);
}
attach(viewport: CdkVirtualScrollViewport): void {
this.onDataLengthChanged();
}
}
#Component({
selector: "my-app",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"],
providers: [
{ provide: VIRTUAL_SCROLL_STRATEGY, useClass: CustomVirtualScrollStrategy }
]
})
export class AppComponent implements OnInit, AfterViewInit {
placeholderHeight = 0;
displayedColumns: string[] = ["id", "name", "age"];
dataSource: GridTableDataSource<any>;
rows = Array(200)
.fill(0)
.map((x, i) => {
return { name: "name" + i, id: i, age: 27 };
});
itemSize = 48;
#ViewChild(CdkVirtualScrollViewport, { static: true })
viewport: CdkVirtualScrollViewport;
#ViewChild(MatSort, { static: false }) sort: MatSort;
constructor() {}
ngOnInit() {
this.dataSource = new GridTableDataSource(
this.rows,
this.viewport,
this.itemSize
);
this.dataSource.offsetChange.subscribe(offset => {
this.placeholderHeight = offset;
});
this.dataSource.data = this.rows;
// debugger;
// this.dataSource.sort = this.sort; // this.sort is null here
}
ngAfterViewInit() {
debugger;
this.dataSource.sort = this.sort; // this.sort is null here as well
}
placeholderWhen(index: number, _: any) {
return index == 0;
}
}
To implement sorting and other feature, I just copied code from MatTableDataSource. but somehow, this.sort is always null in any method. I couldn't find reason for this. Can anyone explain this behavior?
Here is stackblitz to play with.
it doesn't work.
angular team doesn't support this
https://github.com/angular/components/issues/19003

PrimeNg TurboTable filters are not working with LazyLoad

I am unable to use filters with lazy load option. Can anyone help me if i am missing anything here?
I read primeng documentation this and this and this with examples. I could find any solution.
When I use both [lazy] and filters together, filters are not working. If I just remove [lazy]="true" from HTML would work the filters. How can I achieve both?
import { Component, OnInit, Input } from '#angular/core';
import { SelectItem, LazyLoadEvent } from 'primeng/primeng';
import { MyService } from '../services/my.service';
import { ColumnHeaders } from '.';
#Component({
selector: 'myList-table',
templateUrl: 'myList-table.component.html',
styleUrls: ['myList-table.component.less']
})
export class myListTableComponent implements OnInit {
rowCount = { 'value': 5 };
totalRecords: number = 0;
pageNavLinks: number = 0;
myList: any = [];
columnHeaders = ColumnHeaders;
#Input() myListStatus = 'live';
constructor(private myService: MyService) { }
ngOnInit() { this.lazyLoad({ 'first': 0 }); }
lazyLoad(event: LazyLoadEvent) {
const pageNumber = Math.round(event.first / this.rowCount.value) + 1;
this.myService.getmyList(this.myListStatus, pageNumber, this.rowCount.value)
.subscribe(response => {
this.myList = response.batches;
this.totalRecords = response.batches[0].TotalRowCount;
this.pageNavLinks = Math.round(this.totalRecords / this.rowCount.value);
});
}
changeCount() {
this.totalRecords = 0;
this.pageNavLinks = 0;
this.lazyLoad({ 'first': 0 });
}
}
<div class="ui-g-12">
<p-table #dt [columns]="columnHeaders" [value]="myList" [paginator]="true" [rows]="rowCount?.value" [totalRecords]="totalRecords" [responsive]="true" (onLazyLoad)="lazyLoad($event)" [lazy]="true">
<ng-template pTemplate="header" let-columns>
<tr>
<th *ngFor="let col of columns">
{{col.header}}
</th>
</tr>
<tr>
<th *ngFor="let col of columns">
<div class="search-ip-table">
<i class="fa fa-search"></i>
<input pInputText type="text" (input)="dt.filter($event.target.value, col.field, col.filterMatchMode)">
</div>
</th>
</tr>
</ng-template>
<ng-template pTemplate="body" let-rowData let-columns="columns">
<tr [pSelectableRow]="rowData">
<td>{{rowData.id}}</td>
<td>{{rowData.name}}</td>
<td>{{rowData.TName}}</td>
<td>{{rowData.Base}}</td>
<td>{{rowData.Date | date:'medium' }}</td>
</tr>
</ng-template>
<ng-template pTemplate="paginatorleft">
<span>Total Records: {{totalRecords}}</span>
</ng-template>
<ng-template pTemplate="paginatorright">
<p-dropdown [options]="pageRecordsCountOptions" [(ngModel)]="rowCount" optionLabel="value" (onChange)="changeCount()"></p-dropdown>
</ng-template>
</p-table>
</div>
When [lazy]="true", filter doesn't work in the front-end, but leave this work to the back-end by (onLazyLoad) event.
If you want filter your data in the front-end, you can into lazyLoad() method :
.subscribe(response =>. ...
using filter informations provided by event parameter.

Bootstrap table with nested components in angular2

I'm the begginer with angular2, and i try to build bootstrap table with nested components, the child component is display in single cell. Probably I'm doing something wrong with ngFor loop. This is my child component:
import { Component, OnInit, ViewEncapsulation, Input } from '#angular/core';
import { Customer } from '../customer';
import { CustomersComponent } from '../customers.component'
#Component({
selector: 'single-customer',
encapsulation: ViewEncapsulation.None,
inputs:['customer'],
templateUrl: './single-customer.component.html',
styleUrls: ['./single-customer.component.css']
})
export class SingleCustomerComponent implements OnInit {
customer: Customer;
constructor() { }
ngOnInit() {
}
}
and template:
<td>
{{customer.surname | uppercase}}
</td>
<td>
{{customer.name}}
</td>
<td>
{{customer.phone}}
</td>
<td>
{{customer.mail}}
</td>
<td>
{{customer.comments}}
</td>
<td><button type="button" class="btn btn-primary btn-xs" data-toggle="modal" data-target=".update-customer-modal" ng-click="setCustomerData(customer)">Edytuj</button></td>
<td><button type="button" class="btn btn-danger btn-xs" data-toggle="modal" data-target=".delete-customer-modal" ng-click="setCustomerData(customer)">Usuń</button></td>
<!-- </tr> -->
Parent component:
import { Component, OnInit, Directive, ViewEncapsulation } from '#angular/core';
import { NgFor } from '#angular/common';
import { SingleCustomerComponent } from './single-customer/single-customer.component';
import { Customer } from './customer';
import { CustomersService } from './customers.service';
#Component({
selector: 'app-customers',
encapsulation: ViewEncapsulation.None,
templateUrl: './customers.component.html',
styleUrls: ['./customers.component.css'],
providers: [CustomersService],
})
export class CustomersComponent implements OnInit {
customers: Customer[];
customersLength: number;
constructor(private _customersService: CustomersService) {
}
ngOnInit() {
this.getCustomers();
}
getCustomers(){
this._customersService.getCustomers().then((res) => {
this.customers = res;
this.customersLength = this.customers.length;
});
}
}
parent template:
<div class="col-md-12">
<div class="table-responsive">
<table class="table table-hover">
<thead>
<tr class="info">
<td>ID</td>
<td>NAZWISKO</td>
<td>IMIĘ</td>
<td>TELEFON</td>
<td>MAIL</td>
<td>URODZINY</td>
<td>UWAGI</td>
<td></td>
<td></td>
</tr>
</thead>
<tbody>
<tr *ngFor="let customer of customers">
<single-customer [customer]="customer"></single-customer>
</tr>
</tbody>
</table>
</div>
</div>
and parents module:
import { NgModule } from '#angular/core';
import { CommonModule } from '#angular/common';
import { CustomersComponent } from './customers.component';
import { SingleCustomerComponent } from './single-customer/single-customer.component'
#NgModule({
imports: [
CommonModule,
],
declarations: [CustomersComponent, SingleCustomerComponent]
})
export class CustomersModule { }
What I'm doing wrong?
Table element in HTML just allows thead, tbody, tfoot and tr as children.
You can change your children component's selector to:
#Component({
selector: '[single-customer]',
...
})
export class SingleCustomerComponent implements OnInit {
...
And change your parent template to:
...
<tbody>
<tr *ngFor="let customer of customers"
single-customer
[customer]="customer">
</tr>
</tbody>
...