0 typescript angular-material angular angular-reactive-forms angular8
我正在尝试创建一个材质下拉包装器(mat-select dropdown),它将与 formControlName 一起使用。如果某人的库中有 Stackblitz,可以发布他们的 Stackblitz 吗?随意从头开始,并创建自己的答案,只要符合要求即可。
要求:
1)需要与formControlName一起使用。我们有带有 formBuilder 的父组件表单及其验证器,它试图引用这个子包装器。作为典型场景,父组件表单构建器还有许多其他表单字段。
2) 如果数据不满足父 FormBuilder 验证器的要求,则需要显示红色无效错误。
3) a) 不仅需要与 formControlName/patchValue 一起使用(patchValue 应该与整个类一起使用);b) 如果有人将数据放入 @Input() SelectedValueId Id 数字,也可以选择。可以和两个一起工作
试图让它工作,但还没有成功,有人有任何代码来解决这个问题吗?
需要工作 stackblitz,才能获得成功的答案,
在本例中,Id 是 sourceOfAddressId
export class SourceOfAddressDto implements ISourceOfAddressDto {
sourceOfAddressId: number | undefined; // should work with this Id
sourceOfAddressCode: string | undefined;
sourceOfAddressDescription: string | undefined;
Run Code Online (Sandbox Code Playgroud)
打字稿:
@Component({
selector: 'app-address-source-dropdown',
templateUrl: './address-source-dropdown.component.html',
styleUrls: ['./address-source-dropdown.component.scss'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => AddressSourceDropdownComponent),
multi: true
}
]
})
export class AddressSourceDropdownComponent implements OnInit, OnChanges {
dataList: any[] = [];
@Input() Label = 'Address Source';
@Input() sourceOfAddressDefaultItem: SourceOfAddressDto = SourceOfAddressDefault;
@Input() selectedSourceOfAddress: any;
@Input() TxtValue = 'sourceOfAddressId';
@Input() TxtField = 'sourceOfAddressDescription';
@Input() Disabled: boolean;
@Input() valuesToExclude: number[] = [];
@Input() Hint = '';
@Input() styles: string;
@Input() defaultSourceOfAddressCode: any;
@Output() addressSourceChange = new EventEmitter<any>();
private _selectedValueId: number;
@Input() set selectedValueId(value: number) {
this._selectedValueId = value;
let outputData: any;
if (this.selectedValueId == this.sourceOfAddressDefaultItem[this.TxtValue]) {
outputData = null;
} else {
outputData = this.dataList.find(x => x[this.TxtValue] == this.selectedValueId);
}
this.onChange(outputData);
}
get selectedValueId(): any {
return this._selectedValueId;
}
@Input() errors: any = null;
disabled: boolean;
control: FormControl;
writeValue(value: any) {
this.selectedValueId = value ? value : '';
}
onChange = (_: any) => { };
onTouched: any = () => { };
registerOnChange(fn: any) { this.onChange = fn; }
registerOnTouched(fn: any) { this.onTouched = fn; }
setDisabledState(isDisabled) { this.disabled = isDisabled; }
constructor(
public injector: Injector,
private AddressService: AddressServiceProxy,
) { }
ngOnInit() {
this.loadDataList();
}
ngOnChanges() { }
loadDataList() {
this.AddressService.getSourceOfAddressAll().subscribe(res => {
this.dataList = res.body.filter(q => q.sourceOfAddressId !== -1);
});
}
}
Run Code Online (Sandbox Code Playgroud)
HTML:
<div class="dropdown-cont">
<mat-form-field appearance="outline">
<mat-label>{{Label}}</mat-label>
<mat-select
disableOptionCentering
[disabled]="Disabled"
[ngStyle]="styles"
(ngModelChange)="selectedValueId=$event"
required>
<mat-option [value]="sourceOfAddressDefaultItem[TxtValue]">{{sourceOfAddressDefaultItem[TxtField]}}</mat-option>
<mat-option *ngFor="let item of dataList" [value]="item[TxtValue]">
{{item[TxtField]}}
</mat-option>
</mat-select>
<mat-hint>{{Hint}}</mat-hint>
</mat-form-field>
</div>
Run Code Online (Sandbox Code Playgroud)
其他人提到您需要显式实现该ControlValueAccessor
接口。虽然这绝对是一个很好的实践,但在 TypeScript 中不是必需的,因为任何满足接口的东西也会隐式实现它,这是您使用writeValue
、registerOnChange
和registerOnTouched
方法(以及,setDisabledState
但该方法是可选的)执行的操作。
因此,最大的问题是实施的细节。Angular 依赖于该接口的实现来执行神奇的双向绑定formControlName
(formControl
就此而言),其中父组件既可以监听子组件,也可以在子组件上设置值。
你的writeValue
和都registerOnTouched
很好。你的registerOnChange
不是。在这里,您可以在组件本地进行更改并“注册”它们,这意味着您可以将常用的 Angular valueChanges 事件函数挂接到您自己的自定义 valueChanges 中。
使用表单控件来实现这一点的典型方法:
control = new FormControl('');
registerOnChange(fn: (value: string) => void) {
this.control.valueChanges
.subscribe(fn);
}
Run Code Online (Sandbox Code Playgroud)
因此,一旦您执行类似的操作,您就会从父组件中获得向上和向下的更改。
现在,为了满足您的所有请求,您将需要更多自定义代码。不久前我碰巧实现了一些非常相似的东西,并且效果很好,并且我在 stackblitz 中重新创建了它。
希望这足以让您继续前进。
归档时间: |
|
查看次数: |
5010 次 |
最近记录: |