如何在角度 2 中将输入值转换为大写(传递给 ngControl 的值)

Posted

技术标签:

【中文标题】如何在角度 2 中将输入值转换为大写(传递给 ngControl 的值)【英文标题】:How to convert input value to uppercase in angular 2 (value passing to ngControl) 【发布时间】:2016-06-19 23:24:25 【问题描述】:

我正在尝试使用 ngControl 在角度 2 中的值来验证输入字段。 我需要验证用户是否始终以大写形式输入值。

现在我们需要将用户输入的值转换为大写。但我正在使用 ngControl 处理来自输入字段的值,而不是 ngModel(考虑到我可以使用 ngModelChange 事件将值更新为大写。)

那么转换 ngControl 使用的值的最佳且低成本的方法是什么。

【问题讨论】:

能否给我们看一些代码或到目前为止你做了什么? <input type="text" #input [value]="input.value.toUpperCase()" /> 你回答完了吗? 可能考虑使用 CSS。 text-transform:uppercase; 将其设为大写? @frosty css 类只会影响视觉外观,不会影响实际值。 【参考方案1】:

我将创建一个 ControlValueAccessor 的自定义实现。后者对应于监听主机输入事件的指令。这样您就可以将用户填写的内容输入大写。控件将自动包含大写的值。

这里是实现:

@Directive (
  selector: 'input[uppercase]',
  // When the user updates the input
  host:  '(input)': 'onChange($event.target.value.toUpperCase())' 
)
export class UppercaseValueAccessor extends DefaultValueAccessor 
  (...)

  // When the code updates the value of the
  // property bound to the input
  writeValue(value:any):void 
    if (value!=null) 
      super.writeValue(value.toUpperCase());
    
  

不要忘记在指令提供者中注册这个自定义值访问器。这样,您的自定义值访问器将被使用而不是默认访问器。

const UPPERCASE_VALUE_ACCESSOR = new Provider(NG_VALUE_ACCESSOR,  useExisting: forwardRef(() => UppercaseValueAccessor), multi: true);

@Directive (
  providers: [ UPPERCASE_VALUE_ACCESSOR ],
  (...)
)
export class UppercaseValueAccessor ...

并在要使用此方法的组件的指令属性中添加指令。

查看这个课程了解更多详情:

https://github.com/angular/angular/blob/master/modules/angular2/src/common/forms/directives/default_value_accessor.ts

此链接可能会提供其他提示(请参阅“NgModel-compatible component”部分):

http://restlet.com/blog/2016/02/17/implementing-angular2-forms-beyond-basics-part-2/

【讨论】:

为了使其与验证([class.invalid]="myControl.touched && !myControl.valid)一起工作,响应输入事件我需要调用super.writeValue(updatedValue); this.onTouched(); this.onChange(updatedValue); DefaultValueAccessor source 自 4.3.2 起【参考方案2】:

正如@Eric Martinez 建议的那样,您可以创建一个本地模板变量,并将大写字符串绑定到输入事件的 value 属性:

<input type="text" #input (input)="input.value=$event.target.value.toUpperCase()" />

或者,您可以将其设为指令:

@Directive(
    selector: 'input[type=text]',
    host: 
        '(input)': 'ref.nativeElement.value=$event.target.value.toUpperCase()',
    

)
export class UpperCaseText 
    constructor(private ref: ElementRef) 
    

要使用该指令,请在组件的指令列表中指定 UpperCaseText

directives: [UpperCaseText]

Demo Plnkr

【讨论】:

如果在 beta 9 中实现,这将产生错误。'值在上次检查后发生变化' 我还是明白了。因为 (ngModelChange) 也不起作用,所以我根本不做它来修复它。 你确定是上面的代码导致了这个问题吗?我没有收到任何错误 这条线不起作用:&lt;input type="text" #input (input)="input.value=$event.target.value.toUpperCase()" /&gt; input.value=$event.target.value.toUpperCase()" 在这个实现中,如果最后一个字符是小写的。它保持原样。角度 4.3【参考方案3】:

这是我的更通用的解决方案,它基本上类似于 DefaultValueAccessor 添加了文本“转换器”功能。所以你会使用

<input mdInput [transformer]="uppercase" ...>

在您的组件中,您拥有大写功能(除了大写之外,您还可以执行其他操作,例如实现掩码)...

  uppercase(value: string) 
    return value.toUpperCase();
  

指令...

import  NG_VALUE_ACCESSOR, ControlValueAccessor  from '@angular/forms';
import  Directive, forwardRef, Input, OnChanges, SimpleChanges, Renderer, ElementRef  from '@angular/core';
import  TextMaskModule, MaskedInputDirective  from 'angular2-text-mask';

@Directive(
  selector: 'input[transformer]',
  // When the user updates the input
  host:  '(input)': 'handleInput($event.target.value)', '(blur)': 'onTouched()' ,
  providers: [
     provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => TextTransformerDirective), multi: true ,
  ]

)
export class TextTransformerDirective implements ControlValueAccessor 
  private inputElement: htmlInputElement
  lastValue = "";
  onTouched = () =>  
  onChange = (_: any) =>  
  @Input('transformer')
  transformer = (v: string) => v;

  constructor(private renderer: Renderer, private element: ElementRef) 

  

  handleInput(value: any) 
    let newVal = this.transformer(value);
    if (newVal != value || this.lastValue != newVal) 
      this.lastValue = newVal;
      this.renderer.setElementProperty(this.element.nativeElement, 'value', newVal);
      this.onChange(newVal);
    
  

  writeValue(value: any) 
    let normalizedValue = value == null ? '' : value;
    normalizedValue = this.transformer(normalizedValue);
    this.renderer.setElementProperty(this.element.nativeElement, 'value', normalizedValue);
  

  registerOnChange(fn: (value: any) => any): void  this.onChange = fn 

  registerOnTouched(fn: () => any): void  this.onTouched = fn 


