Angular 2 – ng-bootstrap如何为其NgbRadio指令提供NgbRadioGroup和NgbButtonLabel?

前端之家收集整理的这篇文章主要介绍了Angular 2 – ng-bootstrap如何为其NgbRadio指令提供NgbRadioGroup和NgbButtonLabel?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
这是标签代码
  1. import {Directive} from '@angular/core';
  2.  
  3. @Directive({
  4. selector: '[ngbButtonLabel]',host:
  5. {'[class.btn]': 'true','[class.active]': 'active','[class.disabled]': 'disabled','[class.focus]': 'focused'}
  6. })
  7. export class NgbButtonLabel {
  8. active: boolean;
  9. disabled: boolean;
  10. focused: boolean;
  11. }

这是单选按钮代码

  1. import {Directive,forwardRef,Input,Renderer2,ElementRef,OnDestroy} from '@angular/core';
  2. import {ControlValueAccessor,NG_VALUE_ACCESSOR} from '@angular/forms';
  3.  
  4. import {NgbButtonLabel} from './label';
  5.  
  6. const NGB_RAdio_VALUE_ACCESSOR = {
  7. provide: NG_VALUE_ACCESSOR,useExisting: forwardRef(() => NgbRadioGroup),multi: true
  8. };
  9.  
  10. let nextId = 0;
  11.  
  12. /**
  13. * Easily create Bootstrap-style radio buttons. A value of a selected button is bound to a variable
  14. * specified via ngModel.
  15. */
  16. @Directive({
  17. selector: '[ngbRadioGroup]',host: {'data-toggle': 'buttons','role': 'group'},providers: [NGB_RAdio_VALUE_ACCESSOR]
  18. })
  19. export class NgbRadioGroup implements ControlValueAccessor {
  20. private _radios: Set<NgbRadio> = new Set<NgbRadio>();
  21. private _value = null;
  22. private _disabled: boolean;
  23.  
  24. get disabled() { return this._disabled; }
  25. set disabled(isDisabled: boolean) { this.setDisabledState(isDisabled); }
  26.  
  27. /**
  28. * The name of the group. Unless enclosed inputs specify a name,this name is used as the name of the
  29. * enclosed inputs. If not specified,a name is generated automatically.
  30. */
  31. @Input() name = `ngb-radio-${nextId++}`;
  32.  
  33. onChange = (_: any) => {};
  34. onTouched = () => {};
  35.  
  36. onRadioChange(radio: NgbRadio) {
  37. this.writeValue(radio.value);
  38. this.onChange(radio.value);
  39. }
  40.  
  41. onRadioValueUpdate() { this._updateRadiosValue(); }
  42.  
  43. register(radio: NgbRadio) { this._radios.add(radio); }
  44.  
  45. registerOnChange(fn: (value: any) => any): void { this.onChange = fn; }
  46.  
  47. registerOnTouched(fn: () => any): void { this.onTouched = fn; }
  48.  
  49. setDisabledState(isDisabled: boolean): void {
  50. this._disabled = isDisabled;
  51. this._updateRadiosDisabled();
  52. }
  53.  
  54. unregister(radio: NgbRadio) { this._radios.delete(radio); }
  55.  
  56. writeValue(value) {
  57. this._value = value;
  58. this._updateRadiosValue();
  59. }
  60.  
  61. private _updateRadiosValue() { this._radios.forEach((radio) => radio.updateValue(this._value)); }
  62. private _updateRadiosDisabled() { this._radios.forEach((radio) => radio.updateDisabled()); }
  63. }
  64.  
  65.  
  66. /**
  67. * Marks an input of type "radio" as part of the NgbRadioGroup.
  68. */
  69. @Directive({
  70. selector: '[ngbButton][type=radio]',host: {
  71. '[checked]': 'checked','[disabled]': 'disabled','[name]': 'nameAttr','(change)': 'onChange()','(focus)': 'focused = true','(blur)': 'focused = false'
  72. }
  73. })
  74. export class NgbRadio implements OnDestroy {
  75. private _checked: boolean;
  76. private _disabled: boolean;
  77. private _value: any = null;
  78.  
  79. /**
  80. * The name of the input. All inputs of a group should have the same name. If not specified,* the name of the enclosing group is used.
  81. */
  82. @Input() name: string;
  83.  
  84. /**
  85. * You can specify model value of a given radio by binding to the value property.
  86. */
  87. @Input('value')
  88. set value(value: any) {
  89. this._value = value;
  90. const stringValue = value ? value.toString() : '';
  91. this._renderer.setProperty(this._element.nativeElement,'value',stringValue);
  92. this._group.onRadioValueUpdate();
  93. }
  94.  
  95. /**
  96. * A flag indicating if a given radio button is disabled.
  97. */
  98. @Input('disabled')
  99. set disabled(isDisabled: boolean) {
  100. this._disabled = isDisabled !== false;
  101. this.updateDisabled();
  102. }
  103.  
  104. set focused(isFocused: boolean) {
  105. if (this._label) {
  106. this._label.focused = isFocused;
  107. }
  108. }
  109.  
  110. get checked() { return this._checked; }
  111.  
  112. get disabled() { return this._group.disabled || this._disabled; }
  113.  
  114. get value() { return this._value; }
  115.  
  116. get nameAttr() { return this.name || this._group.name; }
  117.  
  118. constructor(
  119. private _group: NgbRadioGroup,private _label: NgbButtonLabel,private _renderer: Renderer2,private _element: ElementRef) {
  120. this._group.register(this);
  121. }
  122.  
  123. ngOnDestroy() { this._group.unregister(this); }
  124.  
  125. onChange() { this._group.onRadioChange(this); }
  126.  
  127. updateValue(value) {
  128. this._checked = this.value === value;
  129. this._label.active = this._checked;
  130. }
  131.  
  132. updateDisabled() { this._label.disabled = this.disabled; }
  133. }

