Директива атрибута с ngModel для изменения значения поля
Я хочу изменить (принудительно) значения поля ввода при вводе с использованием атрибута Directive. С его помощью я хотел бы создать директивы, такие как прописные, строчные, maxlength, filterchar и т. Д., Которые будут использоваться в полях ввода в формах. Я нашел этот пример: Пример типизированной директивы Angular 2 Attribute, но, похоже, это не работает. Возможно, это было сделано для более ранней сборки Angular2. Это именно то, что я хотел бы сделать.
Когда я создаю директиву, как это:
import {Directive} from 'angular2/core';
import {NgModel} from 'angular2/common';
@Directive({
selector: '[ngModel][uppercase]',
host: {
'(input)' : 'onInputChange()'
}
})
export class UppercaseDirective{
constructor(public model:NgModel){}
onInputChange(){
var newValue = this.model.value.toUpperCase();
this.model.valueAccessor.writeValue(newValue);
this.model.viewToModelUpdate(newValue);
}
}
И используйте его в такой форме:
<input type="text" class="form-control" [(ngModel)]="field.name" ngControl="name" #name="ngForm" required uppercase>
(и зарегистрируйтесь NgModel
в качестве поставщика). Я получаю
undefined this.model.value.
я могу использовать $event.target.value = $event.target.value.toUpperCase()
(при прохождении $event
с onInputChange()
) и это работает для представления (оно показывает ввод в верхнем регистре. Но оно не обновляет поле привязки "field.name".
Итак, как создать директиву атрибута Angular2, которая делает это?
-- РЕДАКТИРОВАТЬ --
После некоторого дальнейшего расследования мне удалось получить то, что я хочу. Ответ, предоставленный Гюнтером, ближе к моему первоначальному замыслу и, возможно, лучше. Но вот другой способ:
import {Directive, Input, Output, EventEmitter} from 'angular2/core';
@Directive({
selector: '[ngModel][uppercase]',
host: {
"(input)": 'onInputChange($event)'
}
})
export class UppercaseDirective{
@Output() ngModelChange:EventEmitter<any> = new EventEmitter()
value: any
onInputChange($event){
this.value = $event.target.value.toUpperCase()
this.ngModelChange.emit(this.value)
}
}
Как я уже сказал, я не уверен, что это также хороший способ сделать это, поэтому комментарии приветствуются.
3 ответа
Обновить
Этот подход не работает должным образом. Смотрите ответ @RyanHow для лучшего решения.
оригинал
@Directive({
selector: '[ngModel][uppercase]',
providers: [NgModel],
host: {
'(ngModelChange)' : 'onInputChange($event)'
}
})
export class UppercaseDirective{
constructor(private model:NgModel){}
onInputChange(event){
this.model.valueAccessor.writeValue(event.toUpperCase());
}
}
Хотя ответ Гюнтера выглядит многообещающе, есть ошибка в том, что конечное значение в модели имеет последнюю введенную букву в нижнем регистре.
Посмотреть здесь:
https://plnkr.co/edit/SzxO2Ykg2pKq1qfgKVMH
Пожалуйста, используйте ответ, указанный в вопросе. Работает правильно.
@Directive({
selector: '[ngModel][uppercase]',
host: {
"(input)": 'onInputChange($event)'
}
})
export class UppercaseDirective{
@Output() ngModelChange:EventEmitter<any> = new EventEmitter()
value: any
onInputChange($event){
this.value = $event.target.value.toUpperCase()
this.ngModelChange.emit(this.value)
}
}
Требование, которое я должен был создать директиву, чтобы обрезать начальные и конечные пробелы для ввода текста. мое решение:
import { Directive, ElementRef, HostListener, Output, EventEmitter } from '@angular/core';
import { NgModel } from "@angular/forms";
@Directive({
selector: '[text-trim]',
providers: [NgModel]
})
export class TextInputTrimDirective {
@Output() ngModelChange: EventEmitter<any> = new EventEmitter();
constructor(private el: ElementRef) {}
@HostListener('change') onInputChange() {
const value = this.el.nativeElement.value.trim();
this.ngModelChange.emit(value);
}
}
Я столкнулся с той же проблемой, где мне нужно создать пользовательский выбор в Angular с select2. Я создал следующую директиву, чтобы добиться этого с помощью директивы атрибута и ngModel
,
import {ElementRef, Directive, EventEmitter, Output, Input} from '@angular/core';
import {NgModel} from "@angular/forms";
declare let $;
@Directive({
selector: '[custom-select]',
providers: [NgModel]
})
export class CustomSelectComponent{
$eventSelect:any;
@Output() ngModelChange:EventEmitter<any> = new EventEmitter();
@Input() set ngModel(value:any){
//listen to the input value change of ngModel and change in the plugin accordingly.
if(this.$eventSelect){
this.$eventSelect.val(value).trigger('change',{fromComponent:true});
}
}
constructor(private elementRef: ElementRef) {}
ngOnInit(){
this.$eventSelect = $(this.elementRef.nativeElement);
this.$eventSelect.select2({minimumResultsForSearch:-1});
this.$eventSelect.on("change.select2", (event,data)=> {
//listen to the select change event and chanage the model value
if(!data || !data.fromComponent){ //dont change model when its chagned from the input change event
this.ngModelChange.emit(this.$eventSelect.val());
}
});
}
}
с последующим использованием
<select custom-select [(ngModel)]="protocol.type">
<option value="1">option1</option>
<option value="1">option2</option>
</select>