Angularjs   发布时间:2022-04-20  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了角度材料2具有ng值访问器的自定义组件大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。
我正在开发角度4.4材料beta12自定义组件,但无法弄清楚我的实现中出了什么问题

我正在尝试实现以下自定义输入

角度材料2具有ng值访问器的自定义组件

任务:

>设置值为formControl,一旦我从服务器获取数据(data.productTeam是数据 – 可以在代码中看到)
>在编辑时,应使用值更新formcontrol(例如:P12DT2H231M)

问题:

>我无法将认值绑定到formcontrol.
>没有ngDefaultControl(表单控件的值访问器没有名称:’productTeam’错误发生)

dashboard.component.js

this.CRForm = this.fb.group({
      productTeam: [data.productTeam || '']
});

在Dashboard.html中

<mat-form-field  floatPlaceholder="always" >
        <app-mat-custom-form-field #custref formControlName="productTeam" placeholder="P12D" ></app-mat-custom-form-field>
    <!--<app-mat-custom-form-field #custref formControlName="productTeam" placeholder="P12D" ngDefaultControl></app-mat-custom-form-field> -->
      </mat-form-field>
 {{Custref.@R_489_6084@} -- gives value eg:[P12DT1H2M] and only if ngDefaultControl
 {{CRForm['controls']['productTeam']['value']}} --not giving any

垫定制外形field.ts

import {
  Component,OnInit,OnDestroy,Input,HostBinding,Optional,Renderer2,Self,forWARDRef,ElementRef
} from '@angular/core';
import {
  MatFormFieldControl
} from '@angular/material';
import {
  ControlValueAccessor,FormGroup,FormBuilder,NgControl,NG_VALUE_ACCESSOR
} from '@angular/forms';
import {
  coerceBooleanProperty
} from '@angular/cdk/coercion';
import {
  FocusMonitor
} from '@angular/cdk/a11y';
import {
  Subject
} from 'rxjs/Subject';

class Duration {
  constructor(public days: number,public hours: number,public minutes:
    number) {}
  getDuration() {
    return 'P' + (this.days || 0) + 'DT' + (this.hours || 0) + 'H' +
      (this.minutes || 0) + 'M';
  }
  setDuration() {}
}
@Component({
  SELEctor: 'app-mat-custom-form-field',templateUrl: './mat-custom-form-field.component.html',styleUrls: ['./mat-custom-form-field.component.scss'],providers: [{
      provide: MatFormFieldControl,useExisTing: MatCustomFormFieldComponent
    },{
      provide: NG_VALUE_ACCESSOR,useExisTing: forWARDRef(() => MatCustomFormFieldComponent),multi: true
    }
  ]
})
export class MatCustomFormFieldComponent implements OnInit,MatFormFieldControl < Duration >,ControlValueAccessor,OnDestroy {
  parts: FormGroup;
  focused = false;
  stateChanges = new Subject < void > ();
  errorState = false;
  controlType = 'my-tel-input';
  private _disabled = false;
  private _required = false;
  private _placeholder: String;
  static nextId = 0;
  @input()
  get required() {
    return this._required;
  }
  set required(req) {
    this._required = coerceBooleanProperty(req);
    this.stateChanges.next();
  }
  @input()
  get disabled() {
    return this._disabled;
  }
  set disabled(dis) {
    this._disabled = coerceBooleanProperty(dis);
    this.stateChanges.next();
  }
  /* code for placeholder property */
  @input()
  get placeholder() {
    return this._placeholder;
  }
  set placeholder(plh) {
    this._placeholder = plh;
    this.stateChanges.next();
  }
  @input()
  get value(): Duration | null {
    let n = this.parts.value;
    if (n.days && n.hours && n.minutes) {
      return new Duration(n.days,n.hours,n.minutes);
    }
    return null;
  }

  set value(duration: Duration | null) {
    duration = duration || new Duration(0,0);
    this.parts.SETVALue({
      days: duration.days,hours: duration.hours,minutes: duration.minutes
    });
    this.writeValue('P' + (duration.days || 0) + 'DT' + (duration.hours || 0) +
      'H' + (duration.minutes || 0) + 'M');
    this.stateChanges.next();
  }
  onContainerClick(event: MouseEvent) {
    if ((event.target as Element).tagName.toLowerCase() != 'input') {
      this.elRef.nativeElement.querySELEctor('input').focus();
    }
  }

  /* code to get id and set id*/

  @HostBinding() id = `mat-custom-form-
    field-${MatCustomFormFieldComponent.nextId++}`;

  @HostBinding('class.floaTing')
  get shouldPlaceholderFloat() {
    return this.focused || !this.empty;
  }

  @HostBinding('attr.aria-describedby') describedBy = '';

  setDescribedByIds(ids: String[]) {
    this.describedBy = ids.join(' ');
  }

  constructor(fb: FormBuilder,private fm: FocusMonitor,private elRef:
    ElementRef,renderer: Renderer2,public ngControl: NgControl,) {
    fm.monitor(elRef.nativeElement,renderer,truE).subscribe(origin => {
      this.focused = !!origin;
      this.stateChanges.next();
    });
    ngControl.valueAccessor = this;
    this.parts = fb.group({
      'days': '','hours': '','minutes': '',});
  }

  ngOnInit() {}

  ngOnDestroy() {
    this.stateChanges.complete();
    this.fm.stopMonitoring(this.elRef.nativeElement);
  }
  get empty() {
    let n = this.parts.value;
    return !n.area && !n.exchange && !n.subscriber;
  }
  private propagateChange = (_: any) => {};

  public writeValue(a: any) {
    if (a !== undefined) {
      this.parts.SETVALue({
        days: a.subString(a.lasTindexOf("P") + 1,a.lasTindexOf("D")),hours: a.subString(a.lasTindexOf("T") + 1,a.lasTindexOf("H")),minutes: a.subString(a.lasTindexOf("H") + 1,a.lasTindexOf("M"))
      });
    }
  };
  public registerOnChange(fn: any) {
    this.propagateChange = fn;
  }

  // not used,used for touch input
  public registerOnTouched() {}
  // change events from the textarea
}

垫定制外形field.html

< div[formGroup]="parts">
  < input class="area" formControlName="days" size="3">
    < span> & ndash; < /span>
    < input class="exchange" formControlName="hours" size="3">
    < span> & ndash; < /span>
    < input class="subscriber" formControlName="minutes" size="3">
  < /div>

解决方法

首先,我修改你的写入值fn,因为它在null的情况下对我不起作用:

public writeValue(a: String) {
    if (a && a !== '') {
      this.parts.SETVALue({
        days: a.subString(a.lasTindexOf('P') + 1,a.lasTindexOf('D')),hours: a.subString(a.lasTindexOf('T') + 1,a.lasTindexOf('H')),minutes: a.subString(a.lasTindexOf('H') + 1,a.lasTindexOf('M'))
      });
    }
  }

自定义组件模板保持不变.
我以这样的示例形式使用此组件:

表格进行测试

<div>
  <form #form="ngForm" [formGroup]="productForm">
    <mat-form-field>
      <product-team-input formControlName="productTeam" placeholder="P12D" ></product-team-input>
    </mat-form-field>
  </form>
  {{ form.value | json }}
</div>

Simple AppComponent设置控件的认值(求解点1),还包含一个简单的单击方法,可以模拟从服务器加载数据时的情况.

@Component({
  SELEctor: 'app-root',templateUrl: './app.component.html',styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'app';

  data: String;
  productForm: FormGroup;

  constructor(private fb: FormBuilder) {
    this.productForm = this.fb.group({
      productTeam: [null] // can be value like P12DT2H231M as well
    });
  }
  onClick() {
    this.productForm.controls['productTeam'].patchValue('P12DT2H231M');
  }
}

使用此设置,您已经能够使用组件,并且将设置认值,但您还不会收到任何更改.

为了接收父表单中的更改,您需要使用在组件中注册的propagateChange回调来传播它们(以解决第2点).
因此,组件代码的主要更改是订阅组件内部表单组的更改,您将从中将其传播到上一级:

this.parts = fb.group({
  'days': '',});

this.subs.push(this.parts.valueChanges.subscribe((value: Duration) => {
  this.propagateChange(value);
}));

我还将在这里留下product-team-field.component.ts和Duration类的完整代码,以防万一:

duration.ts

class Duration {
      constructor(public days: number,public minutes:
        number) {
         }

    toString() {
      return 'P' + (this.days || 0) + 'DT' + (this.hours || 0) +
      'H' + (this.minutes || 0) + 'M';
    }

}

产品团队field.component.ts
    

@Component({
  SELEctor: 'product-team-input',templateUrl: './product-team-field.component.html',styleUrls: ['./product-team-field.component.css'],providers: [{
    provide: MatFormFieldControl,useExisTing: ProductTeamControl
  },{
    provide: NG_VALUE_ACCESSOR,useExisTing: forWARDRef(() => ProductTeamControl),multi: true
  }]
})
export class ProductTeamControl implements OnInit,MatFormFieldControl<Duration> {
  static nextId = 0;
  ngControl = null;
  parts: FormGroup;
  focused = false;
  stateChanges = new Subject<void>();
  errorState = false;
  controlType = 'product-team-input';
  private _disabled = false;
  private _required = false;
  private _placeholder: String;

  @input()
  get required() {
    return this._required;
  }
  set required(req) {
    this._required = coerceBooleanProperty(req);
    this.stateChanges.next();
  }
  @input()
  get disabled() {
    return this._disabled;
  }
  set disabled(dis) {
    this._disabled = coerceBooleanProperty(dis);
    this.stateChanges.next();
  }
  @input()
  get placeholder() {
    return this._placeholder;
  }
  set placeholder(plh) {
    this._placeholder = plh;
    this.stateChanges.next();
  }
  @input()
  get value(): Duration | null {
    const n = this.parts.value;
    if (n.days && n.hours && n.minutes) {
      return new Duration(n.days,0);
    this.writeValue(duration.toString());
    this.stateChanges.next();
  }
  onContainerClick(event: MouseEvent) {
    if ((event.target as Element).tagName.toLowerCase() !== 'input') {
      this.elRef.nativeElement.querySELEctor('input').focus();
    }
  }

  @HostBinding() id = `${this.controlTypE}-${ProductTeamControl.nextId++}`;

  @HostBinding('class.floaTing')
  get shouldPlaceholderFloat() {
    return this.focused || !this.empty;
  }

  @HostBinding('attr.aria-describedby') describedBy = '';

  setDescribedByIds(ids: String[]) {
    this.describedBy = ids.join(' ');
  }

  private subs: Subscription[] = [];

  constructor(
    private fb: FormBuilder,private elRef: ElementRef,renderer: Renderer2) {

    this.subs.push(fm.monitor(elRef.nativeElement,truE).subscribe(origin => {
      this.focused = !!origin;
      this.stateChanges.next();
    }));

    this.parts = fb.group({
      'days': '',});

    this.subs.push(this.parts.valueChanges.subscribe((value: Duration) => {
      this.propagateChange(value);
    }));
  }

  ngOnInit() { }

  ngOnDestroy() {
    this.stateChanges.complete();
    this.subs.forEach(s => S.Unsubscribe());
    this.fm.stopMonitoring(this.elRef.nativeElement);
  }
  get empty() {
    const n = this.parts.value;
    return !n.area && !n.exchange && !n.subscriber;
  }

  private propagateChange = (_: any) => { };

  public writeValue(a: String) {
    if (a && a !== '') {
      this.parts.SETVALue({
        days: a.subString(a.lasTindexOf('P') + 1,a.lasTindexOf('M'))
      });
    }
  }
  public registerOnChange(fn: any) {
    this.propagateChange = fn;
  }

  public registerOnTouched(fn: any): void {
    return;
  }

  public setDisabledState?(isDisabled: Boolean): void {
    this.disabled = isDisabled;
  }
}

大佬总结

以上是大佬教程为你收集整理的角度材料2具有ng值访问器的自定义组件全部内容,希望文章能够帮你解决角度材料2具有ng值访问器的自定义组件所遇到的程序开发问题。

如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。