在 Angular 的 INPUT 元素上使用 ngModel 中的管道

Posted

技术标签:

【中文标题】在 Angular 的 INPUT 元素上使用 ngModel 中的管道【英文标题】:Using Pipes within ngModel on INPUT Elements in Angular 【发布时间】:2017-01-31 06:11:46 【问题描述】:

我有一个 html INPUT 字段。

<input 
    [(ngModel)]="item.value" 
    name="inputField" 
    type="text" 
/>

我想格式化它的值并使用现有的管道:

.... 
[(ngModel)]="item.value | useMyPipeToFormatThatValue" 
....

并得到错误信息:

动作表达式中不能有管道

如何在这种情况下使用管道?

【问题讨论】:

【参考方案1】:

你不能在模板语句中使用Template expression operators(pipe, save navigator):

(ngModelChange)="Template statements"

(ngModelChange)="item.value | useMyPipeToFormatThatValue=$event"

https://angular.io/guide/template-syntax#template-statements

与模板表达式一样,模板语句使用的语言 看起来像 javascript。模板语句解析器不同于 模板表达式解析器,特别支持基本的 赋值 (=) 和链接表达式(使用 ; 或 ,)。

但是,某些 JavaScript 语法是不允许的

新 递增和递减运算符,++ 和 -- 运算符分配,例如 += 和 -= 位运算符 |和& 模板表达式运算符

所以你应该这样写:

<input [ngModel]="item.value | useMyPipeToFormatThatValue" 
      (ngModelChange)="item.value=$event" name="inputField" type="text" />

Plunker Example

【讨论】:

有人能解释一下为什么要这样拆分吗?我正在尝试将日期绑定到类型为 date: [(ngModel)]="model.endDate | date:'y-MM-dd'" 的输入,并且管道将不起作用。但是,如果我取消香蕉语法并使用上面的拆分语法,它就可以正常工作。 这真的有效吗?它对我不起作用。它说动作表达式中不能有管道 这对我有用! @BlakeRivell“[]”将属性从数据源单向绑定到视图目标,此时您可以更改它与管道的显示方式。当使用“()”绑定时,改变格式的另一种方式在这里是没用的。所以我想这就是为什么香蕉在盒子里的原因“[()]”不能和管道一起工作,把它们分开是要走的路。你可以在这里阅读更多信息:angular.io/docs/ts/latest/guide/… 请注意,在示例中,管道仅适用于一个方向。假设item.value 是一个数字,您使用DatePipe 将其转换为日期字符串。当日期被编辑时,$event 也将是一个日期字符串,并且不适合回到item.value 您必须反转管道在您的(ngModelChange) 表达式中所做的事情 - 即将日期字符串转回一个数字。 @Protagonist (ngModelChange)="updateItemValue($event)",然后创建一个updateItemValue(date: string) 方法并在其中item.value = someConversionFunction(date); 现在如果你问应该使用什么作为转换函数,我不知道。也许Date.parse() 可能会起作用。【参考方案2】:
<input [ngModel]="item.value | useMyPipeToFormatThatValue" 
      (ngModelChange)="item.value=$event" name="inputField" type="text" />

这里的解决方案是将绑定拆分为单向绑定和事件绑定——[(ngModel)] 语法实际上包含了这两个绑定。 [] 是单向绑定语法,() 是事件绑定语法。当一起使用时 - [()] Angular 将其识别为简写,并以单向绑定和事件绑定到组件对象值的形式连接双向绑定。

您不能将[()] 与管道一起使用的原因是管道仅适用于单向绑定。因此必须拆分管道,只对单向绑定进行操作,单独处理事件。

有关更多信息,请参阅 Angular Template Syntax。

【讨论】:

如何添加条件表达式如 |数字:'3.2-5'?【参考方案3】:

我尝试了上面的解决方案,但模型的值是格式化的值,然后返回并给我 currencyPipe 错误。所以我不得不

  [ngModel]="transfer.amount | currency:'USD':true"
                                   (blur)="addToAmount($event.target.value)"
                                   (keypress)="validateOnlyNumbers($event)"

关于 addToAmount 的功能 -> 模糊更改导致 ngModelChange 给我光标问题。

removeCurrencyPipeFormat(formatedNumber)
    return formatedNumber.replace(/[$,]/g,"")
  

并删除其他非数值。

validateOnlyNumbers(evt) 
  var theEvent = evt || window.event;
  var key = theEvent.keyCode || theEvent.which;
  key = String.fromCharCode( key );
  var regex = /[0-9]|\./;
  if( !regex.test(key) ) 
    theEvent.returnValue = false;
    if(theEvent.preventDefault) theEvent.preventDefault();
  

【讨论】:

我们还尝试了 Percent pipe 的选择答案,并为 (ngModelChange) 编写了一个类似于 toDecimal() 的方法,这两个方法相互追逐。所以你不能输入超过 1 位数字。令人惊讶的是它的投票率如此之高【参考方案4】:

下面给出了我的解决方案 searchDetail 是一个对象..

<p-calendar  [ngModel]="searchDetail.queryDate | date:'MM/dd/yyyy'"  (ngModelChange)="searchDetail.queryDate=$event" [showIcon]="true" required name="queryDate" placeholder="Enter the Query Date"></p-calendar>

<input id="float-input" type="text" size="30" pInputText [ngModel]="searchDetail.systems | json"  (ngModelChange)="searchDetail.systems=$event" required='true' name="systems"
            placeholder="Enter the Systems">

【讨论】:

【参考方案5】:
<input [ngModel]="item.value | currency" (ngModelChange)="item.value=$event"
name="name" type="text" />

我想对已接受的答案再补充一点。

如果输入控件的类型不是文本,则管道将不起作用。

牢记这一点,节省您的时间。

【讨论】:

请考虑在您的回答中添加更多信息 检查 ngx-locale-mask 角度库,我根据角度语言环境为特定货币屏蔽输入框【参考方案6】:

您必须使用 [ngModel] 而不是使用 [(ngModel)] 的双向模型绑定。然后将手动更改事件与 (ngModelChange) 一起使用。这是组件中所有双向输入的公共规则。

因为事件发射器上的管道是错误的。

【讨论】:

【参考方案7】:

由于两种方式绑定,为了防止出错:

ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was 
checked.

你可以像这样调用一个函数来改变模型:

<input [ngModel]="item.value" 
  (ngModelChange)="getNewValue($event)" name="inputField" type="text" />


import  UseMyPipeToFormatThatValuePipe  from './path';

constructor(
    private UseMyPipeToFormatThatValue: UseMyPipeToFormatThatValuePipe,
)

getNewValue(ev: any): any 
    item.value= this.useMyPipeToFormatThatValue.transform(ev);

如果有更好的解决方案来防止这个错误就好了。

【讨论】:

以上是关于在 Angular 的 INPUT 元素上使用 ngModel 中的管道的主要内容,如果未能解决你的问题,请参考以下文章

<input> 元素中的“name”属性与 *ngFor 的 Angular2 绑定

angular 的 @Input@Output 的一个用法

angular- input元素的ng-model属性

Angular 指令从元素中删除原始属性

如何使用 ControlValueAccessor Angular 在自定义输入中使用指令

如何更改 Angular 指令上的变量?