1

タブセットを作成できるサードパーティのライブラリを使用しています。これは、単純なタブセットを作成するために使用しているコードです

<clr-tabs           
   (clrTabsCurrentTabContentChanged)="onTabContentActivated($event)" >

  <clr-tab-link>Firewall</clr-tab-link>
  <clr-tab-link>DHCP</clr-tab-link>

  <clr-tab-content>
      <vcd-firewall-tab></vcd-firewall-tab>
  </clr-tab-content>

  <clr-tab-content>
     <vcd-dhcp-tab></vcd-dhcp-tab>
  </clr-tab-content>
</clr-tabs>

loadData()タブが選択されたときに通知するイベントをフックしました。そのメソッドを<vcd-firewall-tab>と で呼び出したいと思います<vcd-dhcp-tab>

は、選択された へのclrTabsCurrentTabContentChanged参照を提供しますが、その最初の子にアクセスして、遅延読み込みを実装するためclr-tab-contentに呼び出したいと思います。loadData()

@QueryChildrenクエリする要素のタイプを指定する必要があることを除いて、注釈を使用できると思います。問題は、この場合、タイプがわからないことです。または、他の多くのタブである可能性があり<vcd-firewall-tab><vcd-dhcp-tab>新しいタブを追加するたびにカスタム コードを追加したくありません。

イベントハンドラーからこのようなことができることを望んでいました(しかし、それは存在しません

onTabContentActivated(tabContent: TabContent){
    (tabContent.query(':first-child') as CanLoadData).loadData();
}

@QueryChildren('clr-tab-content > *')各タブの下に子が1つしかないと仮定して、タブのインデックスを のようなものに一致させることができると思いました。

4

2 に答える 2

2

サポートされている方法は 2 つだけです

  • コンポーネントまたはディレクティブの型を渡す
  • テンプレート変数の名前を渡す

他の要件についてElementRefは、DOM を直接挿入してアクセスできますElementRef.nativeElement....が、この方法ではコンポーネントやディレクティブではなく要素のみを取得します。

于 2016-10-07T14:29:17.390 に答える
1

ギュンターが述べたように、質問に対する本当の答えは、それはできないということです。タイプが事前にわからない場合は、クエリを実行できません。

この特定の問題に対する解決策をハックし、2 つのことを行うことで、各タブに追加するコードの量を最小限に抑えました。

  • の子要素で DOM イベントを発生させる、タブセットに追加できるディレクティブを作成します<clr-tab-contents>
  • loadData()DOM イベントのフックアップを行い、タブがアクティブになったときに を自動的に呼び出す関数を作成する

これを実装する最小限の例を次に示します。それは非常に粗雑です。私の実際のコードは他のコーナー ケースを処理しますが、ソリューションにノイズを追加したくありませんでした。

<!-- One piece of glue per tabset -->
<clr-tabs vcd-lazy-tab-loader>
  <clr-tab-link>Firewall</clr-tab-link>
  <clr-tab-link>DHCP</clr-tab-link>

  <clr-tab-content>
      <vcd-firewall-tab></vcd-firewall-tab>
  </clr-tab-content>

  <clr-tab-content>
     <vcd-dhcp-tab></vcd-dhcp-tab>
  </clr-tab-content>
</clr-tabs>

// lazy-tab-loader.directive.ts
@Directive({
  selector: '[vcd-lazy-tab-loader]'
})

export class VcdLazyTabLoader {  
  constructor(@Inject(forwardRef(() => Tabs)) private tabSet: Tabs,
              private el: ElementRef) {
    tabSet.currentTabIndexChanged.subscribe((tabIndex) => {
      // Not very pretty, we'll find a nicer way later
      // It relies on the internal HTML structure of clr-tab-content
      const element = this.el.nativeElement.querySelectorAll(`clr-tab-content`)[tabIndex]                      
            .firstElementChild.firstElementChild;
      element.dispatchEvent(new CustomEvent("vcd-activated", {}));
    });
  }
}

export interface CanLoadData {
  loadData(): void;
}

export function setupLazyLoader(el: HTMLElement, dataLoader: CanLoadData) {
  el.addEventListener('vcd-activated', () => {
    dataLoader.loadData();
  });
}

// firewall-tab.component.ts (AND dhcp-tab.components.ts)
@Component(...)
// First piece of glue (implement CanLoadData) for a tab
class FirewallTab implements CanLoadData {

  constructor(private firewallService: FirewallService,
              private el: ElementRef) {
      // Second piece of glue, per tab
      // Constructor is not the best place, it's here just to avoid extra code
      setupLazyLoader(el.nativeElement, this);
  }
  loadData () {
    this.service.getRules().subscribe((data)=> this.rules = rules);
  }
}
于 2016-10-07T21:30:49.453 に答える