J'essaie de valider les champs de saisie en utilisant la valeur de ngControl dans angular 2 . Je dois valider que l'utilisateur entre toujours la valeur en majuscule.
Nous devons maintenant convertir la valeur entrée par l'utilisateur en majuscule. Mais je gère les valeurs des champs d'entrée à l'aide de ngControl, pas de ngModel (étant donné que j'aurais pu utiliser l'événement ngModelChange pour mettre à jour la valeur en majuscule.)
Quel est donc le moyen le plus économique et le plus économique de convertir la valeur utilisée par ngControl?
Comme @Eric Martinez l'a suggéré, vous pouvez créer une variable de modèle local et lier la chaîne en majuscule à la propriété value de l'événement d'entrée:
<input type="text" #input (input)="input.value=$event.target.value.toUpperCase()" />
Alternativement, vous pouvez en faire une directive:
@Directive({
selector: 'input[type=text]',
Host: {
'(input)': 'ref.nativeElement.value=$event.target.value.toUpperCase()',
}
})
export class UpperCaseText {
constructor(private ref: ElementRef) {
}
}
Pour utiliser la directive, spécifiez UpperCaseText
dans la liste de directives de votre composant:
directives: [UpperCaseText]
Voici ma solution:
Utiliser le programme d'écoute hôte pour écouter l'événement d'entrée, puis le forcer en majuscule.
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);
}
}
Avec cette directive, vous pouvez facilement forcer les entrées en majuscules comme ceci:
<input type="text" class="form-control" placeholder="ID"
formControlName="id" [(ngModel)]="form.value.id" uppercase/>
Je créerais une implémentation personnalisée de ControlValueAccessor. Ce dernier correspondrait à une directive qui écouterait l'événement d'entrée de l'hôte. De cette façon, vous pourrez mettre en majuscule ce que vous remplissez. Le contrôle contiendra automatiquement la valeur en majuscule.
Voici l'implémentation:
@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());
}
}
}
N'oubliez pas d'enregistrer cet accesseur de valeur personnalisé dans les fournisseurs de directives. De cette façon, votre accesseur de valeur personnalisé sera utilisé à la place de celui par défaut.
const UPPERCASE_VALUE_ACCESSOR = new Provider(NG_VALUE_ACCESSOR, { useExisting: forwardRef(() => UppercaseValueAccessor), multi: true});
@Directive ({
providers: [ UPPERCASE_VALUE_ACCESSOR ],
(...)
})
export class UppercaseValueAccessor ...
Et ajoutez la directive dans l'attribut directives du composant où vous souhaitez utiliser cette approche.
Voir cette classe pour plus de détails:
Ce lien pourrait donner des conseils supplémentaires (voir la section "Composant compatible NgModel):
Au moins d'après mon expérience, j'ai trouvé deux réponses intéressantes, mais qui ne fonctionnaient pas seules: de Thierry Templier (avec le premier commentaire également), et de cal .
J'ai assemblé des parties des deux et j'ai créé cette version, qui fonctionne maintenant avec Angular 4.1.1 sous une forme réactive:
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;
}
}
Ceci est pour les minuscules, mais tout est valable pour les majuscules également, il suffit de renommer la directive, de remplacer dans selector
et transformValue
.
Modifier:
Un exemple d'utilisation simple tiré du code HTML utilisant cette directive:
<input id="myField"
formControlName="myField"
type="text" class="form-control required"
lowercase>
pixelbits a fourni une excellente solution, mais cela ne fonctionne pas dans la dernière version de Angular (v4.3.1) car les directives sont amorties par rapport aux composants. Ma solution est basée sur sa réponse seulement mais fonctionne avec les dernières
Je fournis une solution générique avec une directive d'attribut personnalisée avec une entrée booléenne qui convertira l'entrée en majuscule si elle est vraie.
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();
}
}
Voici le composant App correspondant au modèle.
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 {}
Voici un Plnkr qui le démontre.
Voici mon code de travail que j'utilise angular4
Ceci est votre directive pour les majuscules
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();
}
}
Ceci est votre code de fichier HTML où vous avez utilisé la directive majuscule
<input type="text" id="id" placeholder="id" tabindex="0" formControlName="id" appUpper>
Voici ma solution plus générique qui ressemble fondamentalement à DefaultValueAccessor avec une fonction "transformateur" de texte ajoutée. Donc, vous utiliseriez
<input mdInput [transformer]="uppercase" ...>
Dans votre compontent vous avez la fonction majuscule (vous pouvez faire autre chose que majuscule comme mettre en place un masque) ...
uppercase(value: string) {
return value.toUpperCase();
}
Directif...
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 }
}
Code simple sans directives
Dans l'événement flou de votre texte d'entrée, appelez une méthode qui modifie la valeur en majuscule, la mienne s'appelle "cambiaUpper".
<input id="shortsel" type="text" class="form-control m-b-12" #shortsel="ngModel" name="shortsel" [(ngModel)]="_stockprod.shortName" (blur)="cambiaUpper($event)"/>
Et dans le composant (yourComponentFile.ts), créez cette méthode qui reçoit l'événement, obtenez la valeur de l'événement et modifiez-la en majuscule.
public cambiaUpper(event: any) {
event.target.value = event.target.value.toUpperCase();
}
Tada!