【讨论】:

在我看来很多片段都和DefaultAccessor一样。为什么不继承它,只添加不同的东西?【参考方案4】:

这是我的解决方案:

使用主机监听器监听输入事件,然后将其强制为大写。

import Directive, EventEmitter, HostListener, Output from '@angular/core';
@Directive(
  selector: '[ngModel][uppercase]'
)
export class UppercaseDirective 
  @Output() ngModelChange: EventEmitter<any> = new EventEmitter();
  value: any;

  @HostListener('input', ['$event']) onInputChange($event) 
    this.value = $event.target.value.toUpperCase();
    this.ngModelChange.emit(this.value);
  

使用此指令,您可以轻松地将输入强制为大写,如下所示:

<input type="text" class="form-control" placeholder="ID"
           formControlName="id" [(ngModel)]="form.value.id" uppercase/>

【讨论】:

简单、优雅、有效、轻松。选择器的顺序无关紧要,因此如果您需要根据 Angular 标准遵守 TS linting,它们可以颠倒过来。这应该是国际海事组织接受的答案。干得好! 我的坏了,我忘记了什么? 1)创建类,2)在我的 SharedModule.ts 上导入,3)在 MyPage.ts 上导入 SharedModule.ts 并像上面的示例一样设置字段。 @franzisk_br 您是否从 SharedModule 导出指令? 最后一个字符是小写的,我该如何解决这个问题? (我正在使用角度 6) 根据我读过的一些帖子,我在 Angular 7 中为大写和小写开发了一个解决方案。但我只测试了反应形式。该方案解决了最后一个单词和光标位置的问题。 stackblitz.com/edit/angular-form-uppercase-lowercase【参考方案5】:

pixelbits 提供了一个很好的解决方案,但它在最新版本的 Angular (v4.3.1) 中不起作用,因为指令从组件中贬值。我的解决方案仅基于他的回答,但适用于最新的

我正在提供一个带有自定义属性指令的通用解决方案,它带有一个布尔输入,如果它是真的,它将把输入转换为大写。

大写.directive.ts:

     import  Directive, ElementRef, Input  from '@angular/core';
     @Directive(
     selector: '[UpperCase]',
     host: 
        '(input)': 'toUpperCase($event.target.value)',

     

    )
    export class UpperCaseTextDirective  

    @Input('UpperCase') allowUpperCase: boolean;
    constructor(private ref: ElementRef) 
    

    toUpperCase(value: any) 
        if (this.allowUpperCase)
        this.ref.nativeElement.value = value.toUpperCase();
    

    

这里是模板对应的App组件。

app.ts

    //our root app component
   import Component, NgModule, VERSION from '@angular/core'
   import BrowserModule from '@angular/platform-browser'
   import UpperCaseTextDirective from './upper-case.directive'

    @Component(
    selector: 'my-app',
    template: `
    <div>
      <h2>Hello name</h2>
      Auto Capitalize True: <input [UpperCase]="true" type="text" #input />
    <br/>
     Auto Capitalize False: <input [UpperCase]="allowEdit" type="text"/>

    </div>
    `,
    )
    export class App 
    name:string;
    allowEdit:boolean;
    constructor() 
    this.name = `Angular! v$VERSION.full`;
    this.allowEdit= false;
    
     

     @NgModule(
    imports: [ BrowserModule ],
    declarations: [ App,UpperCaseTextDirective ], 
    bootstrap: [ App ]
    )
   export class AppModule 

这里有一个Plnkr 证明了这一点。

【讨论】:

用反应式和模板驱动的表单测试,工作正常!【参考方案6】:

至少根据我的经验,我发现这里有两个答案很有见地,但不能单独工作:from Thierry Templier(也有第一条评论)和from cal。

我将两者的部分放在一起,并提出了这个版本,它现在以反应形式与 Angular 4.1.1 一起使用:

