[Angular] [formControl] 多个formControl的消息传递

[Angular] [formControl] 多个formControl的消息传递

明确需求

业务场景: 在根据某些条件搜索产品时,需要有两个输入框输入单价的范围。当输入有效时,搜索按钮处于可点击状态。
实现思路:使用一个FormGroup包裹两个FormControl分别接收单价的最低值与最高值。
功能点

  1. 双边检查:当两个输入框输入均为空时,判定为有效,此时搜索将会显示全量数据。
  2. 单边检查:当只有一个输入框为空时,判定为无效。并且空值框的边框会变红。
  3. 区间范围检查:当最低价高于最高价时,判定为无效。

实现

如果只考虑第三点,两个FormControl可以共用一个validator函数判断其是否有效。实现如下

// An easy method 
//!!!!!!worng!!!!!!!!!
import { Component, Input, OnInit } from '@angular/core';
import { FormControl } from '@angular/forms';
import * as _ from 'lodash';

@Component({
  selector: 'app-range',
  templateUrl: './range.component.html',
  styleUrls: ['./range.component.scss'],
})
export class RangeComponent implements OnInit {

  constructor() {
  }

  @Input()
  title: string = '单价';

  @Input()
  startValue: FormControl;

  @Input()
  endValue: FormControl;

  ngOnInit() {
    this.startValue.setValidators(this.validator());
    this.endValue.setValidators(this.validator());
  }

  private validator() {
    return () => {
      if (this.isValueEmpty(this.startValue.value) && !this.isValueEmpty(this.endValue.value)
       && this.isInvalidValueRange) {
        return { outOfRange: true };
      }
    };
  }
  isValueEmpty = (value: number) => {
    return !_.isNumber(value) && !_.isBoolean(value) && _.isEmpty(value);
  }
}

但是这样虽然满足了需求1和3,但是将无法满足需求2。需求2中,当两个输入框均为空,没有框变红。当输入一个值后,当前这个框不变红但是另一个框将感应到这个框的变化而变红。因此在程序中加入Subscriber来传递变化消息。实现如下:

import { Component, Input, OnInit } from '@angular/core';
import { FormControl } from '@angular/forms';
import * as _ from 'lodash';

@Component({
  selector: 'app-range',
  templateUrl: './range.component.html',
  styleUrls: ['./range.component.scss'],
})
//The correct method
export class RangeComponent implements OnInit {

  constructor() {
  }

  @Input()
  title: string = '单价';

  @Input()
  startValue: FormControl;

  @Input()
  endValue: FormControl;

  ngOnInit() {
    this.startValue.setValidators(this.startValueValidator());
    this.endValue.setValidators(this.endValueValidator());
    
    this.initSubscriber();
  }

  private endValueValidator() {
    return () => {
      if ((this.isValueEmpty(this.endValue.value) && !this.isValueEmpty(this.startValue.value))
       || this.isInvalidValueRange) {
        return { outOfRange: true };
      }
    };
  }

  private startValueValidator() {
    return () => {
      if ((this.isValueEmpty(this.startValue.value) && !this.isValueEmpty(this.endValue.value))
       || this.isInvalidValueRange) {
        return { outOfRange: true };
      }
    };
  }
  
  get isInvalidValueRange() {
    return !this.isValueEmpty(this.startValue.value) && !this.isValueEmpty(this.endValue.value) 
    && this.startValue.value > this.endValue.value;
  }

  initSubscriber() {
    this.startValue.valueChanges
      .subscribe(() => this.endValue.updateValueAndValidity({ emitEvent: false }));

    this.endValue.valueChanges
      .subscribe(() => this.startValue.updateValueAndValidity({ emitEvent: false }));
  }

  isValueEmpty = (value: number) => {
    return !_.isNumber(value) && !_.isBoolean(value) && _.isEmpty(value);
  }
}

接下来补充以下html文件以及样式文件:

Range.scss


.input-range {
  font-size: 14px;
}

input {
  display: inline-block;
  width: 100px;
  height: 32px;
  border-radius: 3px;
  border: solid 1px $silver;
  margin: 0 8px;
}

.invalid-input-border {
  border-color: $cinnabar;
}

Range.html

<div class="input-range">
  <span>{{title}}</span>
  <input class="input-control form-control"
         type="number"
         [ngClass]="{'invalid-input-border': startValue.invalid}"
         [formControl]="startValue">
  <span> - </span>
  <input class="input-control form-control"
         type="number"
         [ngClass]="{'invalid-input-border': endValue.invalid}"
         [formControl]="endValue">
</div>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值