Использование каналов в ngModel для элементов INPUT в Angular

151

У меня есть поле ВВОДА HTML.

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

и я хочу отформатировать его значение и использовать существующий канал:

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

и получите сообщение об ошибке:

Не может быть конвейера в выражении действия

Как я могу использовать трубы в этом контексте?

Одинокий, уединенный
источник

Ответы:

227

Вы не можете использовать операторы выражения шаблона (конвейер, навигатор сохранения) в операторе шаблона:

(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

Юрзуй
источник
4
Может кто-нибудь объяснить, почему его нужно так разделить? Я пытаюсь привязать дату ко входу с типом date: [(ngModel)] = "model.endDate | date: 'y-MM-dd'", и канал не будет работать. Однако, если я откажусь от бананового синтаксиса и использую выделенный выше синтаксис, он будет работать нормально.
Блейк Ривелл
Это действительно сработало? у меня это не сработало. он говорит, что в выражении действия не может быть канала
NoStressDeveloper
4
Это сработало для меня! @BlakeRivell "[]" привязывает свойство односторонне от источника данных к цели просмотра, в этот момент вы можете изменить способ его отображения с помощью канала. При использовании привязки "()" наоборот, изменение формата здесь было бы бесполезно. Думаю, именно поэтому бананы в коробке "[()]" не работают с трубкой, и лучше всего их разделить. Вы можете прочитать об этом подробнее здесь: angular.io/docs/ts/latest/guide/…
Майк Бовенландер
8
Помните, что в этом примере труба работает только в одном направлении. Скажем, item.valueэто число, и вы используете его DatePipeдля преобразования в строку даты. Когда дата редактируется, $eventона также будет строкой даты и не будет возвращаться в item.valueнее. Вам нужно отменить то, что канал сделал в вашем (ngModelChange)выражении, то есть снова превратить строку даты в число.
Tuupertunut
3
@Protagonist (ngModelChange)="updateItemValue($event)", затем создайте updateItemValue(date: string)метод и внутри него. item.value = someConversionFunction(date); Теперь, если вы спрашиваете, что вы должны использовать в качестве функции преобразования, я не знаю. Может Date.parse()сработает.
Tuupertunut
114
<input [ngModel]="item.value | useMyPipeToFormatThatValue" 
      (ngModelChange)="item.value=$event" name="inputField" type="text" />

Решением здесь является разделение привязки на одностороннюю привязку и привязку событий, которые [(ngModel)]фактически охватывает синтаксис . []синтаксис односторонней привязки и синтаксис ()привязки событий. При совместном использовании - [()]Angular распознает это как сокращение и связывает двустороннюю привязку в форме односторонней привязки и привязки события к значению объекта компонента.

Причина, по которой вы не можете использовать [()]канал, заключается в том, что каналы работают только с односторонними привязками. Следовательно, вы должны разделить канал, чтобы работать только с односторонней привязкой и обрабатывать событие отдельно.

Смотрите Angular Template Syntax для получения дополнительной информации.

KnowHoper
источник
1
Как добавить выражение условия, например | номер: «3.2-5»?
Главный герой
18
<input [ngModel]="item.value | currency" (ngModelChange)="item.value=$event"
name="name" type="text" />

К принятому ответу хочу добавить еще один пункт.

Если тип вашего элемента управления вводом не является текстовым, канал не будет работать.

Помните об этом и сэкономьте свое время.

Тибин Томас
источник
любезно рассмотрите возможность добавления дополнительной информации в свой ответ
Индер
2
проверьте библиотеку angular ngx-locale-mask, которую я сделал, чтобы замаскировать поле ввода для конкретной валюты на основе языкового стандарта angular
Тибин Томас
6

Я пробовал приведенные выше решения, но значение, которое поступает в модель, было отформатированным значением, которое затем возвращалось и давало мне ошибки currencyPipe. Так что мне пришлось

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

И в функции addToAmount -> change on blur, потому что 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();
  }
Cabaji99
источник
мы также попробовали выбранный ответ для Percent pipe и написали такой метод, как toDecimal () для (ngModelChange), и два метода преследуют друг друга. поэтому вы не можете ввести более 1 цифры. удивительно, что за него так много проголосовали
Angela P
1

Мое решение приведено ниже здесь 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">
Бхаскер Навигатор
источник
0

вы должны использовать [ngModel] вместо двусторонней привязки модели с [(ngModel)]. затем используйте событие ручного изменения с (ngModelChange). это публичное правило для всех двухсторонних входов в компоненты.

потому что труба на эмиттере событий неверна.

hamid_reza hobab
источник
0

из-за двусторонней привязки, чтобы предотвратить ошибку:

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

будет хорошо, если есть лучшее решение для предотвращения этой ошибки.

Мохаммад Реза Мрг
источник