import  Directive, Renderer, ElementRef, forwardRef  from '@angular/core';
import  NG_VALUE_ACCESSOR, DefaultValueAccessor  from '@angular/forms';

const LOWERCASE_INPUT_CONTROL_VALUE_ACCESSOR = 
  provide: NG_VALUE_ACCESSOR,
  useExisting: forwardRef(() => LowerCaseInputDirective),
  multi: true,
;

@Directive(
  selector: 'input[lowercase]',
  host: 
    // When the user updates the input
    '(input)': 'onInput($event.target.value)',
    '(blur)': 'onTouched()',
  ,
  providers: [
    LOWERCASE_INPUT_CONTROL_VALUE_ACCESSOR,
  ],
)
export class LowerCaseInputDirective extends DefaultValueAccessor 

  constructor(renderer: Renderer, elementRef: ElementRef) 
    super(renderer, elementRef, false);
  

  writeValue(value: any): void 
    const transformed = this.transformValue(value);

    super.writeValue(transformed);
  

  onInput(value: any): void 
    const transformed = this.transformValue(value);

    super.writeValue(transformed);
    this.onChange(transformed);
  

  private transformValue(value: any): any 
    const result = value && typeof value === 'string'
      ? value.toLowerCase()
      : value;

    return result;
  

这是用于小写的,但也适用于大写,只需重命名指令,在selectortransformValue 内替换。

编辑: 使用此类指令的 HTML 代码的简单用法示例:

<input id="myField"
       formControlName="myField"
       type="text" class="form-control required" 
       lowercase>

【讨论】:

我很高兴找到您的解决方案@superjos,但我无法将它与同一输入元素上的 [formControlName] 指令结合使用。你让它工作了吗? 很高兴它以某种方式有所帮助。是的,它确实有效,只是添加了一个使用示例。仔细检查一下:您是否真的在某个模块中的声明和/或导出组件列表中添加了指令? @superjos 我在 Angular 8 中使用了你的方法,我不能在装饰器中使用主机绑定,所以我使用了主机监听器,它就像一个魅力 :) 附带说明,如果我们使用主机监听器捕获输入事件,我们应该停止传播并阻止默认 $event.preventDefault(); $event.stopPropagation(); 对不起,我帮不上忙,我已经远离这个特定的角度有一段时间了【参考方案7】:

这是我正在使用 angular4 的工作代码

这是你的大写指令

import  Directive, ElementRef, HostListener  from '@angular/core';

@Directive(
  selector: '[appUpper]'
)
export class UpperDirective 

  constructor(public ref: ElementRef)  

  @HostListener('input', ['$event']) onInput(event) 
    this.ref.nativeElement.value = event.target.value.toUpperCase();
  


这是您使用大写指令的 html 文件代码

<input type="text" id="id" placeholder="id" tabindex="0" formControlName="id" appUpper>

【讨论】:

这很好用,但是如果我在模板驱动的表单上有这个,一旦我提交表单,我得到的值都是大写的,除了最后一个字符。所以如果我输入:'aaa',这个指令会转换为'AAA',但是一旦我提交,我得到的值是'AAa' @robert 你修好了吗? @AlexanderRojas 这看起来很有希望:***.com/a/46832182/2050306【参考方案8】:

没有指令的简单代码

在输入文本的模糊事件中,调用一个将值更改为大写的方法,我的称为“cambiaUpper”

<input id="shortsel" type="text" class="form-control m-b-12" #shortsel="ngModel" name="shortsel" [(ngModel)]="_stockprod.shortName" (blur)="cambiaUpper($event)"/>

并在组件(yourComponentFile.ts)中创建这个接收事件的方法,从事件中获取值并将其更改为大写。

public cambiaUpper(event: any) 
      event.target.value = event.target.value.toUpperCase();

多田!

【讨论】:

【参考方案9】:
<input type="text" oninput="this.value = this.value.toUpperCase()">
works good in angular to get every symbol to be a big one :)

【讨论】:

这兼容所有最新浏览器的设备吗?【参考方案10】:

input 文本中的blur 事件中,会将值更改为大写

<input type="text" id="firstName" name="firstName" (blur)="$event.target.value = $event.target.value.toUpperCase()">

【讨论】:

干净简单。喜欢。

以上是关于如何在角度 2 中将输入值转换为大写(传递给 ngControl 的值)的主要内容,如果未能解决你的问题,请参考以下文章

如何在角度 4 中使用 ng-bootstrap 将数据模态组件传递给父组件

角度 ng-model 无法捕获加载输入值

如何在 Bash 中将字符串从大写转换为小写? [复制]

如何将使用 ng-repeat 动态创建的 html 表单的输入元素的值传递给 ng-controller

在 Tensorflow C++ 中将浮点向量传递给张量

在 Python 中将十六进制转换为 RGB 值