Component inside Mat-tab: How to scroll inner component - html

I'm working on a small attendance project and have some table component within some mat-tab components. When there is overflow from the table, it scrolls the full component, I only want it to scroll the table on the inner component.
I have tried adding "overflow: auto" in these sections:
on the (app-attendance-table) selector
inside table component
::ng-deep { .mat-tab-body { overflow: auto } }
on the (mat-tab-group) selector
wrapped (app-attendance-table) in an (ng-container) or (div) and adding overflow: auto
This is the outer component with tabs:
<ng-container>
<mat-form-field class="date">
<input
matInput
[matDatepicker]="picker"
placeholder="Select a Date"
(dateInput)="addEvent($event)"
[(ngModel)]="currentDate"
/>
<mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
<mat-datepicker #picker></mat-datepicker>
</mat-form-field>
</ng-container>
<mat-tab-group>
<ng-container *ngFor="let grade of result; let i = index">
<mat-tab *ngIf="grade.length > 0" [label]="grades[i]">
<app-attendance-table [dataSource]="grade"></app-attendance-table>
</mat-tab>
</ng-container>
</mat-tab-group>
<div *ngIf="this.result.length < 1 && !this.loading">
No Records Found for The Date: {{ currentDate.toDateString() }}
</div>
<mat-spinner *ngIf="this.loading"> </mat-spinner>
</div>
This is the actual table component itself:
<mat-table #table [dataSource]="dataSource">
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef> Student Name </mat-header-cell>
<mat-cell *matCellDef="let student"
><span
[ngClass]="{
absent: student.isAbsent() && !student.Reason,
finished: student.isAbsent() && student.Reason && !student.editing
}"
>
{{ student.Name }}
</span>
</mat-cell>
</ng-container>
<ng-container matColumnDef="grade">
<mat-header-cell *matHeaderCellDef> Student Grade </mat-header-cell>
<mat-cell
[ngClass]="{
absent: student.isAbsent() && !student.Reason,
finished: student.isAbsent() && student.Reason && !student.editing
}"
*matCellDef="let student"
>
{{ student.Grade }}
</mat-cell>
</ng-container>
<ng-container matColumnDef="status">
<mat-header-cell *matHeaderCellDef> Status </mat-header-cell>
<mat-cell
[ngClass]="{
absent: student.isAbsent() && !student.Reason,
finished: student.isAbsent() && student.Reason && !student.editing
}"
*matCellDef="let student"
>
{{ student.Status }}
</mat-cell>
</ng-container>
<ng-container matColumnDef="reason">
<mat-header-cell *matHeaderCellDef> Reason </mat-header-cell>
<mat-cell *matCellDef="let student">
<mat-form-field
class="reasons"
*ngIf="!student.isPresent()"
appearance="outline"
>
<mat-select
[(ngModel)]="student.Reason"
[disabled]="!student.editing"
placeholder="Select Reason"
(selectionChange)="makeChange(student)"
>
<mat-option
*ngFor="let reason of reasons; let i = index"
[value]="reason"
[disabled]="student.Reason === reason"
>
{{ reason }}
</mat-option>
</mat-select>
</mat-form-field>
</mat-cell>
</ng-container>
<ng-container matColumnDef="comments">
<mat-header-cell *matHeaderCellDef> Comments </mat-header-cell>
<mat-cell *matCellDef="let student">
<mat-form-field *ngIf="!student.isPresent()">
<input
matInput
[(ngModel)]="student.Comments"
[disabled]="!student.editing"
(input)="makeChange(student)"
/>
</mat-form-field>
</mat-cell>
</ng-container>
<ng-container matColumnDef="edit">
<mat-header-cell *matHeaderCellDef> </mat-header-cell>
<mat-cell *matCellDef="let student">
<button
*ngIf="!student.isPresent() && !student.editing"
mat-raised-button
color="primary"
(click)="startEditing(student)"
>
Edit
</button>
<button
*ngIf="!student.isPresent() && student.editing"
mat-raised-button
color="warn"
(click)="saveEdits(student)"
>
Finish
</button>
</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
</mat-table>
</div>

To make sure the table is scrollable, wrap the table inside div with a fixed height and make its overflow: auto.
You can also check below links that has both page as well as table as scrollable.
https://angular-qfqpwr.stackblitz.io (Working Stackblitz)
https://material.angular.io/components/table/examples (Table with sticky header)

