微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

javascript-Angular 2自定义复合控件

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

我决定创建用于两个子控件都实现ControlValueAccessor接口的通用表单控件,因为它们将在其他地方单独使用.

我试图将它们都包装在一个文件选择器本地或远程(缺少更好的单词)控件中.该外部控件应负责发出所选文件内容,而不必关心文件的选择方式.

将价值一直传播到消费形式很容易.每次子控件将值传播给中间控件时,中间控件都会使用registerChange回调将其进一步向上传递到消费者链.

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

例如.如果用户在remote-file-picker子控件中输入无效的url,则该子控件的验证功能将触发并显示正确的错误.该错误提供给中间控件.如何将该无效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接口.

例如.

自定义日期控件,实现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,同时实现ControlValueAccessor和Validator

@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;
  }
}

为了回答我自己的第一个问题,将错误汇总到一系列复合控件中的一种好方法在这些复合控件中实现Validator,并使它们的validate函数返回子控件错误的某种组合.

我希望这对其他人有用.

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