【问题标题】:Directive to upper case input fields指向大写输入字段的指令
【发布时间】:2018-03-31 04:58:26
【问题描述】:

我想使用指令将所有输入数据转换为大写。为此,我创建了这个自定义指令:

@Directive({
  selector: '[appToUpperCase]'
})
export class ToUpperCaseDirective {

  constructor() {}

  @HostListener('input', ['$event']) onKeyUp(event) {
    event.target['value'] = event.target['value'].toUpperCase();
  }

}

我就是这样使用它的:

<form [formGroup]="formGroup" appToUpperCase>

当我在我的字段中输入文本时,它几乎可以正常工作,大写转换是永久的,但焦点设置在字段的末尾......所以当我编辑预填充的输入时,如果我想修改数据的开头,我要在每次Keyup事件后将焦点设置在正确的位置...

我该如何解决这个问题?

【问题讨论】:

    标签: angular directive uppercase


    【解决方案1】:

    根据我读过的一些帖子,我在 Angular 7 中为大写和小写开发了一个解决方案。但我只测试了反应形式。该方案解决了最后一个单词和光标位置的问题。

    // user.component.html
    <input  type="text" name="name" class="form-control" formControlName="name" uppercase />
    
    
    // user.component.ts
    import { Directive, ElementRef, HostListener } from '@angular/core';
    @Directive({
    selector: '[uppercase]',
      host: {
        '(input)': '$event'
      }
    })
    export class UppercaseInputDirective {
    
      lastValue: string;
    
      constructor(public ref: ElementRef) { }
    
      @HostListener('input', ['$event']) onInput($event) 
      {
        var start = $event.target.selectionStart;
        var end = $event.target.selectionEnd;
        $event.target.value = $event.target.value.toUpperCase();
        $event.target.setSelectionRange(start, end);
        $event.preventDefault();
    
        if (!this.lastValue || (this.lastValue && $event.target.value.length > 0 && this.lastValue !== $event.target.value)) {
          this.lastValue = this.ref.nativeElement.value = $event.target.value;
          // Propagation
          const evt = document.createEvent('HTMLEvents');
          evt.initEvent('input', false, true);
          event.target.dispatchEvent(evt);
        }
      }
    }
    

    我在这里发帖stackblitz

    【讨论】:

    • 为什么你需要这样做$event.target.setSelectionRange(start, end);?你能解释一下吗
    • 起初看起来不错,但撤消似乎不起作用(在 Chrome 81 上)。
    【解决方案2】:

    对于响应式表单输入(以及文本区域),我可以使用它:

    import { Directive, HostListener } from '@angular/core';
    import { NgControl } from '@angular/forms';
    
    @Directive({
      selector: '[formControlName][inputUppercase]'
    })
    export class InputUppercaseDirective {
    
      constructor(
        private readonly control: NgControl
      ) { }
    
      @HostListener('input', ['$event.target'])
      public onInput(input: HTMLInputElement): void {
        const caretPos = input.selectionStart;
        this.control.control.setValue(input.value.toUpperCase());
        input.setSelectionRange(caretPos, caretPos);
      }
    }
    

    【讨论】:

      【解决方案3】:

      基本上,当您从命令式代码中修改值时,管理光标位置变得很困难。当您重写值输入值时,它会在输入的开头抛出光标。

      我建议您采用 CSS 方式。更干净

      [my-attribute] input { text-transform: uppercase; }
      

      【讨论】:

      • 问题是CSS以大写显示数据但不转换值。我有很多页面,有很多表单,所以我想要一种简单的方法将传入的数据转换为大写,以便在显示和模型中显示。这就是我使用指令的原因
      • @JulienAZEMA 我会选择这个,你会得到视觉外观,似乎你有一个表单,所以你可以做的是在提交时你可以迭代表单对象属性并将它们转换为大写:)
      【解决方案4】:

      Pankaj 的想法比创建指令要好。您只需发送 data.toUpperCase()。无论如何,如果你想使用这样的指令。注意,我们不仅必须使用 preventDefault(),还必须 dispatch event change

      import { Directive,HostListener } from '@angular/core';
      
      @Directive({
        selector: '[appToUpperCase]'
      })
      export class ToUpperCaseDirective {
      
        constructor() { }
      
        @HostListener('keydown', ['$event']) onKeyDown(event:KeyboardEvent) {
          if (event.keyCode>32 && event.keyCode<128)
         {
            event.target['value']+=event.key.toUpperCase();
            event.preventDefault(); //stop propagation
            //must create a "input" event, if not, there are no change in your value
            var evt = document.createEvent("HTMLEvents");
            evt.initEvent("input", false, true);
            event.target.dispatchEvent(evt);
          }
      
        }
      
      }
      

      【讨论】:

      • event.keyCode>32 && event.keyCodekeycode.info我更喜欢使用 onInput 事件。
      【解决方案5】:
      import { Directive, ElementRef, HostListener } from '@angular/core';
      
      @Directive({
        selector: '[lowercaser]'
      })
      export class LowerCaserDirective {
      
        lastValue: string;
      
        constructor(public ref: ElementRef) {
        }
      
        @HostListener('input', ['$event']) onInput(event) {
          const resEventValue = event.target.value.toLowerCase();
          // Avoid max call
          if (!this.lastValue || (this.lastValue && event.target.value.length > 0 && this.lastValue !== resEventValue)) {
            this.lastValue = this.ref.nativeElement.value = resEventValue;
            // Propagation
            const evt = document.createEvent('HTMLEvents');
            evt.initEvent('input', false, true);
            event.target.dispatchEvent(evt);
          }
        }
      
      }
      

      【讨论】:

      【解决方案6】:
      <input class="form-control form-control-sm" id="area" type="text" formControlName="carea" #carea (keyup)="makeUpperCase(addform.get('carea'))"
      
      
      makeUpperCase(control: FormControl) {
      control.setValue(control.value.toUpperCase());
      

      }

      在您的 util.servce.ts 或 component.ts 中创建一个函数,将表单控件作为输入,为该控件设置值,如代码中所述。

      从你的component.html调用这个函数,如图所示。

      【讨论】:

        【解决方案7】:

        由于@robert 提到的 initEvent 的弃用而升级@Leasye 答案 我已经使用 Event 类来创建事件。 我还使用 Renderer2 的 setProperty() 方法为输入元素赋值,而不是直接将其赋值给 DOM 对象。

        import { Directive, ElementRef, HostListener, Renderer2 } from '@angular/core';
        
        @Directive({
          selector: '[appTextUppercase]'
        })
        export class TextUppercaseDirective {
          preValue: string = "";
        
          constructor(private elmRef: ElementRef, private renderer: Renderer2) { }
        
          @HostListener('input', ['$event']) onInput(event: any) {
            const text_upper = event.target.value.toUpperCase();
            if (!this.preValue || (this.preValue && text_upper && this.preValue !== text_upper)) {
              this.preValue = text_upper;
              this.renderer.setProperty(this.elmRef.nativeElement, 'value', text_upper);
              const htmlEvent = new Event('input', { "bubbles": false, "cancelable": true         
            });
                document.dispatchEvent(htmlEvent);
                }
            };
        }

        但是,想指出上述指令中的一个问题,即在通过向后移动光标来编辑字段值的情况下,它不会绑定最后编辑的字符。在这种情况下,@Andy 的解决方案可以正常工作。

        【讨论】:

          猜你喜欢
          • 2018-07-10
          • 2017-11-12
          • 2017-01-14
          • 2014-02-11
          • 1970-01-01
          • 2019-11-25
          • 1970-01-01
          • 1970-01-01
          • 2015-12-21
          相关资源
          最近更新 更多