如何为 Angular Material 构建自定义 formGroup 组件

问题描述

我目前正在研究如何创建时间范围选择器。我的目的是开发一个类似于下面的 mat-date-range-input 组件的组件,用于没有 datepickerpicker-toggle 和 mat-date-range-picker 的时间范围(我只需要用户输入和用户条目的合并):>

<mat-form-field appearance="fill">
  <mat-label>Dates</mat-label>
  <mat-date-range-input [formGroup]="daterange" [rangePicker]="datePicker">
    <input matStartDate placeholder="Start date" formControlName="dateStart" (dateInput)="onDateChange('dateStart',$event)" />
    <input matEndDate placeholder="End date" formControlName="dateEnd" (dateInput)="onDateChange('dateEnd',$event)" />
  </mat-date-range-input>
  <mat-datepicker-toggle matSuffix [for]="datePicker"></mat-datepicker-toggle>
  <mat-date-range-picker #datePicker></mat-date-range-picker>
</mat-form-field>

从现在开始我尝试了几件事,最简单的是使用 controlContainer 并在 ngContainer 中构建我的组表单,这导致了这个错误

core.js:4196 ERROR 错误:mat-form-field 必须包含 MatFormFieldControl

所以接下来我尝试按照本教程创建自定义组件:tutorial angular material 这并不是我想要知道我正在寻找构建一组两个输入控件的内容。 我遇到了和 controlContainer one 一样的问题:

mat-form-field 必须包含一个 MatFormFieldControl。

我的实际组件模板如下:

 <div 
   role="group" 
   class="time-picker-container">
   <input type="time" formControlName="timeStart" min="1" max="24"/>
   <span class="mat-date-range-input-separator">–</span>
   <input type="time" formControlName="timeEnd" min="1" max="24"/>
 </div>

我实现该组件的尝试如下:

export interface TimeRange {
  timeStart: string;
  timeEnd: string;
}

@Component({
  selector: 'time-range-picker',templateUrl: './time-range-picker.component.html',styleUrls: ['./time-range-picker.component.scss'],providers: [{provide: [MatFormFieldControl,NG_VALUE_ACCESSOR],useExisting: 
  TimeRangePickerComponent}]
})
export class TimeRangePickerComponent implements MatFormFieldControl<TimeRange>,ControlValueAccessor 
{

@input()
formGroup: FormGroup;

@input()
get value() : TimeRange | null {
  let fg = this.formGroup.value;
  if (fg.timeStart !== null && fg.timeEnd !== null){
    return { timeStart: fg.timeStart,timeEnd: fg.timeEnd};
  }
  return null;
}
set value(value: TimeRange | null) {
  value = value || { timeStart: '',timeEnd: ''};
  this.formGroup.setValue({ hourStart: value.timeStart,timeStart: value.timeStart});
  this.stateChanges.next();
}

stateChanges: Subject<void>;
static nextId = 0;
@HostBinding() id = `time-range-picker-${TimeRangePickerComponent.nextId++}`;

private _placeholder: string;

@input()
get placeholder() {
  return this._placeholder;
}
set placeholder(value) {
  this._placeholder = value;
  this.stateChanges.next();
}

focused: boolean = false;

get empty() : boolean {
  let p = this.formGroup.value;
  return !p.hourStart && !p.hourEnd && !p.minutesstart && !p.minutesEnd;
}

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

private _required : boolean = false;
@input()
get required() : boolean {
  return this._required;
}
set required(req) {
  this._required = coerceBooleanProperty(req);
  this.stateChanges.next();
}

private _disabled: boolean = false;
@input()
get disabled(): boolean { return this._disabled; }
set disabled(value: boolean) {
  this._disabled = coerceBooleanProperty(value);
  this._disabled ? this.formGroup.disable() : this.formGroup.enable();
  this.stateChanges.next();
}

errorState: boolean = false;
controlType?: string = 'time-range-picker';
autofilled?: boolean;

@Input('aria-describedby') userAriaDescribedBy: string;
setDescribedByIds(ids: string[]): void {
  const controlElement = this.elRef.nativeElement
    .querySelector('.time-range-picker-container')!;

  controlElement.setAttribute('aria-describedby',ids.join(' '));
}

onContainerClick(event: MouseEvent): void {
  if ((event.target as Element).tagName.toLowerCase() != 'input') {
    this.elRef.nativeElement.querySelector('input').focus();
  }
}



constructor(fb: FormBuilder,private fm: FocusMonitor,private elRef: ElementRef<HTMLElement>,@Optional() public parentFormField: MatFormField,@Optional() @Self() public ngControl: NgControl) 
{ 
    fm.monitor(elRef,true).subscribe(origin => {
      this.focused = !!origin;
      this.stateChanges.next();
    });
}

writeValue(obj: any): void {
  if (obj != undefined) this.formGroup.setValue(obj);
}
registerOnChange(fn: any): void {
  this.formGroup.valueChanges.subscribe(fn);
}
registerOnTouched(fn: any): void {
  throw new Error('Method not implemented.');
}
setdisabledState?(isdisabled: boolean): void {
  throw new Error('Method not implemented.');
}

ngOnDestroy(): void {
  this.stateChanges.complete();
  this.fm.stopMonitoring(this.elRef);
}
}

这个问题是我在父组件中有两个不同的formControls,它们以这样的形式(反应形式)链接它们:

this.timeRange = new FormGroup({
  timeStart: new FormControl(this.filtersInput.timeRange.timeStart),timeEnd: new FormControl(this.filtersInput.timeRange.timeEnd),});

this.form = this.formBuilder.group({
  timeRange: this.timeRange
});

如果您对如何实现该功能有任何想法或建议。

提前感谢您阅读和分享您的知识!

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...