如何在自定义控件中屏蔽值

Posted

技术标签:

【中文标题】如何在自定义控件中屏蔽值【英文标题】:How to mask value in custom control 【发布时间】:2017-10-05 03:51:28 【问题描述】:

如何在输入中显示转换后的值(例如“1(234)567-890”),而没有转换后的值('1234567890')?

是否可以为maskInputElmaskInput 分别设置值?

我有模板:

   <input #maskInputEl class="spacer" [type]="type"
   [formControl]="maskInput"/>

和自定义组件:

export class MaskInputComponent implements ControlValueAccessor, OnInit, OnDestroy 
    @ViewChild('maskInputEl') public maskInputEl: ElementRef;

    @Input() public mask: any[];

    public maskInput = new FormControl();

    private _oldValue: string = '';

    public ngOnInit(): void 
        this.maskInput.valueChanges
            .subscribe((value: string) => 
                    let valid = this.isValidValueByMask(value, this.mask);
                    if (valid) 
                        this._oldValue = value;
                     else 
                        value = this._oldValue;
                    

                    this._onChangeCallback(value);
                    this.onChange.emit(value);

                    this.maskInputEl.nativeElement.value = value; 
                ,
                (err) => console.warn(err)
            );
    

    public toggleActive(value) 
        //
    

    public registerOnChange(fn: any): void 
        this._onChangeCallback = fn;
    

    public registerOnTouched(fn: any): void 
        this._onTouchedCallback = fn;
    

    public _onChangeCallback: Function = (_: any) => 
        //
    

    public _onTouchedCallback: Function = (_: any) => 
        //
    

    public makeActive() 
        this.maskInputEl.nativeElement.focus();
    

    public writeValue(value: string): void 
        this.maskInput.setValue(value);
    

    public ngOnDestroy(): void 
        //
    

    private isValidValueByMask(value: string, mask: RegExp[]): boolean 
        //
    

【问题讨论】:

【参考方案1】:

是的,这是可能的。我为自己的项目做了类似的事情,我想创建一个MoneyFieldComponent,它返回一个以美分为单位的值,但允许用户以美元和美分输入他们的货币价值。

基本概念是您的组件必须存储原始值,但是,您在文本字段中显示格式化的值。此外,当用户与您的文本字段交互时,您会使用原始值更新组件的“内部值”。

请注意,您不应该使用 ngModel 来更新您的文本字段 - ngModel 有一些异步行为会在这些情况下造成严重破坏 - 您可以使用原始 javascript 完成相同的操作(或者在我的情况下,我使用了 FormControl) .

示例:

@Component(
  selector: 'ec-money-field',
  template: `
      <md-input-container *ngIf="editMode">
          <input #input mdInput class="value" type="text"
                 (input)="updateInnerValue(input.value)"
                 (blur)="formatTextValue()"
                 [formControl]="control" />
      </md-input-container>
  `,
  providers: [
    provide: NG_VALUE_ACCESSOR, multi: true, useExisting: forwardRef(() => MoneyFieldComponent),
  ]
)
export class MoneyFieldComponent implements OnInit, ControlValueAccessor 

  private valueInCents = 0;
  control = new FormControl(0);

  private onChange: Function = (_: any) => ;
  private onTouch: Function = (_: any) => ;

  constructor()  

  @Input()
  get value(): number 
    return this.valueInCents;
  ;

  // if you update the component by using the value property,
  // propagate that change to the text field    
  set value(newValueInCents: number) 
    this.valueInCents = newValueInCents;
    this.control.setValue(centsToDollars(newValueInCents));
  

  ngOnInit() 
  

  // convert the masked value - i.e. what the user types
  // into the actual numerical value that will be stored
  // You'll have to provide your own conversion function 
  // to convert the user typing 1(855) 555 1234 to 1865551234
  updateInnerValue(dollarValueString: string) 
    this.valueInCents = dollarsToCents(dollarValueString);
    this.onChange(this.valueInCents);
  

  formatTextValue() 
    this.value = this.value;
  

  writeValue(newValue: number): void 
    this.value = newValue;
  

  registerOnChange(fn: any): void 
    this.onChange = fn;
  

  registerOnTouched(fn: any): void 
    this.onTouch = fn;
  

请注意,以上是该组件的简化版本。 The full version can be found on Github.

【讨论】:

我需要相反的,即用户输入清除数据并使用掩码输入转换该数据 但您仍然存储“清除数据”对吗?如果是这样,这是相同的基本概念 - 在用户键入后,您使用格式化值更新 formField,但您将实际值存储在组件中。如果您仅将 formField 更新为模糊时的格式化值,则更容易实现 - 尝试在每个输入事件上执行此操作似乎并不能提供良好的用户体验 - 但如果您尝试提供输入掩码,那么您别无选择,只能更新输入事件的格式化值。如果您遇到问题,我可以更新示例代码

以上是关于如何在自定义控件中屏蔽值的主要内容,如果未能解决你的问题,请参考以下文章

如何让其他控件在自定义控件中看到 DataTables 的集合?

如何在自定义用户控件上创建单击事件?

如何在自定义嵌套用户控件中引用另一个 XAML 元素?

如何在自定义用户控件中为 ListBox ItemTemplate 属性设置适当的上下文

如何在自定义 wpf 控件上绑定数据网格列的可见性?

强制在自定义 WPF 控件中重新绘制自定义绘制的 UIElement