我正在使用Angular 6,Angular Material和Angular CLI构建自己的Web应用程序。最初,它只有一个模块,随着开发的进行,我决定重构:添加功能模块并将现有功能组件放入不同的功能模块中,以应对不断增加的复杂性。我所做的是:
ng g m ai --module app --routing
ai.module.ts
中,并删除app.module.ts中的原始声明ai-routing.module.ts
中,并删除app.module.ts中的原始路由路径。问题是:我什至不能使这个第一个新功能模块正常工作。浏览器控制台中发生错误:ERROR TypeError: Cannot read property 'description' of undefined
,其中“描述”是Observable的属性,我使用异步管道将其插值到模板中。而且仅显示我的应用程序的某些部分(导航栏和页脚)。
My app in browser after I added new ngModule, there are error messages in the console
Detailed error messages, they're repeating
那么有人可以指导我如何正确重构我的项目吗?这是相关代码,在此先谢谢您!
aiservice.component.ts
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, ParamMap } from '@angular/router';
import { map, tap } from 'rxjs/operators';
import { AimodelService } from '../../shared/services/aimodel.service';
import { ModelCategory, modelcategories } from
'../../shared/models/categoryAndReceipt.model';
import { Observable } from 'rxjs';
@Component({
selector: 'app-aiservice',
templateUrl: './aiservice.component.html',
styleUrls: ['./aiservice.component.scss']
})
export class AiServiceComponent implements OnInit {
modelCategories: ModelCategory[];
modelList: Object[];
displayModelList$: Observable<Object[]> = new Observable();
selectedCategory$: Observable<ModelCategory>;
constructor(
private aimodelservice: AimodelService,
private route: ActivatedRoute
) {}
public ngOnInit() {
console.log('init');
this.selectedCategory$ = this.route.paramMap.pipe(
map((params: ParamMap) => {
return modelcategories.find(
category => category.abbr === params.get('abbr')
);
}),
tap(category => {
this.displayModelList$ = this.aimodelservice.getModel().pipe(
map(models =>
models.filter(model => {
return model['category'] === category.categoryId;
}).reverse()
)
);
})
);
}
}
aiservice.component.html:
<div fxLayout="column" fxLayoutAlign="space-between">
<div fxFlex>
<h1>{{(selectedCategory$ | async).title}}
<mat-icon matTooltipClass="appTooltip" matTooltipShowDelay=500 [matTooltip]='(selectedCategory$ | async).description'
matTooltipPosition='after' color="primary">
contact_support
</mat-icon>
</h1>
</div>
<div id="services" fxLayout="column">
<mat-accordion fxFlex *ngFor="let model of displayModelList$ | async;let i=index">
<mat-expansion-panel #i (mouseenter)="i.open()" (mouseleave)="i.close()" (opened)="panelOpenState = true"
(closed)="panelOpenState = false">
<mat-expansion-panel-header class="panelheader" fxLayout="row" fxLayoutAlign="start">
<mat-panel-title fxFlex="35vw">
<h4>
<mat-icon color="primary">offline_bolt</mat-icon> {{model.title}}
</h4>
</mat-panel-title>
<mat-panel-description fxFlex="35vw" fxLayout="row" fxLayoutAlign="start">
<span fxFlex="70%"></span>
<mat-icon fxFlexAlign="center" color="primary">account_balance_wallet</mat-icon>
<span fxFlexAlign="center">COST:{{model.price}} FRS</span>
</mat-panel-description>
</mat-expansion-panel-header>
<div fxLayout="column">
<p fxFlex>{{model.description}}</p>
<div fxLayout="row">
<button mat-raised-button [routerLink]="[model.id]" fxFlex="8rem" fxFlexOffset="83%" mat-button>
<mat-icon color="primary">attach_money</mat-icon>Purchase
</button>
</div>
</div>
</mat-expansion-panel>
</mat-accordion>
</div>
</div>
ai-routing.module.ts:
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { AiServiceComponent } from './aiservice/aiservice.component';
const routes: Routes = [
{
path: ':abbr',
component: AiServiceComponent
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class AiRoutingModule {}
ai.module.ts:
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { AiRoutingModule } from './ai-routing.module';
import { AiServiceComponent } from './aiservice/aiservice.component';
import { SharedModule } from '../shared/shared.module';
@NgModule({
imports: [
CommonModule,
AiRoutingModule,
SharedModule
],
declarations: [
AiServiceComponent
]
})
export class AiModule { }
app.module.ts:
import { BrowserModule } from '@angular/platform-browser';
import { NgModule, NO_ERRORS_SCHEMA } from '@angular/core';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { RouterModule, Routes } from '@angular/router';
import { OverlayContainer } from '@angular/cdk/overlay';
// project components import
import { AppComponent } from './app.component';
import { UseraccountComponent } from './useraccount/useraccount.component';
import { EDIComponent } from './edi/edi.component';
import { EdiIntroComponent } from './edi-intro/edi-intro.component';
import { Edi2Component } from './edi2/edi2.component';
import { AddModelComponent } from './forms/add-model/add-model.component';
import { PurchaseModelComponent } from './forms/purchase-model/purchase- model.component';
import { TopnavbarComponent } from './topnavbar/topnavbar.component';
import { FooterComponent } from './footer/footer.component';
import { FrsConvertPipe } from './useraccount/frs-convert.pipe';
import { MaterialDesignFrameworkModule } from 'angular6-json-schema-form';
import { AiformModelComponent } from './forms/aiform-model/aiform- model.component';
import { SharedModule } from './shared/shared.module';
import { AiModule } from './ai/ai.module';
const appRoutes: Routes = [
{
path: '',
redirectTo: '/account',
pathMatch: 'full'
},
{
path: 'account',
component: UseraccountComponent
},
{
path: 'add-model',
component: AddModelComponent,
},
{
path: ':abbr/:modelId',
component: PurchaseModelComponent
},
{
path: ':abbr/:modelId/form',
component: AiformModelComponent
}
];
@NgModule({
declarations: [
AppComponent,
UseraccountComponent,
EDIComponent,
EdiIntroComponent,
Edi2Component,
AddModelComponent,
PurchaseModelComponent,
TopnavbarComponent,
FooterComponent,
FrsConvertPipe,
AiformModelComponent,
],
imports: [
RouterModule.forRoot(
appRoutes,
{ enableTracing: false, onSameUrlNavigation : 'reload' } // <--debugging purposes only
),
BrowserModule,
BrowserAnimationsModule,
MaterialDesignFrameworkModule,
SharedModule,
AiModule
],
schemas: [ NO_ERRORS_SCHEMA ],
providers: [],
bootstrap: [AppComponent],
entryComponents: []
})
export class AppModule {
constructor(overlayContainer: OverlayContainer) {
overlayContainer.getContainerElement().classList.add('menu-theme');
}
}