美文网首页
Angular ControlValueAccessor 自定义

Angular ControlValueAccessor 自定义

作者: 云上笔记 | 来源:发表于2023-05-23 15:48 被阅读0次

ControlValueAccessor 是一个接口,它定义了一组方法,用于在 Angular 表单控件和模型之间进行双向数据绑定。这些方法包括writeValueregisterOnChangeregisterOnTouchedsetDisabledState。通过实现这些方法,我们可以创建自定义表单控件,并将其与 Angular 表单系统无缝集成。

例如,在项目中某个页面有多个这样的百分数输入框:输入框中的值除以100再传给后端,后端返回的值乘以100再显示

图片.png

为避免每次都要重复处理数据,可以通过 ControlValueAccessor 实现一个自定义的表单输入框,具体实现方式如下:

<!-- html 中定义输入框 -->
<nz-input-group nzSize="small">
    <div nz-row>
        <div nz-col [nzSpan]="leftSpan">
            <input nz-input type="text" nzSize="small" [disabled]="disabled" [ngModel]="percent" (ngModelChange)="onValueChange($event)"/>
        </div>
        <div nz-col nzSpan="{{ 24 - leftSpan }}" class="text-center">
            <input nz-input type="text" nzSize="small" value="%" disabled />
        </div>
    </div>
</nz-input-group>
import { Component, OnInit, Input, forwardRef } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { DecimalPipe } from '@angular/common';

export const EXE_VALUE_ACCESSOR: any = {
  provide: NG_VALUE_ACCESSOR,
  useExisting: forwardRef(() => PercentGroupComponent),
  multi: true
};

@Component({
  selector: 'app-percent-group',
  templateUrl: './percent-group.component.html',
  styleUrls: ['./percent-group.component.scss'],
  providers: [EXE_VALUE_ACCESSOR, DecimalPipe]
})
export class PercentGroupComponent implements OnInit, ControlValueAccessor {
  @Input() required = false;
  @Input() leftSpan = 20;
  public percent;
  public disabled = false;

  public onChange: (param: any) => {};
  public onTouch: (param: any) => {};

  constructor(
    private decimalPipe: DecimalPipe
  ) { }

  ngOnInit(): void {
  }

  /**
   * 注册 onChange 事件, 将事件触发函数暂存,需要时通过调用 this.onChange 触发更新
   * @param fn: 事件触发函数
   * 数据流向:native  form -> angular form
   */
  public registerOnChange(fn: any): void {
    this.onChange = fn;
  }

  /**
   * 注册 onTouched 事件, 用户和控件交互时触发的回调函数,用于通知表单控件已经处于 touched 状态
   * @param fn: 事件触发函数
   * 数据流向:native  form -> angular form
   */
  public registerOnTouched(fn: any): void {
    this.onTouch = fn;
  }

  /**
   * input value change 事件
   * @param value 值
   */
  public onValueChange(value): void {
    // 输入的值除以 100 再传回 angular form
    if (value || value === 0) {
      const num = new Decimal(Number(value)).div(100).toString();
      this.onChange(num);
    } else {
      this.onChange(null);
    }

  }

  /**
   * 当angular form 控件禁用状态变更时调用此函数,以此控制本组件中控件的禁用状态
   * 数据流向:angular form -> native form
   */
  public setDisabledState(isDisabled) {
    this.disabled = isDisabled;
  }

  /**
   * 将 angular form 传入的值写入本组件对应的控件中
   * @param val: formControlName value
   * 数据流向:angular form -> native form
   */
  public writeValue(val): void {
    this.percent = this.getPercentValue(val);
  }

  /**
   * 处理百分数显示格式
   * @param value: 后台返回的数值
   */
  private getPercentValue(val) {
    let percentStr;
    const value = Number(val);
      if ((value ?? -1) > -1) {
        if (value === 0) {
          percentStr = 0;
        } else {
          // 后台返回的数值先乘以100
          const resVal = new Decimal(value).mul(100);
          percentStr = resVal;
          const amount = resVal.toString();
          // 判断是否有四位小数,不足四位补0;若是整数,则保留两位小数
          if (amount.includes('.')) {
            // 小数点后面数字的长度
            const n = amount.split('.')[1].length;
            if (n < 5) {
              percentStr = this.decimalPipe.transform(amount, '1.4');
            }
          } else {
            percentStr = this.decimalPipe.transform(amount, '1.2');
          }
        }
      }
    return percentStr;
  }
}



相关文章

网友评论

      本文标题:Angular ControlValueAccessor 自定义

      本文链接:https://www.haomeiwen.com/subject/gwuxedtx.html