To extend on #Pankaj Prakash's answer, you should set the overflow property on your outer container to overflow: hidden.
Then wrap a div around the mat cells and set the property to overflow: scroll. If you only want a vertical scroll you could also set the following property instead: overflow-y: scroll

Related

Angular 12 Material MatDialogConfig shadows on parent window does not disappear when close popup windows

I am using Angular 12 with Material... I have a main page with a mat-table.
In the HTML I have an Edit() button inside the table and a create() button outside the table.
This is the call .ts in the to the popup Windows. In both cases I call the same function.
callDialog(id:any)
{
const dialogConfig = new MatDialogConfig();
dialogConfig.disableClose = true;
dialogConfig.autoFocus = true;
dialogConfig.width = "60%";
dialogConfig.data=id;
dialogConfig.backdropClass= 'bdrop';
const dialogRef = this.dialog.open(NotificationDetailComponent,dialogConfig);
dialogRef.afterClosed().subscribe(result => {
this.NotificationService();
});
}
create() {
this.callDialog(null);
}
edit(id:string){
this.callDialog(id);
}
When I open the dialog window, the parent window has a shadow.
When I close the popup windows, OnEdit (the button is inside the table), the shadow disappear and all come back to normal. But when I click onCreate() button and then close the popup window, the shadows does not disappear.
In other words.. the shadows in the parent window does not disappear if the button is outside the table..
I tested adding the Create() button inside the table and it works fine...
this is my HTML
<connector-card [title]="cardTitle">
</connector-card>
<div class="search-div">
<button mat-raised-button (click)="create()">
<mat-icon>add</mat-icon>Create
</button>
<mat-form-field class="search-form-field" floatLabel="never" >
<input matInput [(ngModel)]="searchKey" placeholder="Search" autocomplete="off" (keydown.enter)="search()">
<button mat-button matSuffix mat-icon-button aria-label="Clear" *ngIf="searchKey" (click)="delete()">
<mat-icon>close</mat-icon>
</button>
</mat-form-field>
</div>
<div class="mat-elevation-z8">
<mat-table [dataSource]="dataSource" matSort>
<ng-container matColumnDef="Active">
<mat-header-cell *matHeaderCellDef>Active</mat-header-cell>
<mat-cell *matCellDef="let not">{{not.Active}}</mat-cell>
</ng-container>
<ng-container matColumnDef="NotificationName" >
<mat-header-cell *matHeaderCellDef mat-sort-header>Notification Name</mat-header-cell>
<mat-cell *matCellDef="let not">{{not.NotificationName}}</mat-cell>
</ng-container>
<ng-container matColumnDef="ProcessorName" >
<mat-header-cell *matHeaderCellDef mat-sort-header>Processor Name</mat-header-cell>
<mat-cell *matCellDef="let not">{{not.ProcessorName}}</mat-cell>
</ng-container>
<ng-container matColumnDef="ChannelAndLevel">
<mat-header-cell *matHeaderCellDef mat-sort-header>Channel & Level</mat-header-cell>
<mat-cell *matCellDef="let not">{{not.ChannelAndLevel}}</mat-cell>
</ng-container>
<ng-container matColumnDef="edit">
<mat-header-cell *matHeaderCellDef></mat-header-cell>
<mat-cell *matCellDef="let not">
<button mat-icon-button matTooltip="Click to Edit" color="primary" (click)="edit(not.Id)">
<mat-icon>edit</mat-icon>
</button> </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 #paginator [length]="tablePaging.totalRows" [pageIndex]="tablePaging.pageNum" [pageSize]="tablePaging.pageSize" showFirstLastButtons
[pageSizeOptions]="tablePaging.pageSizeOptions" (page)="pageChanged($event)" aria-label="Select page">
</mat-paginator>
</div>
Here is the windows
Another thing I notice if I change the style using
dialogConfig.backdropClass= 'bdrop';
.bdrop {
background-color: #bbbbbbf2;
backdrop-filter: blur(4px);
}
th shadows appears before I open the popup windows, and once opened, the shadow disappears.. But OnCreate() the shadows appears again when I close the opoup windows.
What I am missing?
I had defined my Create button like this
<button mat-raised-button (click)="create()">
<mat-icon>add</mat-icon>Create
</button>
I changed the definition like this
<button (click)="create()">
<mat-icon>add</mat-icon>Create
</button>
I removed
mat-raised-button
and now it works fine... Do not know why...

Click event of Button in MatTable doesn't works

