In this post, we are going to see how to solve one design pattern challenge.

The challenge is what we a simplest way to find out the children elements which belongs to Animals, which belongs to Materials inside the container component.

  <app-animals>
<cat></cat>
<dog></dog>
<rock></rock>
<fox></fox>
<viking></viking>
</app-animals>

As we can see that:

  Animals are <cat>, <dog>, <fox>, <viking>.

Material is <rock>.

1. First way we might use is Tamplate Ref:

<cat  #item></cat>
<fox #item></fox>
  // #item Ref
   @ContentChildren('item') itemRefsQL: QueryList<any>>
   const items = this.itemRefsQL.toArray();

It will work, but the problem for this solution is that, the container should know what children it has. Also the chance that I might mis-mark the component.

2. We can use 'directive' + {read: ElementRef}:

animal.directive.ts:

import { Directive } from '@angular/core';

@Directive({
// tslint:disable-next-line:directive-selector
selector: '[animal]'
})
export class AnimalDirective {}
<cat animal></cat>
<dog animal></dog>
@ContentChildren(AnimalDirective, {read: ElementRef}) directiveElementsQL: QueryList<ElementRef>;
const directiveElements = this.directiveElementsQL.toArray();

Here without {read: ElementRef}, it won't work. We need it to tell Angular we are actually looking for the host element of the directive. Not direcitve itself.

But still the same problem as Tempalte Ref, we need to mark in the template to tell which component we need.

3.  Similar to using directive only, but {read: <interface>}.

We create a Animal interface and the component implements Animal interface.

animal.ts:

export abstract class Animal {
name: string;
abstract speak(): void;
abstract clear(): void;
}

dog.component.ts:

import { Component } from '@angular/core';
import { Animal } from './animal'; @Component({
// tslint:disable-next-line:component-selector
selector: 'dog',
template: `
<div>
<img src="../assets/dog.jpg"/>
<h3>{{saying}}</h3>
</div>
`,
})
// Subclasses Animal
export class DogComponent extends Animal { name = 'Dog';
saying: string; speak() {
this.saying = 'Woof';
} clear() {
this.saying = '';
} }

Now what we can do is Query by Animal interface in the contianer component:

<cat  animal ></cat>
  @ContentChildren(AnimalDirective, {read: Animal}) directiveAnimalsQL: QueryList<Animal>;
const directiveAnimals = this.directiveAnimalsQL.toArray();
console.log("directiveAnimals", directiveAnimals);
/*
CatComponent {injector: Injector_, name: "Cat"}
DogComponent {name: "Dog"}
FoxComponent {name: "Fox"}
VikingComponent {name: "Viking"}
*/

4. Recommended: Finally we come to our recommended solution.

Using alias Injection of the component itself.

import { Component } from '@angular/core';
import { Animal } from './animal'; @Component({
// tslint:disable-next-line:component-selector
selector: 'fox',
template: `
<div>
<img src="../assets/fox.jpeg"/>
<h3>{{saying}}</h3>
</div>
`,
providers: [
{ provide: Animal, useExisting: FoxComponent }
]
})
export class FoxComponent implements Animal {
name = 'Fox';
saying: string; speak() {
this.saying = 'ring-ding-ding-ding-dingedinging';
} clear() {
this.saying = '';
} }

For the animals related component, we inject the provider 'useExisting', so it always refer to the same instance. And we use interface Animal as alias.

Now, our container can be really clean:

      <cat ></cat>
<dog></dog>
  // Any projected component with an Animal "interface" in its injector
   import { Animal } from './animal';
  @ContentChildren(Animal) animalsQL: QueryList<Animal>;

  ngAfterContentInit() {
const animals = this.animalsQL.toArray();
}

Talk, Github

