Угловое 4 - Преобразование значения текстового поля в верхний регистр на лету [дубликат]

$('#sortable').find('li').each(function(){ var listId = $(this).attr("id"); });

Возможно, это сработает ...

9
задан Fred 6 March 2016 в 13:07
поделиться

7 ответов

Вот мое более общее решение, которое в основном похоже на 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 }

}
1
ответ дан Cal 20 August 2018 в 10:42
поделиться
  • 1
    Мне кажется, что много штук - это то же самое, что и DefaultAccessor. Почему бы не унаследовать от этого и добавить только то, что другое? – superjos 1 August 2017 в 23:50
  • 2
    Это, наверное, хорошая идея! – Cal 3 August 2017 в 04:07

Вот мой рабочий код, я использую 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>
0
ответ дан Hemant Sharma 20 August 2018 в 10:42
поделиться

pixelbits предоставил отличное решение, но оно не работает в последней версии Angular (v4.3.1), поскольку директивы обесцениваются из компонента. Мое решение основано на его ответе только, но работает с последним

. Я предоставляю общее решение с настраиваемой директивой атрибута с логическим вводом, который будет скрывать ввод в верхний регистр, если это правда.

upper-case.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.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 , которые демонстрируют это.

4
ответ дан KIA 20 August 2018 в 10:42
поделиться
  • 1
    протестированы как с реактивной, так и с шаблонной формой, работает нормально! – Burak Tasci 22 August 2017 в 15:51

Как предложил @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

25
ответ дан pixelbits 20 August 2018 в 10:42
поделиться
  • 1
    Это даст ошибку, если она будет реализована в бета-версии 9. «Значение изменилось после последнего его проверки» – RoninCoder 24 March 2016 в 20:54
  • 2
    Исправлено для бета-версии 9. – pixelbits 25 March 2016 в 05:44
  • 3
    Я все еще понимаю. Я исправил это, не делая этого вообще, поскольку (ngModelChange) тоже не работает. – RoninCoder 25 March 2016 в 19:40
  • 4
    Вы уверены, что этот код вызывает вышеупомянутый код? Я не получаю никаких ошибок – pixelbits 25 March 2016 в 23:37
  • 5
    эта строка не работает: <input type="text" #input (input)="input.value=$event.target.value.toUpperCase()" /> – RoninCoder 27 March 2016 в 23:52

Вот мое решение:

Использование хост-слушателя для прослушивания входного события, а затем принудительного его ввода в верхний регистр.

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/>
15
ответ дан subaru710 20 August 2018 в 10:42
поделиться
  • 1
    Работает хорошо, элегантно, без проблем + – prajeesh kumar 13 July 2017 в 14:58
  • 2
    Простой, элегантный, эффективный, без проблем. Порядок селекторов не имеет значения, поэтому их можно отменить, если вам необходимо выполнить TS-листинг против угловых стандартов. Это должен быть принятый ответ ИМО. Отлично сработано! – MBielski 28 September 2017 в 14:20
  • 3
    Это не будет работать с реактивными формами, или? – Spock 18 October 2017 в 11:06
  • 4
    Работали как очарование с реактивной формой. – I.Tyger 25 November 2017 в 13:57
  • 5
    Моя не работала, что я забыл? 1) создал класс, 2) импортированный на моем SharedModule.ts, 3) импортировал SharedModule.ts на MyPage.ts и установил поле точно так же, как в приведенном выше примере. – franzmobile 9 December 2017 в 17:00

По крайней мере, по моему опыту, я нашел два ответа здесь проницательными, но не работал сам по себе: из Thierry Templier (с первым комментарием), а из 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;
  }
}

Это для нижнего регистра, но все верно и для верхнего строчка, просто переименуйте директиву, замените внутри selector и transformValue.

Edit: простой пример использования из HTML-кода с использованием такой директивы:

<input id="myField"
       formControlName="myField"
       type="text" class="form-control required" 
       lowercase>
5
ответ дан superjos 20 August 2018 в 10:42
поделиться
  • 1
    Я был рад найти ваше решение @superjos, но я не получаю его работать в сочетании с директивой [formControlName] на том же элементе ввода. Вы получили это на работу? – Johan Sundström 24 October 2017 в 11:44
  • 2
    Рад, что это помогает. Да, это действительно работает, просто добавил пример использования. Просто двойная проверка: действительно ли вы добавляли директиву в список объявленных и / или экспортированных компонентов в каком-то модуле? – superjos 25 October 2017 в 10:26

Я бы создал пользовательскую реализацию 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 ...

И добавьте директиву в атрибут директивы компонента, в котором вы хотите использовать этот подход.

См. Этот класс для более подробной информации:

Эта ссылка может давать дополнительные подсказки (см. раздел «Компонент, совместимый с NgModel»):

7
ответ дан Thierry Templier 20 August 2018 в 10:42
поделиться
  • 1
    Чтобы заставить его работать с проверкой ([class.invalid]="myControl.touched && !myControl.valid), в ответ на входное событие мне нужно было вызвать super.writeValue(updatedValue); this.onTouched(); this.onChange(updatedValue); – cghislai 13 April 2016 в 15:15
  • 2
    Источник DefaultValueAccessor по состоянию на 4.3.2 – superjos 1 August 2017 в 23:21
Другие вопросы по тегам:

Похожие вопросы: