あなたを驚かせるかもしれない角度テクニック


私がこの仕事を構造化するのを手伝ってくれてありがとう.

私は最近特定の要件を持って角アプリケーションに取り組んでいた.アプリケーションシェルは特定のルートの下でモジュールをロードします.各モジュールは、アプリケーションシェルツールバーで項目を公開する機能を持つ必要があります.つの同僚と我々は我々がそれを達成する方法を議論した.
あなたが行動でそれを見るのを待つことができないならば、ここでRepoへのリンクです:https://github.com/kevinmerckx/ng-feature-extension

最初の素朴な試み
角cdkとそのポータルapiを用いて考察した.制限はかなり速く現れました:機能がモジュールによってロードされるとき、機能モジュールのルート構成要素のテンプレートの範囲内で、メニュー項目宣言は評価されるだけです.したがって、この方法は適していない.
私たちは、ロードされる全体の機能モジュールなしで、このツールバー項目を宣言する「オフライン」方法を必要とします.

解決策
私が提案する解決策は3つの柱に基づいている.
  • 射出トークン
  • 拡張モジュール
  • コンポーネントアウトレット
  • まず、各柱を説明しましょう.

    射出トークン
    射出トークンは角度の重要な部分です.彼らは開発者にアプリケーションを拡張する機会を与える.たとえば、使用するバリデータとしてディレクティブを宣言するにはNG_VALIDATORS . カスタムコントロール値アクセサー(cf .)を宣言する場合は、NG_VALUE_ACCESSOR . それらを使用すると、角はあなたにそのAPIを拡張する能力を与えます.

    拡張モジュール
    機能モジュールを作成するときは、通常、1つの角モジュールをエクスポートすることによって行います.その後、メインモジュールでは、lazilyまたはそれをロードします.機能モジュールをいくつかの小さなモジュールに分割することができます.あなたの機能のシェルを1つのモジュールを介して提供し、機能の小さなセットを提供する別の1つをエクスポートできます.後の種類の拡張モジュールを呼び出しましょう.

    コンポーネントアウトレット
    このAPIは角度で提供され、開発者にテンプレート内のコンポーネントを注入する機能を提供します.
    <ng-container *ngComponentOutlet="theComponentToLoad"></ng-container
    
    これらの3つの柱で、機能モジュールがシェルアプリケーションで提供された拡張APIをオフラインで使用できるようにするメカニズムを作成できます.
    まず、機能モジュールの拡張を実装するインターフェイスを宣言する必要があります.
    たとえば、モジュールをアプリケーションツールバーに項目を追加できるようにするには、次のようになります.
    import { Type } from '@angular/core';
    import { Observable } from 'rxjs';
    
    export interface Extension {
      toolbarItem: Type<any>;
      route: Observable<string>; // here we also provide the route to load when the item is clicked
    }
    
    次に、各機能モジュールが提供することができます注入トークンを宣言する必要があります.それを呼びましょうFEATURE_EXTENSION .
    import { InjectionToken } from '@angular/core';
    
    export const FEATURE_EXTENSION = new InjectionToken('FEATURE_EXTENSION');
    
    今私たちのために可能ですtoolbar このトークンをランタイムで使用するコンポーネント
    import { Component, Inject } from '@angular/core';
    import { Extension, FEATURE_EXTENSION } from '../shared';
    
    @Component({
      selector: 'toolbar',
      templateUrl: './toolbar.component.html',
      styleUrls: ['./toolbar.component.css'],
    })
    export class ToolbarComponent {
      constructor(@Inject(FEATURE_EXTENSION) public extensions: Extension[]) {}
    }
    
    現在使用する時間ですngComponentOutlet ツールバーテンプレートからの指示:
    <div
      *ngFor="let extension of extensions"
      tabIndex="0"
      [routerLink]="extension.route | async"
      [routerLinkActive]="'active'"
      [routerLinkActiveOptions]="{ exact: true }"
    >
      <ng-container *ngComponentOutlet="extension.toolbarItem"></ng-container>
    </div>
    
    私たちのアプリケーションのシェルとツールバーが機能拡張モジュールを受信する準備ができました!
    モジュールを「計画」モジュールと呼びましょう.このモジュールは二つのことから成ります:
  • ルートに応じてコンポーネントを読み込む古典的な機能シェルモジュール:PlanningShellModule
  • 軽量拡張モジュールPlanningExtensionModule
  • The PlanningShellModule 特に何も持たず、ルータ(optionnaly lazily)によってロードされます.The PlanningExtensionModule は以下のように宣言されます:
    import { CommonModule } from '@angular/common';
    import { NgModule } from '@angular/core';
    import { of } from 'rxjs';
    import { Extension, FEATURE_EXTENSION, ToolbarItemModule } from 'path/to/some/shared/folder';
    import { PlanningToolbarItemComponent } from './planning-toolbar-item.component';
    
    @NgModule({
      imports: [CommonModule, ToolbarItemModule],
      providers: [
        {
          provide: FEATURE_EXTENSION,
          useValue: {
            toolbarItem: PlanningToolbarItemComponent,
            route: of('planning'),
          } as Extension,
          multi: true
        },
      ],
    })
    export class PlanningExtensionModule {}
    
    最も重要な部分はproviders 提供するプロパティFEATURE_EXTENSION 我々のツールバー項目コンポーネントで値PlanningToolbarItemComponent ロードし、クリックしたときに移動するルートを指定します.使用に注意multi: true これは、他の機能モジュールからこのプロバイダを数回宣言できることを確認します!
    The PlanningToolbarItemComponent で指定できるすべてのコンポーネント、ディレクティブ、パイプを使用できますToolbarItemModule .
    これで、機能拡張モジュールからアプリケーションシェルのツールバーにカスタムコンテンツを表示できます.
    このリポジトリをチェックしてくださいhttps://github.com/kevinmerckx/ng-feature-extension この完全に機能の証明の完全なコードのために.スクリーンショットはこちら

    トップのツールバーで、3つの項目で.プランとコードは、それぞれの拡張モジュールによって提供されるカスタマイズされたツールバー項目を使用します.
    まとめるInjectionToken with multi: true , ngComponentOutlet そして、機能モジュールをシェルと拡張モジュールに分割することによって、我々は機能モジュールのために良い方法を提供しましたExtension インターフェイス.
    km
    写真でLance Anderson on Unsplash