[Angular] Advanced DI的更多相关文章

  1. [Angular 2] DI in Angular 2 - 1

    Orgial aritial --> Link The problem with Angular 1 DI: Angular 2 DI: Solve the singletons problem ...

  2. [Angular] Angular Advanced Features - ng-template , ng-container, ngTemplateOutlet

    Previously we have tab-panel template defined like this: <ul class="tab-panel-buttons" ...

  3. 来自 Thoughtram 的 Angular 2 系列资料

    Angular 2 已经正式 Release 了,Thoughtram 已经发布了一系列的文档,对 Angular 2 的各个方面进行深入的阐释和说明. 我计划逐渐将这个系列翻译出来,以便对大家学习 ...

  4. Angular概念纵览

    Conceptual Overview Template(模板): HTML with additional markup (就是增加了新的标记的HTML) Directive(指令): extend ...

  5. (七)理解angular中的module和injector,即依赖注入

    (七)理解angular中的module和injector,即依赖注入 时间:2014-10-10 01:16:54      阅读:63060      评论:1      收藏:0      [点 ...

  6. angular问题总结与反思

    因为工作中实际开发需要,才开始接触angular框架.从当初的比葫芦画瓢,被各种问题.概念折磨摧残,到现在有一定的了解认识,觉得有必要将自己的认识进行简单的总结.不到位的地方还望多多包涵. 1.双向数 ...

  7. [Angular 2] Understanding @Injectable

    In order to resolve a dependency, Angular’s DI uses type annotations. To make sure these types are p ...

  8. [Angular 2] Factory Provider with dependencies

    This lesson discusses when and how to add dependencies, resolved by Angular’s DI, to factory provide ...

  9. [Angular 2] Factory Provider

    In this lesson, we discuss how and when to use factory providers, to enable dependencies that should ...

随机推荐

  1. .NET页面事件执行顺序

    摘自:http://www.cnblogs.com/kenkofox/archive/2011/03/18/1987998.html和http://blog.csdn.net/yiruoyun/art ...

  2. C#之考勤系统

    闲来无聊,搞搞C#,下面就是我写的一个Demo 员工类 using System; using System.Collections.Generic; using System.Linq; using ...

  3. 关于AS使用git的那些奇葩事儿

    首先致谢: http://blog.csdn.net/a10615/article/details/52135617, 我们不生产代码, 我们只做大自然的搬运工! 总结 1. 首次无法push问题: ...

  4. java与安卓中的回调callback学习笔记

    1.回调的简单设计如下: package com.listercai.top; public class A { private CallBack callBack; private AnotherC ...

  5. SQL Server中,with as使用介绍

    一.WITH AS的含义      WITH AS短语,也叫做子查询部分(subquery factoring),可以让你做很多事情,定义一个SQL片断,该SQL片断会被整个SQL语句所用到.有的时候 ...

  6. Equals相關的一些要點

    什麽時候需要覆蓋Equals? 自定義的值類型需要覆蓋,因爲框架默認的實現是基於反射的,效率不高. 自定義的引用類型要根據業務需要來決定是否提供覆蓋.    什麽時候需要覆蓋operator==()? ...

  7. PHP获得文件的大小并转换格式

    利用filesize($filename)函数获得一个文件的大小 参数$filename为文件的绝对路径,返回的值是文件的大小字节数. 文件较大的时候看起来不方便,下面是一个格式化方法 functio ...

  8. 题解 P3258 【[JLOI2014]松鼠的新家】(From luoguBlog)

    唯一能得分的题也被自己搞炸了,好的. 考场上读完题基本认定和lca脱不了干系,想了一会确认是树剖. 那么问题来了,考前一节课刚发现自己之前打的树剖是错的. 而且就算是错的我也没信心考场调出来. 于是打 ...

  9. 关于图片和auido预加载

    预加载老生常谈: funtion preLoadImages(imageArr){ var self = this; var newimages=[], loadedimages=0 var post ...

  10. es6-set-map数据结构

    Set的用法 set的key一定是字符串 { let list=new Set(); list.add(5);//向set中增加值要用add() list.add(6); console.log('s ...