本来想看的是Directive里的NgControlGroup
由于开头的exportAs 参数直接引导到了DirectiveMetadata
源码里大段的sample和解释,写的很细
首先看下指令的注入
Assume this HTML template:
<div dependency="1"> |
With the following dependency
decorator and SomeService
injectable class.
@Injectable() |
Let’s step through the different ways in which MyDirective
could be declared…
No injection
Here the constructor is declared with no arguments, therefore nothing is injected into
MyDirective
.
@Directive({ selector: '[my-directive]' }) |
This directive would be instantiated with no dependencies.
Component-level injection
Directives can inject any injectable instance from the closest component injector or any of its
parents.
Here, the constructor declares a parameter, someService
, and injects the SomeService
type
from the parent
component’s injector. —注入普通的service
@Directive({ selector: '[my-directive]' })
class MyDirective {
constructor(someService: SomeService) {
}
}
This directive would be instantiated with a dependency on SomeService
.
Injecting a directive from the current element –注入当前元素中的其他指令
Directives can inject other directives declared on the current element.
@Directive({ selector: '[my-directive]' }) |
This directive would be instantiated with Dependency
declared at the same element, in this case
dependency="3"
.
Injecting a directive from any ancestor elements –在当前元素及其父元素中的指令注入(嵌套的,并且返回第一个找到的)
Directives can inject other directives declared on any ancestor element (in the current Shadow
DOM), i.e. on the current element, the
parent element, or its parents.
@Directive({ selector: '[my-directive]' })
class MyDirective {
constructor(@Host() dependency: Dependency) {
expect(dependency.id).toEqual(2);
}
}
@Host
checks the current element, the parent, as well as its parents recursively. If
dependency="2"
didn’t
exist on the direct parent, this injection would
have returned
dependency="1"
.
Injecting a live collection of direct child directives –找子元素中的指令
A directive can also query for other child directives. Since parent directives are instantiated
before child directives, a directive can’t simply inject the list of child directives. Instead,
the directive injects a {@link QueryList}, which updates its contents as children are added,
removed, or moved by a directive that uses a {@link ViewContainerRef} such as a ngFor
, an
ngIf
, or an ngSwitch
.
@Directive({ selector: '[my-directive]' }) |
This directive would be instantiated with a {@link QueryList} which contains Dependency
4 and
Dependency
6. Here, Dependency
5 would not be included, because it is not a direct child.
Injecting a live collection of descendant directives —子元素嵌套
By passing the descendant flag to @Query
above, we can include the children of the child
elements.
@Directive({ selector: '[my-directive]' }) |
This directive would be instantiated with a Query which would contain Dependency
4, 5 and 6.
Optional injection –可能找不到,就给null
The normal behavior of directives is to return an error when a specified dependency cannot be
resolved. If you
would like to inject null
on unresolved dependency instead, you can annotate that dependency
with @Optional()
.
This explicitly permits the author of a template to treat some of the surrounding directives as
optional.
@Directive({ selector: '[my-directive]' }) |
This directive would be instantiated with a Dependency
directive found on the current element.
If none can be
found, the injector supplies null
instead of throwing an error.
开始参数解读
先来总体的构造
constructor({selector, inputs, outputs, properties, events, host, bindings, providers, exportAs, |
- selector: string; – 就是个css选择器,定位指令的
selector
may be declared as one of the following:element-name
: select by element name..class
: select by class name.[attribute]
: select by attribute name.[attribute=value]
: select by attribute name and value.:not(sub_selector)
: select only if the element does not match thesub_selector
.selector1, selector2
: select if eitherselector1
orselector2
matches.
- inputs:string[]
关于inputs 这里有两个概念directiveProperty
specifies the component property where the value is written.bindingProperty
specifies the DOM property where the value is read from.
直接举例 inputs: ['bankName', 'id: account-id']
id 就是directiveProperty , account-id 是bindingProperty
就是从host里的 bindingProperty 给 当前class里的 就是directiveProperty
如果像bankName一样没有bindingProperty,那默认bindingProperty和directiveProperty一样
get inputs(): string[] { |
从代码看,inputs无法直接赋值,只能get,也就是只能从构造中赋值
properties 已废弃 被inputs替换
outputs: string[]
和inputs 类似有2个概念,就不举例了directiveProperty
specifies the component property that emits events.bindingProperty
specifies the DOM property the event handler is attached to.
同inputs 只有 get
get outputs(): string[] {
return isPresent(this._events) && this._events.length > 0 ? this._events : this._outputs;
}
get events(): string[] { return this.outputs; }
private _outputs: string[];
private _events: string[];
host: {[key: string]: string};
- host 绑定 events
直接来例子吧
({
selector: 'button[counting]',
host: {
'(click)': 'onClick($event.target)'
}
})
class CountClicks {
numberOfClicks = 0;
onClick(btn) {
console.log("button", btn, "number of clicks:", this.numberOfClicks++);
}
}
({
selector: 'app',
template: `<button counting>Increment</button>`,
directives: [CountClicks]
})
class App {}
bootstrap(App);这是指令的host也就是指令所在的那个元素
给他的click 绑定了一个方法onClick。 利用$event参数来进一步操作Property Bindings
来例子({
selector: '[ngModel]',
host: {
'[class.valid]': 'valid',
'[class.invalid]': 'invalid'
}
})
class NgModelStatus {
constructor(public control:NgModel) {}
get valid { return this.control.valid; }
get invalid { return this.control.invalid; }
}
({
selector: 'app',
template: `<input [(ngModel)]="prop">`,
directives: [FORM_DIRECTIVES, NgModelStatus]
})
class App {
prop;
}
bootstrap(App);
给指令所在的元素的class 中的 valid/invalid 赋值。
- Attributes 赋值
这个能力只能针对一些特殊的 Attributes
({
selector: '[my-button]',
host: {
'role': 'button'
}
})
class MyButton {
}
给role 赋值 button
- providers: any[]
一组要注入的对象(class)
class Greeter { |
bindings 废弃,改用providers
get providers(): any[] { |
exportAs: string;
可以在模板中应用指令里的变量Defines the name that can be used in the template to assign this directive to a variable.
@Directive({
selector: 'child-dir',
exportAs: 'child'
})
class ChildDir {
exprotAsVar = "exportAs Text";
}
@Component({
selector: 'main',
template: `<child-dir #c="child"></child-dir> {{c.exprotAsVar}}`,
directives: [ChildDir]
})
class MainComponent {
}queries: {[key: string]: any};
源码中说了两种query- Content queries are set before the
ngAfterContentInit
callback is called. - View queries are set before the
ngAfterViewInit
callback is called.
view query的例子
- Content queries are set before the
|
viewChildren 是去query 当前组件中的 View 里 是否有对应类型的指令或者子组件
在ngAfterViewInit 中viewChildren 已经得到了
可以操作如下
this.viewChildren.toArray()[0].a |
再说 Content queries
content 就和本组件的view 和class无关了, 他是去找任何用了此组件tag的内嵌content里去query
举例: SomeDir 中要去query 类型是ChildComponent的组件
当你在某个组件中用了
<someDir> |
这种结构,他就query到了.
|
ContentChildren 是在ngAfterContentInit 里才能获取到的
如下this.contentChildren.first
>ChildComponent {a: "hha"}