带有抽象类的Angular库模块注入服务

时间:2018-08-15 12:49:31

标签: angular typescript

我创建了一个Angular Component Library,并通过NPM(通过Nexus)将其分发到几个类似的项目。它包含一个PageComponent,后者又包含一个FooterComponent和一个NavbarComponent。在NavbarComponent中存在一个按钮,该按钮触发logout功能。该功能将通过相应项目的PageService提供。为此,我在Angular Component库中创建了一个AbstractPageServicePageService扩展了AbstractPageService)。

首先,我通过EventEmitter解决了这个问题。但是由于我必须为每个新页面提供一个logout函数,所以我想通过每个项目一个服务来解决这个问题。我使用Angular Component Library的PageService方法传递了forRoot()(项目)。

一切正常,但是想知道是否有更好的解决方案,或者该解决方案是否值得推荐?

我是Angular的新手,但我还是有点不安全。我希望你明白我想要的。我的英语不是最好的。 :D

我对此有以下解决方案:

组件库-components.module.ts

import {ModuleWithProviders, NgModule} from '@angular/core';
import {CommonModule} from '@angular/common';
import {RouterModule} from '@angular/router';
import {FontAwesomeModule} from '@fortawesome/angular-fontawesome';

    
import {NavbarComponent} from './layout/navbar/navbar.component';
import {PageComponent} from './layout/page/page.component';
import {PageHeaderComponent} from './components/page-header/page-header.component';
// ... others ...

@NgModule({
  imports: [
    CommonModule,
    RouterModule,
    FontAwesomeModule
  ],
  declarations: [
    NavbarComponent,
    PageComponent,
    // ... others ...
  ],
  exports: [
    NavbarComponent,
    PageComponent,
    // ... others ...
  ]
})
export class ComponentsModule {
  static forRoot(pageService): ModuleWithProviders {
    return {
      ngModule: ComponentsModule,
      providers: [
        {provide: 'PageService', useClass: pageService}
      ]
    };
  }
}

组件库-page.component.ts

import {Component, EventEmitter, HostBinding, Inject, Input, Output} from '@angular/core';
import {AbstractPageService} from '../../services/abstract-page.service';

@Component({
  selector: 'dc-page',
  templateUrl: './page.component.html',
  styleUrls: ['./page.component.scss']
})
export class PageComponent {

  @HostBinding('class') styleClass = 'd-flex flex-column';

  @Input() customStyleClass = null;

  @Input() showLogoutButton = true;
  // @Output() logoutButtonClick: EventEmitter<any> = new EventEmitter();

  constructor(@Inject('PageService') protected pageService: AbstractPageService) {
  }

  logout(): void {
    this.pageService.logout();
  }
}

组件库-abstract-page.service.ts

import {Injectable} from '@angular/core';

@Injectable()
export abstract class AbstractPageService {

  abstract logout(): void;

}


这里是项目中的用途:

项目-app.module.ts

import {BrowserModule} from '@angular/platform-browser';
import {NgModule} from '@angular/core';

import {AppComponent} from './app.component';
import {RouterModule, Routes} from '@angular/router';
import {FontAwesomeModule} from '@fortawesome/angular-fontawesome';

import {ComponentsModule} from 'components';

const appRoutes: Routes = [
  {path: '', component: AppComponent},

  // otherwise redirect to home
  {path: '**', redirectTo: ''}
];


@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    FontAwesomeModule,
    RouterModule.forRoot(appRoutes),
    ComponentsModule.forRoot(PageService),
  ],
  providers: [
    // {provide: 'PageService', useClass: PageService}
  ],
  bootstrap: [AppComponent]
})
export class AppModule {
}

项目-page.service.ts

import {Injectable} from '@angular/core';
import {AbstractPageService} from '../../../projects/components/src/lib/services/abstract-page.service';

@Injectable({
  providedIn: 'root'
})
export class PageService extends AbstractPageService {

  constructor() {
    super();
  }

  logout() {
    console.log('Ausloggen!');
  }
}

4 个答案:

答案 0 :(得分:6)

我使用了这种方法,但是遇到了一个问题:

PageService与应用程序中的库中的string不同。由于它是在多个模块(应用程序模块和库模块)中提供的,因此会创建一个新的每个模块的实例。

我最终要做的是通过应用程序模块中的// app.module.ts in the root application providers: [ { provide: 'PageService', useClass: PageService } ] 提供服务:

@Inject()

然后使用// anywhere in the root application where the service is needed constructor(@Inject('PageService') private pageService: PageService) {}

在需要的地方注入服务
export interface AbstractPageService {
  logout(): void;
}

然后,在中,我创建了一个简单的界面:

Inject()

然后,我可以简单地通过// anywhere in the library where the service is needed constructor(@Inject('PageService') private pageService: AbstractPageService) {} 装饰器将服务注入到库中,然后使用该接口键入该服务(无需在根应用程序中实现该接口):

PageService

现在,根应用程序都使用与根应用程序相同的AWSRequestSigningApacheInterceptor的单例实例。

答案 1 :(得分:1)

重用单例

在应用程序 appModule.ts 中提供

{ provide: 'currentCompanyService', useFactory: getCompanyServiceFactory, deps: [AppInitService]}

创建只返回注入实例的工厂。

export function getCompanyServiceFactory(appInitService: AppInitService): AppInitService {
 return appInitService;
}

注入库组件

public CustomLibraryComponent {

   private companyService: AppInitService;

   constructor(@Inject('currentEnvironment') environment: any,
               @Inject('currentCompanyService') companyService: AppInitService) {
       this.environment = environment;
       this.companyService = companyService;
   }
}

答案 2 :(得分:0)

如Sunil Singh所说,解决方案是普通的抽象类(没有@Injectable)。

export abstract class AbstractPageService {

  abstract logout(): void;

}

答案 3 :(得分:0)

我认为应该有“ useValue”而不是“ useClass”。

export class ComponentsModule {
  static forRoot(pageService): ModuleWithProviders {
    return {
      ngModule: ComponentsModule,
      providers: [
        {provide: 'PageService', useClass: pageService}
      ]
    };
  }
}