请注意

  1. @Directive({
  2. selector: '[ngbButton][type=radio]','(blur)': 'focused = false'
  3. }
  4. })

没有provider部分,但构造函数有一个NgbRadioGroup和NgbButtonLabel.此外,在使用指令时,不要像这样放弃ngbButtonLabel:

  1. <div [(ngModel)]="model" ngbRadioGroup>
  2. <label>
  3. <input ngbButton type="radio" name="radio" [value]="values[0]"/> {{ values[0] }}
  4. </label>
  5. </div>

导致NgbButtonLabel没有提供者!错误.我遗失了什么声明?以下是其完整存储库的链接https://github.com/ng-bootstrap/ng-bootstrap

ng-bootstrap包期望该元素
  1. <input ngbButton type="radio" ...>

在您提供NgbRadio指令的情况下,将提供您提供NgbButtonLabel指令的父元素.

所以你的模板应该是这样的:

  1. <label ngbButtonLabel> <======== add ngbButtonLabel attribute
  2. <input ngbButton type="radio" name="radio" [value]="values[0]"/> {{ values[0] }}
  3. </label>

要理解为什么会这样,你需要从层次结构树中知道how angular gets dependencies.

假设我们的根组件中有以下模板:

app.component.html

  1. <div dirA>
  2. <comp-b dirB>
  3. <span dirC>
  4. <i dirD></i>
  5. </span>
  6. </comp-b>
  7. </div>

以及以下指令集:

  1. @Directive({
  2. selector: '[dirA]',providers: [{ provide: 'A',useValue: 'dirA provider' }]
  3. })
  4. export class DirA {}
  5.  
  6. @Component({
  7. selector: 'comp-b',template: '<ng-content></ng-content>',providers: [{ provide: 'B',useValue: 'comp-b provider'}]
  8. })
  9. export class ComponentB {}
  10.  
  11. @Directive({ selector: 'dirB' })
  12. export class DirB {}
  13.  
  14. @Directive({ selector: 'dirC' })
  15. export class DirC {}
  16.  
  17. @Directive({ selector: 'dirD' })
  18. export class DirD {
  19. constructor(private dirB: DirB) {}
  20. }

注意:私有dirB:DirB就像私有_label:NgbButtonLabel在你的情况下

Angular编译器为我们的模板创建视图工厂:

注意:我在组件上使用了新的preserveWhitespaces:false选项,因此我们在工厂中看不到textDef.

然后从这个工厂角度creates ViewDefinition并实例化主机元素的提供者.

角度编译器在哪里采用提供者?

你应该知道的主要事情是each directive provides its own token

所以这里的提供者看起来如下:

  1. <div dirA> [DirA]
  2. <comp-b dirB> [ComponentB,DirB]
  3. <span dirC> [DirC]
  4. <i dirD></i> [DirD]
  5. </span>
  6. </comp-b>
  7. </div>

以下规则是我们在指令元数据中声明的提供程序(提供程序数组)也将添加到主机元素提供程序:

  1. <div dirA> [DirA,{ provide: 'A',useValue: 'dirA provider' }]
  2. <comp-b dirB> [ComponentB,DirB,{ provide: 'B',useValue: 'comp-b provider'}]
  3. <span dirC> [DirC]
  4. <i dirD></i> [DirD]
  5. </span>
  6. </comp-b>
  7. </div>

现在angular正试图获得DirB指令的提供者

  1. @Directive({ selector: 'dirD' })
  2. export class DirD {
  3. constructor(private dirB: DirB) {}
  4. }

角度依赖性解析机制以< i dirD>< / i>开头.节点并上升到< div dirA>:

  1. null or throw error
  2. /\
  3. @NgModule
  4. /\
  5. my-app
  6. <div dirA> /\ [DirA,useValue: 'dirA provider' }]
  7. <comp-b dirB> /\ [ComponentB,useValue: 'comp-b provider'}]
  8. <span dirC> /\ [DirC]
  9. <i dirD></i> /\ [DirD]
  10. </span>
  11. </comp-b>
  12. </div>

因此,角度将在< comp-b dirB>上找到DirB提供者.主机元素.我们可能会认为angular会使DirB提供者BUT三步
确实是角度uses prototypical inheritance来定义元素的提供者.

这样我们的树看起来像:

  1. null or throw error
  2. /\
  3. @NgModule
  4. /\
  5. my-app
  6. <div dirA> /\ [
  7. DirA,useValue: 'dirA provider' }
  8. ]
  9. <comp-b dirB> /\ [
  10. ComponentB,useValue: 'comp-b provider'},DirA,useValue: 'dirA provider' }
  11. ]
  12. <span dirC> /\ [
  13. DirC,ComponentB,useValue: 'dirA provider' }
  14. ]
  15. <i dirD></i> /\ [
  16. DirD,DirC,useValue: 'dirA provider' }
  17. ]
  18. </span>
  19. </comp-b>
  20. </div>

正如我们所看到的,实际上角度仅使用一步来从< i dirD>< / i>中找到DirB提供者.主机元素.

猜你在找的Angularjs相关文章