角度材料2具有ng值访问器的自定义组件
我正在开发角度4.4材料beta12自定义组件,但无法弄清楚我的实现中出了什么问题
我正在尝试实现以下自定义输入 任务: >设置值为formControl,一旦我从服务器获取数据(data.productTeam是数据 – 可以在代码中看到) 问题: >我无法将默认值绑定到formcontrol. 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; } } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |