Usando Pipes no ngModel em Elementos INPUT em Angular

143

Eu tenho um campo HTML INPUT.

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

e eu quero formatar seu valor e usar um canal existente:

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

e receba a mensagem de erro:

Não pode ter um canal em uma expressão de ação

Como posso usar pipes neste contexto?

Solitário
fonte

Respostas:

213

Você não pode usar operadores de expressão de modelo (canal, salvar navegador) na instrução de modelo:

(ngModelChange)="Template statements"

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

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

Como expressões de modelo, as instruções de modelo usam uma linguagem que se parece com JavaScript. O analisador de instrução de modelo difere do analisador de expressão de modelo e suporta especificamente as atribuições básicas (=) e as expressões de encadeamento (com; ou,).

No entanto, certa sintaxe do JavaScript não é permitida :

  • Novo
  • operadores de incremento e decremento, ++ e -
  • atribuição de operador, como + = e - =
  • os operadores bit a bit | e &
  • os operadores de expressão do modelo

Então você deve escrever da seguinte maneira:

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

Exemplo de Plunker

yurzui
fonte
3
Alguém pode explicar por que tem que ser dividido assim? Estou tentando vincular uma data a uma entrada com o tipo date: [(ngModel)] = "model.endDate | date: 'y-MM-dd'" e o canal não funcionará. No entanto, se eu acabar com a sintaxe banana e usar a sintaxe dividida acima, ela funcionará bem.
precisa saber é o seguinte
Isso realmente funcionou? não funcionou para mim. ele diz que não pode ter uma tubulação em uma expressão de ação
NoStressDeveloper
4
Isso funcionou para mim! @BlakeRivell "[]" vincula a propriedade unidirecionalmente da fonte de dados para exibir o destino nesse ponto. Você pode alterar a forma como ela é exibida com um pipe. Ao usar a ligação "()", o contrário seria alterar aqui o formato. Então acho que é por isso que a banana em uma caixa "[()]" não funciona com um cano e dividi-los é o caminho a percorrer. Você pode ler mais sobre isso aqui: angular.io/docs/ts/latest/guide/…
Mike Bovenlander
8
Lembre-se de que no exemplo o tubo funciona apenas em uma direção. Digamos que item.valueé um número e você o DatePipeconverte em uma sequência de datas. Quando a data é editada, $eventela também será uma sequência de datas e não se ajustará novamente. item.valueVocê deve reverter o que o pipe fez em sua (ngModelChange)expressão - ou seja, transformar a sequência de datas em um número.
Tuupertunut 2/17/17
3
@ Protagonista (ngModelChange)="updateItemValue($event)", crie um updateItemValue(date: string)método e dentro dele item.value = someConversionFunction(date); Agora, se você está perguntando o que deve usar como função de conversão, eu não sei. Talvez Date.parse()possa funcionar.
Tuupertunut
111
<input [ngModel]="item.value | useMyPipeToFormatThatValue" 
      (ngModelChange)="item.value=$event" name="inputField" type="text" />

A solução aqui é dividir a ligação em uma ligação unidirecional e em evento - que a sintaxe [(ngModel)]realmente abrange. []é uma sintaxe de ligação unidirecional e ()é uma sintaxe de ligação de evento. Quando usados ​​juntos - o [()]Angular reconhece isso como abreviação e liga uma ligação bidirecional na forma de uma ligação unidirecional e uma associação de evento a um valor de objeto componente.

A razão pela qual você não pode usar [()]com um tubo é que eles funcionam apenas com ligações unidirecionais. Portanto, você deve dividir o tubo para operar apenas na ligação unidirecional e manipular o evento separadamente.

Consulte Sintaxe de modelo angular para obter mais informações.

KnowHoper
fonte
1
Como adiciono a expressão de condição como | número: '3.2-5'?
Protagonista
14
<input [ngModel]="item.value | currency" (ngModelChange)="item.value=$event"
name="name" type="text" />

Gostaria de acrescentar mais um ponto à resposta aceita.

Se o tipo do seu controle de entrada não for texto, o canal não funcionará.

Tenha isso em mente e economize seu tempo.

Tibin Thomas
fonte
considere adicionar mais informações em sua resposta
Inder
1
verifique NGX-locale-mascarar biblioteca angular que fiz para mascarar caixa de entrada para uma determinada moeda com base na localidade angular
Tibin Thomas
6

Eu tentei as soluções acima, mas o valor que vai para o modelo foi o valor formatado, retornando e gerando erros de currencyPipe. Então eu tive que

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

E na função de addToAmount -> alterar no desfoque, porque o ngModelChange estava me dando problemas de cursor.

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

E removendo os outros valores não numéricos.

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
fonte
também tentamos a resposta escolhida para o canal Percent e escrevemos um método como toDecimal () para o (ngModelChange), e os dois métodos se perseguem. então você não pode digitar mais de um dígito. surpreendendo que está upvoted tanto
Angela P
1

Minha solução é fornecida abaixo aqui searchDetail é um objeto.

<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">
Bhasker The Navigator
fonte
0

você deve usar [ngModel] em vez da ligação de modelo bidirecional com [(ngModel)]. use o evento de alteração manual com (ngModelChange). essa é uma regra pública para todas as entradas bidirecionais nos componentes.

porque o canal no emissor do evento está errado.

hamid_reza hobab
fonte
0

devido à ligação bidirecional, para evitar erros de:

ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was 
checked.

você pode chamar uma função para alterar o modelo assim:

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

será bom se houver uma solução melhor para evitar esse erro.

Mohammad Reza Mrg
fonte