2016-10-03 82 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的单例值。谢谢! –