【问题标题】:Attribute directive with ngModel to change field value使用 ngModel 的属性指令来更改字段值
【发布时间】:2016-07-06 12:06:33
【问题描述】:

我想在使用属性指令键入时更改(强制)输入字段值。有了它,我想创建大写、小写、maxlength、filterchar 等指令,用于表单的输入字段。我找到了这个例子:Angular 2 Attribute Directive Typescript Example 但这似乎不起作用。也许它适用于 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 注册为提供者)。我得到一个

未定义 this.model.value。

我可以使用$event.target.value = $event.target.value.toUpperCase()(当通过$eventonInputChange() 传递时)这适用于视图(它确实将输入显示为大写。但它不会更新绑定字段“field.name” .

那么如何创建一个 Angular2 属性指令来做到这一点呢?

-- 编辑--

经过进一步调查,我设法得到了我想要的。 Günter 提供的答案更接近我的初衷,也许更好。但这里有另一种方式:

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)
    }
}

正如我所说,我不确定这是否也是一个好方法,所以欢迎 cmets。

【问题讨论】:

    标签: angular directive angular2-ngmodel


    【解决方案1】:

    我必须创建一个指令来修剪文本输入的前导和尾随空格。 我的解决方案:

    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);
    }
    }
    

    【讨论】:

      【解决方案2】:

      虽然 Günter 的回答看起来很有希望,但存在一个错误,即模型中的最终值具有最后输入的小写字母。

      看这里:

      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)
          }
      }
      

      https://plnkr.co/edit/oE3KNMCG7bvEj8FV07RV

      【讨论】:

      • 在你的 plunker 中,如果你放了一个绑定,例如。

        你好 {{field.name}}

        。它的最后一个字母是小写的。
      • 另外,在角度 rc1 中,更新模型会触发 ngModelChange 事件再次触发,您会得到一个无限循环。
      • 关于原始问题(我无法评论:/),在 rc1 中,如果使用 $event.target.value.toUpperCase() 初始代码将起作用,因为更新模型发出模型更改事件。似乎有些事情发生了变化!
      • @RyanHow:这两个 plnkrs 都没有为我运行。我尝试了这种方法,它正在工作。但是,如果我想在输入字段中有原始输入值,但在模型中修改值,我该怎么办?通过这种方法,我仍然有从模型到输入的“反馈”。
      • @Vicky 抱歉,从这里开始,Angular 发生了很大变化,我怀疑这不再起作用了。
      【解决方案3】:

      我遇到了同样的问题,我需要在 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>
      

      【讨论】:

        【解决方案4】:

        更新

        这种方法不能正常工作。请参阅@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());
          }
        }
        

        Plunker

        【讨论】:

        • 这正是我想要做的 Günter,谢谢!这真的很有意义。与此同时,我找到了另一种方法。我将用这个变体编辑我的问题。我不确定这是否也是一个好方法。也许你可以看看它。
        • 好的,在你添加答案后写评论,我会收到通知。
        • 我尝试了@Output() ngModelChange:EventEmitter 来设置值,但这对我不起作用:D。我认为将ngModelChange 用于@Input() 的优点是它适用于ngModel 涵盖的所有类型的输入元素,也适用于使用不同事件的浏览器(选择和单选输入目前存在问题,因为其中 - 至少当ngModel 问题得到解决时。我想我希望我的@Input() 和你的@Output() 组合起来最好,如果它真的有效的话。
        • 我将使用这两个选项进行更多实验。现在我很高兴已经学到了足够多的东西以某种方式把它做好。谢谢。
        • 感谢您的帮助 .. 很好的解决方案 :)
        猜你喜欢
        • 2019-03-28
        • 2016-10-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-03-06
        • 2014-10-09
        相关资源
        最近更新 更多