在 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 绑定