I'm new to Angular Material and have been implementing the MatTable by fetching the data from the Firebase (Real-time Database). For every Row of the MatTable, I need a button to delete the particular data of the row by its $key. The MatTable, fetching of data and the button shows up properly. Just when the button is clicked, it doesn't calls the delete function given in the click event.
Angular 8.2
Angular Material 8.2.3
Firebase 7.14.1
Typescript 3.5.3
HTML code for MatTable
<mat-table [dataSource]="listData" matSort>
<ng-container matColumnDef="key">
<mat-header-cell *matHeaderCellDef >key</mat-header-cell>
<mat-cell *matCellDef="let element">{{element.$key}}</mat-cell>
</ng-container>
<ng-container matColumnDef="studentPRN">
<mat-header-cell *matHeaderCellDef >PRN</mat-header-cell>
<mat-cell *matCellDef="let element">{{element.leaveStudentPRN}}</mat-cell>
</ng-container>
<ng-container matColumnDef="studentName" >
<mat-header-cell *matHeaderCellDef >Name</mat-header-cell>
<mat-cell *matCellDef="let element">{{element.leaveStudentName}}</mat-cell>
</ng-container>
<ng-container matColumnDef="studentClass">
<mat-header-cell *matHeaderCellDef>Class</mat-header-cell>
<mat-cell *matCellDef="let element">{{element.leaveStudentClass}}</mat-cell>
</ng-container>
<ng-container matColumnDef="startDate">
<mat-header-cell *matHeaderCellDef mat-sort-header>Start Date</mat-header-cell>
<mat-cell *matCellDef="let element">{{element.leaveStartDate}}</mat-cell>
</ng-container>
<ng-container matColumnDef="endDate">
<mat-header-cell *matHeaderCellDef mat-sort-header>End Date</mat-header-cell>
<mat-cell *matCellDef="let element">{{element.leaveEndDate}}</mat-cell>
</ng-container>
<ng-container matColumnDef="leaveType">
<mat-header-cell *matHeaderCellDef>Type</mat-header-cell>
<mat-cell *matCellDef="let element">{{element.leaveType}}</mat-cell>
</ng-container>
<ng-container matColumnDef="leaveDescription">
<mat-header-cell *matHeaderCellDef>Description</mat-header-cell>
<mat-cell *matCellDef="let element">{{element.leaveDescription}}</mat-cell>
</ng-container>
<ng-container matColumnDef="leaveTeacher">
<mat-header-cell *matHeaderCellDef>Requested to</mat-header-cell>
<mat-cell *matCellDef="let element">{{element.leaveTeacher}}</mat-cell>
</ng-container>
<ng-container matColumnDef="leaveStatus">
<mat-header-cell *matHeaderCellDef>Status</mat-header-cell>
<mat-cell *matCellDef="let element">{{element.leaveStatus}}</mat-cell>
</ng-container>
<ng-container matColumnDef="action">
<mat-header-cell *matHeaderCellDef>Action</mat-header-cell>
<mat-cell *matCellDef="let row">
<button mat-icon-button color="warn" (click)="withdrawLeave(row.$key)">
<mat-icon>delete_outline</mat-icon></button>
</mat-cell>
</ng-container>
<ng-container matColumnDef="loading">
<mat-footer-cell *matFooterCellDef colspan="6">Fetching data...</mat-footer-cell>
</ng-container>
<ng-container matColumnDef="noData">
<mat-footer-cell *matFooterCellDef colspan="6">No data found.</mat-footer-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayColumns"></mat-header-row>
<mat-row *matRowDef="let rows; columns: displayColumns;"></mat-row>
<mat-footer-row *matFooterRowDef="['noData']" [ngClass]="{'hide':listData!=null}"></mat-footer-row>
<mat-footer-row *matFooterRowDef="['loading']" [ngClass]="{'hide':!(listData!=null && listData.data.length==0)}"></mat-footer-row>
</mat-table>
<mat-paginator [pageSizeOptions]="[5,10,20,30]" [pageSize]="5" showFirstLastButtons></mat-paginator>
Typescript for button click event
withdrawLeave($key){
if(confirm("Do you want to withdraw the leave request?")){
this.auth.withdrawLeave($key);
}
Auth Service
leaveList : AngularFireList<any>;
getLeaves(){
this.leaveList = this.firebase.list('Leaves');
return this.leaveList.snapshotChanges();
}
withdrawLeave($key: string){
this.leaveList.remove($key);
}
Typescript for fetching data into MatTable
setAppliedLeaves(){
this.auth.getLeaves().subscribe(list => {
let array = list.map(item => {
return {
$key: item.key,
...item.payload.val()
};
});
this.listData = new MatTableDataSource(array);
this.listData.sort = this.sort;
this.listData.paginator = this.paginator;
});
}
I think the problem is the way you are sending the element to the function.
Here is an example of how I implemented a click - delete.
In the html file:
<ng-container matColumnDef="columndelete">
<th mat-header-cell *matHeaderCellDef>Delete</th>
<td mat-cell *matCellDef="let element">
<h5 (click)="delete(element)"><i class="fa fa-trash"></i>
</h5>
</td>
</ng-container>
and in the ts file:
delete(elm: Details) {
//logic
}
Details is the interface, the type of the element.
BTW, you might want to look at this link https://material.angular.io/components/table/overview,
instead of for example
<mat-table ...>
you should use
<table mat-table ...>

Conflicting Components Angular Testing

I am following this project (https://stackblitz.com/edit/angular-material-expandable-table-rows) for my feature development as I am trying to achieve the similar functionality.
I was able get my feature working correctly, however when I run the test, I get the following error -
Template parse errors:
More than one component matched on this element.
Make sure that only one component's selector can match a given element.
Conflicting components: MockedComponent,MatHeaderRow ("
</ng-container>
[ERROR ->]<mat-header-row *matHeaderRowDef="displayedColumnsProgramDetails"></mat-header-row>
"): ng:///DynamicTestModule/MaterialAudioProgramsComponent.html#107:18
More than one component matched on this element.
Make sure that only one component's selector can match a given element.
Conflicting components: MockedComponent,MatRow ("t-header-row *matHeaderRowDef="displayedColumnsProgramDetails"></mat-header-row>
[ERROR ->]<mat-row *matRowDef="let row; columns: displayedColumnsProgramDetails;"></mat-row>
I am unable to figure out what I need to do here.
Here's my component.html
<mat-spinner *ngIf="dataLoading" class="loading"></mat-spinner>
<ng-container class="ap-container" *ngIf="materialAudioPrograms$ | async as materialAudioPrograms">
<div class="container" *ngIf="materialAudioPrograms.length > 0; else dataLoading">
<mat-table [dataSource]="dataSource$" class="audio-programs vertical-data">
<ng-container matColumnDef="Start Channel">
<mat-header-cell *matHeaderCellDef>
Start Channel </mat-header-cell>
<mat-cell *matCellDef="let element">
<mat-icon *ngIf="element.show== false" aria-hidden="false" aria-label="ad-info-icon">keyboard_arrow_right
</mat-icon>
<mat-icon *ngIf="element.show== true" aria-hidden="false" aria-label="ad-info-icon">keyboard_arrow_down
</mat-icon>
{{element.startChannelNumber}}
</mat-cell>
</ng-container>
<ng-container matColumnDef="Layout">
<mat-header-cell *matHeaderCellDef> Layout </mat-header-cell>
<mat-cell *matCellDef="let element"> {{element.layout}} </mat-cell>
</ng-container>
<ng-container matColumnDef="Language">
<mat-header-cell *matHeaderCellDef> Language </mat-header-cell>
<mat-cell mat-cell *matCellDef="let element"> {{(element.language != null) ? element.language : 'None'}}
</mat-cell>
</ng-container>
<ng-container matColumnDef="Active">
<mat-header-cell *matHeaderCellDef> Active </mat-header-cell>
<mat-cell *matCellDef="let element"> {{(element.active == true)? 'Yes': 'No'}} </mat-cell>
</ng-container>
<ng-container matColumnDef="expandedDetail">
<mat-cell *matCellDef="let detail">
<mat-tab-group>
<!-- Program Tab and Table -->
<mat-tab label="Program">
<ng-container>
<mat-table [dataSource]="audioProgramDetailsDataSource$" class="vertical-data">
<ng-container matColumnDef="Censored">
<mat-header-cell *matHeaderCellDef> Censored </mat-header-cell>
<mat-cell *matCellDef="let element">
{{(element.censored != null) ? (element.censored ? 'Yes' :'No'): 'None'}} </mat-cell>
</ng-container>
<ng-container matColumnDef="Dubbed">
<mat-header-cell *matHeaderCellDef> Dubbed </mat-header-cell>
<mat-cell *matCellDef="let element">
{{(element.dubbed != null) ? (element.dubbed ? 'Yes' :'No'): 'None'}} </mat-cell>
</ng-container>
<ng-container matColumnDef="Music">
<mat-header-cell *matHeaderCellDef> Music </mat-header-cell>
<mat-cell *matCellDef="let element">
{{(element.music != null) ? (element.music ? 'Yes' :'No'): 'None'}} </mat-cell>
</ng-container>
<ng-container matColumnDef="Effects">
<mat-header-cell *matHeaderCellDef> Effects </mat-header-cell>
<mat-cell *matCellDef="let element">
{{(element.effects != null) ? (element.effects ? 'Yes' :'No'): 'None'}} </mat-cell>
</ng-container>
<ng-container matColumnDef="DVS">
<mat-header-cell *matHeaderCellDef> DVS </mat-header-cell>
<mat-cell *matCellDef="let element"> {{(element.dvs != null) ? (element.dvs ? 'Yes' :'No'): 'None'}}
</mat-cell>
</ng-container>
<ng-container matColumnDef="MOS">
<mat-header-cell *matHeaderCellDef> MOS </mat-header-cell>
<mat-cell *matCellDef="let element">
{{(element.muteOrSilence != null) ? (element.muteOrSilence ? 'Yes' :'No'): 'None'}} </mat-cell>
</ng-container>
<ng-container matColumnDef="Voiceover">
<mat-header-cell *matHeaderCellDef> Voiceover </mat-header-cell>
<mat-cell *matCellDef="let element">
{{(element.voiceOver != null) ? (element.voiceOver ? 'Yes' :'No'): 'None'}} </mat-cell>
</ng-container>
<ng-container matColumnDef="Rescore">
<mat-header-cell *matHeaderCellDef> Rescore </mat-header-cell>
<mat-cell *matCellDef="let element">
{{(element.rescore != null) ? (element.rescore ? 'Yes' :'No'): 'None'}} </mat-cell>
</ng-container>
<ng-container matColumnDef="Contains Dialog">
<mat-header-cell *matHeaderCellDef> Contains Dialog </mat-header-cell>
<mat-cell *matCellDef="let element">
{{(element.dialog != null) ? (element.dialog ? 'Yes' :'No'): 'None'}} </mat-cell>
</ng-container>
<ng-container matColumnDef="CALM Act">
<mat-header-cell *matHeaderCellDef> CALM Act Compliance </mat-header-cell>
<mat-cell *matCellDef="let element">
{{(element.calmACT != null) ? (element.calmAct ? 'Yes' :'No'): 'None'}} </mat-cell>
</ng-container>
<ng-container matColumnDef="EBUR128">
<mat-header-cell *matHeaderCellDef> EBUR128 Compliance </mat-header-cell>
<mat-cell *matCellDef="let element">
{{(element.ebuR128 != null) ? (element.ebuR128 ? 'Yes' :'No'): 'None'}} </mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumnsProgramDetails"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumnsProgramDetails;"></mat-row>
</mat-table>
</ng-container>
</mat-tab>
<!--
Attributes Tab and Table -->
<mat-tab label="Attributes">
<ng-container>
<mat-table [dataSource]="audioProgramDetailsDataSource$" class="vertical-data">
<ng-container matColumnDef="Loudness Level">
<mat-header-cell *matHeaderCellDef> Loudness Level </mat-header-cell>
<mat-cell *matCellDef="let element">
{{(element.loudnessLevel != null) ? (element.loudnessLevel ? 'Yes' :'No'): 'None'}} </mat-cell>
</ng-container>
<ng-container matColumnDef="Loudness Range">
<mat-header-cell *matHeaderCellDef> Loudness Range </mat-header-cell>
<mat-cell *matCellDef="let element">
{{(element.loudness_Range != null) ? (element.loudness_Range ? 'Yes' :'No'): 'None'}} </mat-cell>
</ng-container>
<ng-container matColumnDef="True Peak Level (Max)">
<mat-header-cell *matHeaderCellDef> True Peak Level (Max) </mat-header-cell>
<mat-cell *matCellDef="let element">
{{(element.truePeakLevel != null) ? (element.truePeakLevel ? 'Yes' :'No'): 'None'}} </mat-cell>
</ng-container>
<ng-container matColumnDef="True Peak Channel-L">
<mat-header-cell *matHeaderCellDef> True Peak Level Channel-L </mat-header-cell>
<mat-cell *matCellDef="let element">
{{(element.truePeakLevelChannel_L != null) ? (element.truePeakLevelChannel_L ? 'Yes' :'No'): 'None'}}
</mat-cell>
</ng-container>
<ng-container matColumnDef="True Peak Channel-R">
<mat-header-cell *matHeaderCellDef> True Peak Level Channel-R </mat-header-cell>
<mat-cell *matCellDef="let element">
{{(element.truePeakLevelChannel_R != null) ? (element.truePeakLevelChannel_R ? 'Yes' :'No'): 'None'}}
</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumnsAttributeDetails"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumnsAttributeDetails;"></mat-row>
</mat-table>
</ng-container>
</mat-tab>
</mat-tab-group>
</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumnsAudioPrograms"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumnsAudioPrograms;" class="element-row" matRipple
(click)="toggleRow(row)"></mat-row>
<mat-row *matRowDef="let row; columns: ['expandedDetail']; when: isExpansionDetailRow"
[#detailExpand]="row.element.show ? 'expanded' : 'collapsed'" style="overflow: hidden"> </mat-row>
</mat-table>
<div class="container" *ngIf="materialAudioPrograms.length === 0 && (dataLoading === false | async)">
<p class="no-data-msg">No Audio Programs Available</p>
</div>
</div>
</ng-container>
Here' the component.module.ts
import { NgModule } from '#angular/core';
import { CommonModule } from '#angular/common';
import { MaterialAudioProgramsComponent } from './material-audio-programs.component';
import {
MatTableModule,
MatTabsModule,
MatIconModule,
MatProgressSpinnerModule
} from '#angular/material';
#NgModule({
declarations: [MaterialAudioProgramsComponent],
imports: [CommonModule, MatProgressSpinnerModule, MatTableModule, MatTabsModule, MatIconModule],
entryComponents: [MaterialAudioProgramsComponent]
})
export class MaterialAudioProgramsModule {
// Define entry property to access entry component in lazy-loader service
static entry = MaterialAudioProgramsComponent;
}
And the component.spec.ts
import { async, ComponentFixture, TestBed } from '#angular/core/testing';
import { MaterialMockModule } from '#content-platform/unit-test-helpers';
import { MaterialAudioProgramsComponent } from './material-audio-programs.component';
import { StoreModule } from '#ngrx/store';
import { RouterTestingModule } from '#angular/router/testing';
import { CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA } from '#angular/core';
import { MatTableModule } from '#angular/material';
describe('MaterialAudioProgramsComponent', () => {
let component: MaterialAudioProgramsComponent;
let fixture: ComponentFixture<MaterialAudioProgramsComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [MaterialAudioProgramsComponent],
imports: [MaterialMockModule, StoreModule.forRoot({}), RouterTestingModule, MatTableModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(MaterialAudioProgramsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
I am not able to figure out a solution for this,any help is greatly appreciated.
Thanks
Try removing MaterialMockModule and leaving MatTableModule. If I were you, I would take advantage of NO_ERRORS_SCHEMA and not import any module but you may need them (the child components) when doing integration tests.

How to change a MaterialTable Cell content on click?

Big Picture
Hi,
I'm trying to use Angular Material in Angular 7.
I have to use a Material table with some data on it. My question is: Is there a way to change a MatCell content on click?
For example, consider the table in HTML above, with people's name, age and phone.
Angular Material Table HTML
<mat-form-field>
<input matInput (keyup)="applyFilter($event.target.value)" placeholder="Phone">
</mat-form-field>
<mat-table [dataSource]="dataSource" class="mat-elevation-z8" matSort >
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef mat-sort-header>Name</mat-header-cell>
<mat-cell *matCellDef="let person" >{{person.name}}</mat-cell>
</ng-container>
<ng-container matColumnDef="age">
<mat-header-cell *matHeaderCellDef mat-sort-header>Age</mat-header-cell>
<mat-cell *matCellDef="let person">{{person.age}}</mat-cell>
</ng-container>
<ng-container matColumnDef="phone">
<mat-header-cell *matHeaderCellDef mat-sort-header>Phone Number</mat-header-cell>
<mat-cell *matCellDef="let person">{{person.phone}}</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]="100" [pageSize]="5" [pageSizeOptions]="[5, 10, 25, 100]"></mat-paginator>
What works
Table to diplay data, pagination, filter and sorting headers are working great!
What I need
I want to do is when I click in the phone cell, insted of a text, a <input> tag takes {{person.phone}} place with the current number, allowing me to change the phone number and save the new one.
like this:
Desired MatCell content on click
<ng-container matColumnDef="phone">
<mat-header-cell *matHeaderCellDef mat-sort-header>Phone Number</mat-header-cell>
<mat-cell *matCellDef="let person">
<input matInput [value]="person.phone"(focusout)="changePhone($event.target.value, person)" placeholder="Phone">
</mat-cell>
</ng-container>
Can anyone help me please?
You can use *ngIf with some kind of flag for the selected phone number to swap between the two. So for example, if you have something like this in your component:
selectedPerson:Person;
...you could have something like this in your template:
...
<ng-container matColumnDef="phone">
<mat-header-cell *matHeaderCellDef mat-sort-header>Phone Number</mat-header-cell>
<mat-cell *matCellDef="let person">
<span *ngIf="selectedPerson !== person" (click)="selectedPerson = person">
{{person.phone}}
</span>
<input *ngIf="selectedPerson === person" matInput [value]="person.phone"(focusout)="changePhone($event.target.value, person)" placeholder="Phone">
</mat-cell>
</ng-container>
...

Need to change the color of a row depending on the status in ANGULAR 4

I have 6 column ie.. name, email, phone, company, status_1 and status_2.
status_1 has two option , ie.. "1" or "0"
status_2 also has two option , ie.. "1" or "0"
My Requirement : I need to change the color of the row
logic :
if(status_1 is "1" -> change to red)
else if (status_2 is "1" -> change to green)
else if (status_1 and status_2 is "1" -> give priority to status_1)
Mycode :
<div>
<mat-table [dataSource]="dataSource">
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef> Name </mat-header-cell>
<mat-cell *matCellDef="let user"> {{user.name}} </mat-cell>
</ng-container>
<ng-container matColumnDef="email">
<mat-header-cell *matHeaderCellDef> E-Mail </mat-header-cell>
<mat-cell *matCellDef="let user"> {{user.email}} </mat-cell>
</ng-container>
<ng-container matColumnDef="phone">
<mat-header-cell *matHeaderCellDef> Phone </mat-header-cell>
<mat-cell *matCellDef="let user"> {{user.phone}} </mat-cell>
</ng-container>
<ng-container matColumnDef="company">
<mat-header-cell *matHeaderCellDef> Company </mat-header-cell>
<mat-cell *matCellDef="let user"> {{user.company.name}} </mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
</mat-table>
</div>
I will display 4 columns , and colour of the row should be changed according to status
please help me
thank you.
Make the following change
html
change mat-row as
<mat-row *matRowDef="let row; columns: displayedColumns;" [ngStyle]="{'background-color': getRowColor(row)}"></mat-row>
ts
getRowColor(row){
if (row.status_1 === '1') {
return "red";
} else if (row.status_2 === '1') {
return "green";
}
}
You need to use [ngStyle] to specify your conditions. Assuming the entire listing you gave is your row, add the directive to your outermost <div>, like this:
<div [ngStyle]="{ 'background-color': status_1 === '1' ? 'red' : (status_2 === '1' ? 'green' : 'auto') }">
<mat-table [dataSource]="dataSource">
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef> Name </mat-header-cell>
<mat-cell *matCellDef="let user"> {{user.name}} </mat-cell>
</ng-container>
<ng-container matColumnDef="email">
<mat-header-cell *matHeaderCellDef> E-Mail </mat-header-cell>
<mat-cell *matCellDef="let user"> {{user.email}} </mat-cell>
</ng-container>
<ng-container matColumnDef="phone">
<mat-header-cell *matHeaderCellDef> Phone </mat-header-cell>
<mat-cell *matCellDef="let user"> {{user.phone}} </mat-cell>
</ng-container>
<ng-container matColumnDef="company">
<mat-header-cell *matHeaderCellDef> Company </mat-header-cell>
<mat-cell *matCellDef="let user"> {{user.company.name}} </mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
</mat-table>
</div>
I would argue the expression should be in a function, which will be nicer to read and easier to maintain. Given
getColor() {
if (status_1 === '1') {
return 'red';
} else if (status_2 === '1') {
return 'green';
}
}
You can change your <div> to use:
<div [ngStyle]="{ 'background-color': getColor() }">