加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

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

发布时间:2020-12-17 17:36:41 所属栏目:安全 来源:网络整理
导读:我正在开发角度4.4材料beta12自定义组件,但无法弄清楚我的实现中出了什么问题 我正在尝试实现以下自定义输入 任务: 设置值为formControl,一旦我从服务器获取数据(data.productTeam是数据 – 可以在代码中看到) 在编辑时,应使用值更新formcontrol(例如:P12D
我正在开发角度4.4材料beta12自定义组件,但无法弄清楚我的实现中出了什么问题

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

enter image description here

任务:

>设置值为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.value}} -- 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;
  }
}

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读