如何正确地将Angular项目重构为功能模块?

时间:2018-10-14 01:38:32

标签: javascript angular typescript refactoring ng-modules

我正在使用Angular 6,Angular Material和Angular CLI构建自己的Web应用程序。最初,它只有一个模块,随着开发的进行,我决定重构:添加功能模块并将现有功能组件放入不同的功能模块中,以应对不断增加的复杂性。我所做的是:

  1. 使用角度CLI命令添加模块:ng g m ai --module app --routing
  2. 将组件声明放入ai.module.ts中,并删除app.module.ts中的原始声明
  3. 将路由路径放入ai-routing.module.ts中,并删除app.module.ts中的原始路由路径。
  4. 将所有必要的共享服务,管道等导入模块

问题是:我什至不能使这个第一个新功能模块正常工作。浏览器控制台中发生错误:ERROR TypeError: Cannot read property 'description' of undefined,其中“描述”是Observable的属性,我使用异步管道将其插值到模板中。而且仅显示我的应用程序的某些部分(导航栏和页脚)。

Project Structure

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

0 个答案:

没有答案