【问题标题】:Angular2: Injecting a provider into a component using a custom decorator or annotation?Angular2:使用自定义装饰器或注释将提供程序注入组件?
【发布时间】:2016-07-27 16:03:13
【问题描述】:

我正在使用简单的TabsProvider 为某些@Pages(Ionic 2 装饰器)在 Ionic 2 中隐藏标签:

tabs.ts

import { Injectable } from 'angular2/core';
import { BehaviorSubject } from 'rxjs';

@Injectable()
export class TabsProvider {
  currentState = new BehaviorSubject<boolean>(true);
  public showTabs(){
    this.currentState.next(true);
  }
  public hideTabs(){
    this.currentState.next(false);
  }
}

标签组件订阅currentStateTabsProvider被注入到各个页面如下:

sample-page.ts:

import {Page} from 'ionic-angular';
import { TabsProvider } from './tabs';

@Page({
  ...
})
export class SamplePage {
  tabsProvider: TabsProvider;

  constructor(tabsProvider: TabsProvider) {
    this.tabsProvider = tabsProvider;
  }

  onPageWillEnter(){
    this.tabsProvider.hideTabs();
  }

  onPageWillLeave(){
    this.tabsProvider.showTabs();
  }
}

这段代码几乎都是样板文件,如果我可以在装饰器(或注释)中定义这个功能会更简洁,例如:

import { Page } from 'ionic-angular';
import { hideTabs } from './tabs';

@hideTabs()
@Page({
  ...
})
export class BuyPage {
}

但我无法确定如何注入 TabsProvider 并将 onPageWillEnteronPageWillLeave 方法添加到 SamplePage。

装饰器(或注释)能否以某种方式注入额外的 Angular 提供程序?

到目前为止我走的最远:

tabs.ts:

export function hideTabs() {
  return function(cls: any) {
    cls.prototype.onPageWillEnter = function() {
      this.tabsProvider.hideTabs();
    };
    cls.prototype.onPageWillLeave = function() {
      this.tabsProvider.showTabs();
    };
    return cls;
  }
}

这让我们得到了我们正在寻找的一部分,但仍然需要导入和注入 TabsProvider 作为特定实例成员:

sample-page.ts

import {Page, Events} from 'ionic-angular';
import { hideTabs, TabsProvider } from './tabs';

@hideTabs()
@Page({
  ...
})
export class SamplePage {
  constructor(public tabsProvider: TabsProvider) {
  }
}

是否可以将其完全抽象为@hideTabs()

编辑:

标签组件的相关部分(适用于任何有兴趣实现的人)pages/tabs/tabs.ts

import { Page } from 'ionic-angular';
import { TabsProvider } from './tabs';

@Page({
  ...
})
export class TabsPage {

  ...

  currentState: boolean;
  constructor(TabsProvider: TabsProvider) {
    TabsProvider.currentState.subscribe((state: boolean) => {
      this.currentState = state;
    });
  }
}

pages/tabs/tabs.html:

<div [ngClass]="{'hide-tabs': !currentState}">
  <ion-tabs>
    ...
  </ion-tabs>
</div>

pages/tabs/tabs.scss:

.hide-tabs ion-tabbar-section {
    display: none;
}

【问题讨论】:

    标签: angularjs typescript angular ionic2 angular2-services


    【解决方案1】:

    我刚刚遇到了同样的问题,这就是我想出的解决方案。一般的做法是:

    • 使用Reflect.getOwnMetadata 从类中读取现有依赖项。
    • 添加到依赖列表
    • 创建一个新的构造函数来包装旧构造函数并处理这些依赖关系。

    tabs.ts:

        import TabsProvider from "./tabs";
    
        export function hideTabs() {
          return function(cls: Function) : any {
    
            // Save existing onPageWillEnter and onPageWillLeave inplementations
            let enter = cls.prototype.onPageWillEnter || function () {};
            let leave = cls.prototype.onPageWillLeave || function () {};
    
            // Create new constructor for class
            const newCls = function (tabsProvider, ...args) {
                this.__hideTabs__tabsProvider = tabsProvider;
                return cls.apply(this, args);
            }
    
            // Copy prototype to new constructor
            newCls.prototype = constructor.prototype;
    
            // Copy metadata to new constructor
            let metadatakeys = Reflect.getMetadataKeys(cls);
            metadatakeys.forEach(function (key) {
              Reflect.defineMetadata(key, Reflect.getOwnMetadata(key, cls), newCls)
            });
    
            // Read dependencies list from 'cls', add our own dependency, and write list to 'newCls'
            let dependencies = Reflect.getOwnMetadata('design:paramtypes', cls);
            dependencies = [TabsProvider].concat(dependencies)
            Reflect.defineMetadata('design:paramtypes', params, newCls);
    
            // Define new onPageWillEnter and onPageWillLeave implementation which implement tab show/hide functionality
            // and also call the old implementation saved above (if they exist)
            newCls.prototype.onPageWillEnter = function() {
              this.tabsProvider.hideTabs();
              enter.apply(this, arguments);
            };
    
            newCls.prototype.onPageWillLeave = function() {
              this.tabsProvider.showTabs();
              leave.apply(this, arguments);
            };
    
            return newCls;
          }
        }
    

    我还建议将 @hideTabs 装饰器移到 @Page 装饰器下方

    【讨论】:

    • 你,先生,真是个天才!想法很棒,我相信这是正确的方法。谢谢!
    猜你喜欢
    • 2020-07-31
    • 1970-01-01
    • 2018-07-30
    • 2018-04-15
    • 1970-01-01
    • 1970-01-01
    • 2016-12-06
    • 2013-09-28
    • 2018-10-14
    相关资源
    最近更新 更多