Reputation: 135
Whenever I use tag mat-expansion-panel-header in html I get error in console.
Using https://material.angular.io/components/expansion/overview basic expansion panel example.
ERROR TypeError: Cannot read property 'pipe' of undefined
at new MatExpansionPanelHeader (expansion.es5.js:326)
at createClass (core.js:9103)
at createDirectiveInstance (core.js:8978)
at createViewNodes (core.js:10198)
at callViewAction (core.js:10514)
at execComponentViewsAction (core.js:10433)
at createViewNodes (core.js:10226)
at createRootView (core.js:10112)
at callWithDebugContext (core.js:11143)
at Object.debugCreateRootView [as createRootView] (core.js:10630)
View_TrainingOptionsComponent_0 @ TrainingOptionsComponent.html:25
I have MatExpansionModule in module.ts.
Versions in package.json:
<div fxLayoutAlign="space-between stretch" class="options-list-container">
<div class="options-list">
<mat-divider class="mat-divider"></mat-divider>
<mat-accordion *ngFor="let option of filteredHeaders" class="option mat-accordion" data-id="{{option.id}}">
<mat-expansion-panel #optionPanel>
<mat-expansion-panel-header class="mat-expansion-panel-header">
<mat-panel-title fxFlex.lg="70" fxFlex.xs="70" fxFlex.md="70">
{{option.title}}
</mat-panel-title>
<mat-panel-title fxFlex.lg="15" fxFlex.xs="70" fxFlex.md="70">
{{option.dateFrom | date:'dd-MM-yyyy'}}
</mat-panel-title>
<mat-panel-title class="status" fxFlex.lg="15" fxFlex.xs="15">
{{option.price}} + ~{{option.additionalPrice}} EUR
</mat-panel-title>
</mat-expansion-panel-header>
<app-option-details *ngIf="optionPanel._getExpandedState() === 'expanded'"
[id]="option.id"
(dateEmitter)="getDates($event)">
</app-option-details>
<div fxFlex="100" fxLayout="row" fxLayoutAlign="end center">
<div fxFlex="50" fxLayout.lt-lg="100" fxLayoutAlign="start center">
<button mat-raised-button color="primary" (click)="openEditOption(option.id); editMode = true">EDIT OPTION</button>
</div>
<div fxFlex="100" fxLayout.lt-lg="100" fxLayoutAlign="end center">
<button mat-raised-button color="primary" (click)="openDialog(option);">APPLY</button>
</div>
</div>
</mat-expansion-panel>
</mat-accordion>
</div>
</div>
component.ts
import { Component, OnInit } from '@angular/core';
import { trigger, style, animate, transition } from '@angular/animations'
import { HttpErrorResponse } from '@angular/common/http';
import { Observable } from 'rxjs';
import { MatDialog } from '@angular/material';
import { ITrainingOption } from '../shared/trainingOption.model';
import { ISelector } from '../shared/selector.model';
import { IOptionHeader } from '../shared/optionHeader.model';
import { ApiService } from '../shared/api.service';
import { FormGroup, FormControl } from '@angular/forms';
import { ApplicationsComponent } from './applications/applications.component';
import { MomentDateAdapter, MAT_MOMENT_DATE_ADAPTER_OPTIONS } from '@angular/material-moment-adapter';
import { DateAdapter, MAT_DATE_FORMATS, MAT_DATE_LOCALE } from '@angular/material/core';
export const dateFormat = {
parse: {
dateInput: 'l',
},
display: {
dateInput: 'l',
monthYearLabel: 'MMM YYYY',
dateA11yLabel: 'l',
monthYearA11yLabel: 'MMMM YYYY',
},
};
export interface IIsInternalSelect {
value: boolean;
viewValue: string;
}
@Component({
selector: 'app-options',
templateUrl: './training-options.component.html',
styleUrls: ['./training-options.component.scss'],
providers: [
{
provide: DateAdapter,
useClass: MomentDateAdapter,
deps: [MAT_DATE_LOCALE, MAT_MOMENT_DATE_ADAPTER_OPTIONS, MAT_DATE_FORMATS]
},
{
provide: MAT_DATE_FORMATS,
useValue: dateFormat
},
{ provide: MAT_DATE_LOCALE, useValue: 'en-GB' },
{ provide: MAT_MOMENT_DATE_ADAPTER_OPTIONS, useValue: { useUtc: true } }
],
animations: [
trigger(
'enterAnimation', [
transition(':enter',
[
style({ transform: 'translateX(100%)' }),
animate('400ms', style({ transform: 'translateX(0)' }))
]),
transition(':leave', [
style({ transform: 'translateX(0)' }),
animate('200ms', style({ transform: 'translateX(100%)' }))
])
]
)
],
})
export class TrainingOptionsComponent implements OnInit {
constructor(private apiService: ApiService, public dialog: MatDialog) { }
ngOnInit(): void {
this.getCategories();
this.getEventTypes();
this.getHeaders();
}
form = new FormGroup({
id: new FormControl(),
title: new FormControl(),
link: new FormControl(),
description: new FormControl(),
categoryId: new FormControl(),
periodFrom: new FormControl(),
periodTo: new FormControl(),
price: new FormControl(),
additionalPrice: new FormControl(),
eventTypeId: new FormControl(),
isInternal: new FormControl(),
isFullDay: new FormControl(),
createdById: new FormControl()
});
isAddOptionShown: boolean;
minDateFrom: Date = new Date();
minDate: Date;
maxDate: Date;
categories: ISelector[] = [];
eventTypes: ISelector[] = [];
headers: IOptionHeader[] = [];
filteredHeaders: IOptionHeader[] = [];
optionDates: Date[] = [];
organizerTypes: IIsInternalSelect[] = [
{ value: true, viewValue: 'Internal' },
{ value: false, viewValue: 'External' }
];
openDialog(option: IOptionHeader): void {
this.dialog.open(ApplicationsComponent, {
data: {
opt: option,
dates: this.optionDates
}
});
}
set searchString(value: string) {
this.filteredHeaders = value ? this.performFilter(value) : this.headers;
}
performFilter(filterBy: string): IOptionHeader[] {
filterBy = filterBy.toLocaleLowerCase();
return this.headers.filter((header: IOptionHeader) =>
header.title.toLocaleLowerCase().indexOf(filterBy) !== -1);
}
submitOption(option: ITrainingOption) {
this.apiService.addOrUpdateOption(option).subscribe(() => {
this.isAddOptionShown = false;
this.getHeaders();
});
}
getHeaders() {
this.apiService.getTrainingOptionHeaders().subscribe(
x => {
this.headers = x;
this.filteredHeaders = x;
}
);
}
getCategories() {
this.apiService.getCategories().subscribe(
categories => {
this.categories = categories;
});
}
getEventTypes() {
this.apiService.getEventTypes().subscribe(
eventTypes => {
this.eventTypes = eventTypes;
});
}
openEditOption(editOptionId: number) {
this.apiService.getTrainingOption(editOptionId).subscribe(x => {
this.form.setValue({
'id': x.id,
'title': x.title,
'description': x.description,
'link': x.link,
'categoryId': x.categoryId,
'eventTypeId': x.eventTypeId,
'isInternal': x.isInternal,
'price': x.price,
'additionalPrice': x.additionalPrice,
'periodFrom': x.periodFrom,
'periodTo': x.periodTo,
'isFullDay': x.isFullDay,
'createdById': x.createdById
});
this.isAddOptionShown = true;
this.minDateFrom = x.periodFrom;
this.minDate = x.periodFrom;
this.maxDate = x.periodTo;
});
}
getDates(dates: Date[]) {
this.optionDates = dates;
}
resetForm() {
this.form.setValue({
'id': 0,
'title': '',
'description': '',
'link': '',
'categoryId': '',
'eventTypeId': '',
'isInternal': false,
'price': 0,
'additionalPrice': 0,
'periodFrom': null,
'periodTo': null,
'isFullDay': false,
'createdById': '.'
});
this.minDateFrom = new Date();
this.minDate = this.minDateFrom;
this.maxDate = null;
}
}
module.ts
import {
MatExpansionModule,
MatButtonModule,
MatButtonToggleModule,
MatInputModule,
MatToolbarModule,
MatIconModule,
MatListModule,
MatSelectModule,
MatDatepickerModule,
MatNativeDateModule,
} from '@angular/material';
import { MatChipsModule } from '@angular/material/chips';
import { CoreModule } from '../core/core.module';
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { TrainingOptionsComponent } from './training-options.component';
import { FlexLayoutModule } from '@angular/flex-layout';
import { MatCardModule } from '@angular/material/card';
import { CommonModule } from '@angular/common';
import { MatCheckboxModule } from '@angular/material/checkbox';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { ApplicationsComponent } from './applications/applications.component';
import { TrainingRequestsModule } from '../training-requests/training-requests.module';
export const appRoutes: Routes = [
{ path: '', component: TrainingOptionsComponent },
{ path: 'application', component: ApplicationsComponent }
];
@NgModule({
imports: [
MatCardModule,
FlexLayoutModule,
MatButtonModule,
MatButtonToggleModule,
MatInputModule,
MatToolbarModule,
MatIconModule,
MatCheckboxModule,
MatListModule,
MatChipsModule,
MatSelectModule,
MatDatepickerModule,
MatNativeDateModule,
MatExpansionModule,
CoreModule,
CommonModule,
RouterModule.forChild(appRoutes),
FormsModule,
ReactiveFormsModule,
TrainingRequestsModule
],
declarations: [TrainingOptionsComponent, ApplicationsComponent],
exports: [],
})
export class TrainingOptionsModule { }
EDIT: Added code. For a record, doesn't work even if I change html to basic expansion panel example's html. Link is in second line.
Upvotes: 1
Views: 10674
Reputation: 7331
The probable cause is that you have a mismatch in @angular/material
and @angular/cdk
versions.
They need to be exactly the same version.
Source: Github issue comment
Upvotes: 1
Reputation: 5732
It might be helpful to share your HTML structure and you TypeScript code as well for that component.
In the most basic scenario you just would have to import and export the MatExpansionModule
on you module.ts, after that you just need to write the correct HTML tag inside an <mat-expansion-panel>
tag.
It seems you are trying to use a Pipe on an piece of information that's not properly defined. So as I said, it would help a lot if you share what your HTML looks like.
Upvotes: 0