gpt4 book ai didi

javascript - Angular 2自定义复合控件

转载 作者:太空狗 更新时间:2023-10-29 18:16:17 24 4
gpt4 key购买 nike

我正在尝试为 Angular 2 创建一个自定义复合控件。我的要求是我需要创建一个通用的文件选择器控件,允许用户使用 html5 输入选择文件或者[ type=file] 输入文件的 url。

我决定创建通用表单控件,为两个子控件实现 ControlValueAccessor 接口(interface),因为它们将在别处单独使用。

我试图将它们都包装在一个file-picker-local-or-remote(找不到更好的词)控件中。此外部控件应负责发出所选文件的内容,而不关心文件是如何选取的。

将值一直传播到消费表单很容易。每次子控件向中间控件传播一个值时,中间控件都会使用 registerChange 回调将它进一步向上传递给消费者。

但是,我在传播子控件中可能发生的验证错误时遇到了问题。我需要将错误一直传播到使用表单,以便将它们本地化。

例如如果用户在 remote-file-picker 子控件中输入了无效的 url,则该子控件的验证函数将触发并显示正确的错误。这个错误交给中介控制。我如何才能将此无效网址错误一直传播到消费表单?

更广泛地说,是否有关于如何在 Angular 2 中创建复合控件的具体指南?我找不到任何包装其他自定义控件的自定义控件的示例,所以我不确定我是否正确地进行了操作。

换句话说,给定:

表格:

outerForm = new FormGroup({
file: new FormControl(null, Validators.required)
});

<form [formGroup]="outerForm">
<File-Picker-Local-Or-Remote formControlName="file"></File-Picker-Local-Or-Remote>
<span class="error">******???******</span>
</form>

文件选择器本地或远程

innerForm = new FormGroup({
local: new FormControl(),
remote: new FormControl(null, Validators.pattern('http://...'))
});

<input type="file" formControlName="local" />
<input type="text" formControlName="remote" />

当远程子控件验证失败时,它会将错误代码提供给 innerForm。我如何将这些错误消息传播到外部表单,以便我可以用适当的验证消息替换 ******???******?

编辑:我应该注意到,有很多方法可以让我破解解决方案或绕过这个问题,包括使用事件发射器构建我自己的解决方案,首先不使用复合控件等。

我真正感兴趣的是 Angular 2 方法,它可以创建可重用和可扩展的表单控件,消费者可以像任何其他表单控件一样与之交互,并且可以由其他开发人员进一步构建以创建更高级别的控件。

最佳答案

我和一位同事不久前就解决了这个问题,但这里是为其他遇到此问题的人提供的解决方案。

关键是在复合组件中同时实现 ControlValueAccessor 和 Validator 接口(interface)。

例如

自定义日期控件,实现ControlValueAccessor

@Component({
...
providers: [{
provide: NG_VALUE_ACCESSOR,
useExisting: CustomDateControl),
multi: true
}]
})
export class CustomDateControl implements ControlValueAccessor {
// implement ControlValueAccessor
}

自定义时间控件,实现ControlValueAccessor

@Component({
...
providers: [{
provide: NG_VALUE_ACCESSOR,
useExisting: CustomTimeControl),
multi: true
}]
})
export class CustomTimeControl implements ControlValueAccessor {
// implement ControlValueAccessor
}

自定义复合控件dateTime,同时实现了ControlValueAccessorValidator

@Component({
...
providers: [{
provide: NG_VALIDATORS,
useExisting: CustomDateTimeControl,
multi: true
}, {
provide: NG_VALUE_ACCESSOR,
useExisting: CustomDateTimeControl,
multi: true
}]
})
export class CustomDateTimeControl implements OnInit, ControlValueAccessor, Validator {
private propagateChange = function (change) { };
private propagateTouched = function () { };

// Inner controls (you can also use an internal FormGroup for this)
public date = new FormControl();
public time = new FormControl();

constructor() {}

ngOnInit() {
this.date.valueChanges
.subscribe(value => {
this.propagateChange(value + ' ' + this.time.value);
this.propagateTouched();
}

this.time.valueChanges
.subscribe(value => {
this.propagateChange(this.date.value + ' ' + value);
this.propagateTouched();
}
}

writeValue(value) {
// Need to update the inner controls, but don't use setValue / patchValue,
// as that will trigger valueChanges in the above subscriptions,
// incorrectly calling touched
}

registerOnChange(fn) {
this.propagateChange = fn;
}

registerOnTouched(fn) {
this.propagateTouched = fn;
}

validate(control) {
// Custom logic to validate the parent control. In this case,
// we may choose to union all childrens' errors.

let errors = Object.assign(this.localControl.errors || {}, this.remoteControl.errors || {});
return Object.keys(errors).length ? errors : null;
}
}

为了回答我自己最初的问题,将错误冒泡到复合控件链中的一个好方法是在这些复合控件中实现验证器,并让它们的验证函数返回子控件错误的某种组合。

我希望这对其他人有用。

关于javascript - Angular 2自定义复合控件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42525791/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com