2016-10-03 42 views
0

$ mdToast注入我有把$ mdToast(從角材料)的單個實例到一個基類(打字稿)一個具體的問題。我在我的用戶界面中有五個選項卡,並給每個單獨的控制器實例(即單獨注入和ctor聲明)。將$ mdToast聲明移到基類中是有意義的,而不是單獨在各處聲明它。你會看到基類有它自己的「$ inject」,但顯然這已經被派生類中的類所取代。我只是想弄清楚將$ mdToast移動到一個通用基類的最簡潔的方法。什麼是最好的方法?這是我的代碼目前的樣子。單個實例/基類

原帖由$ mdToast行註釋掉:

export class MainController extends BaseController { 
static $inject = [ 
    'tableService', 
    '$mdSidenav', 
    //'$mdToast', 
    '$mdDialog', 
    '$mdMedia', 
    '$mdBottomSheet']; 

constructor(
    private tableService: ITableService, 
    private $mdSidenav: angular.material.ISidenavService, 
    //private $mdToast: angular.material.IToastService, 
    private $mdDialog: angular.material.IDialogService, 
    private $mdMedia: angular.material.IMedia, 
    private $mdBottomSheet: angular.material.IBottomSheetService) { 
    super(); 
    var self = this; 
}} 

用下面的基類。注意在構造函數之外注入$ mdToast和聲明$ mdToast。

export class BaseController { 
static $inject = [ 
    '$mdToast']; 

constructor(
) { 
    var self = this; 
} 

private $mdToast: angular.material.IToastService; 

openToast(message: string): void { 
    this.$mdToast.show(
    this.$mdToast.simple() 
     .textContent(message) 
     .position('top right') 
     .hideDelay(3000) 
); 
}} 

我在其他地方看到了巧妙的使用$注入器,但它對我不起作用。歡迎收到所有回覆!

回答

2

它可能是這樣一個圖案:

export class BaseController { 
    static $inject = [...]; 
    ... 
} 

export class MainController extends BaseController { 
    static $inject = [...BaseController.$inject, 
     ... 
    ]; 

    constructor(...deps) { 
     const superDeps = BaseController.$inject.map((dep, i) => deps[i]); 

     super(...superDeps); 

     const thisDeps = deps.slice(superDeps.length); 
     const thisDepNames = this.constructor.$inject.slice(superDeps.length); 
     ... 


    } 

    ... 
} 

它可以被包裝成用於注射或裝飾爲方便起見一些基類如果使用多於一次或兩次以上,但它始終是大約解析兩個陣列,$injectdeps,並將相關性分配給this

此方法不是類型安全的。

對於打字稿最好是保持事物WET但類型安全的。我們總是希望有父類來第一次的一致性,相關性:

export class BaseController { 
    static $inject = ['$mdToast']; 

    constructor(protected $mdToast: angular.material.IToastService) { ... } 
} 

export class MainController extends BaseController { 
    static $inject = [ 
     '$mdToast' 

     'tableService', 
     ... 
    ]; 

    constructor(
     $mdToast: angular.material.IToastService, 

     private tableService: ITableService, 
     ... 
    ) { 
     super($mdToast); 
    }} 
    ... 
} 
+0

您的聲明中有趣的智慧。你給了我很多考慮。第二個例子仍然需要注入$ mdToast兩次,這是我試圖避免的。我該如何確保從所有繼承自BaseController的類中只獲得$ mdToast的一個實例? (順便說一句,我upvoted) –

+0

杜佩'$ mdToast'在這裏是正確的。無論如何,它將作爲構造函數參數傳遞(這可以用類裝飾器修復,但它不值得這樣做)。但它應該被賦值給'this'只有一次,它不能覆蓋可見性(注意在父類構造函數中有'protected $ mdToast',但在子類構造函數中只有'$ mdToast')。當然,'$ mdToast'只會在每個控制器實例中被注入一次,這個類是否被繼承是無關緊要的,這就是繼承的作用。 – estus

+0

在週末和所有來自颶風馬修的難民期間,我決定實施您的更改,並且完全按照承諾進行工作。我仍然討厭不得不成爲WET,但你對此的評論是保持TypeScript類型安全的最佳方式。我來自一個硬核C++/Java/C#背景,並且在Javascript/TypeScript中這樣思考是我需要比以前更靈活的一個好地方。 –

1

這種方法是一個黑客,肯定的,但它會完成這項工作是一個非常乾燥的方式。利用ES6的導入/導出語句,在需要的地方提供該服務。

export let $injector; 

class injectorConfig { 
    static $inject = ['$injector']; 
    constructor (private $originalInjector) { 
     $injector = $originalInjector; 
    } 
} 

app.config(injectorConfig); 

然後你BaseController.ts文件看起來像這樣

import {$injector} from '../yourfilename'; 

export class BaseController { 
    private $mdToast = $injector.get('$mdToast'); 
    constructor() { 
     var self = this; 
    } 
} 

只是因爲它的工作原理並不意味着你應該依靠它,但像這種情況下,我認爲這種技術是有道理的。請記住,在Angular運行此配置塊之前,$ injector將不可用,因此您不能在提供程序或配置塊運行之前運行的任何其他代碼中使用它。

+0

這看起來像一個乾淨的方式來確保$ mdToast的單例值。謝謝! –