Utilizzo di Pipes in ngModel su INPUT Elements in Angular


144

Ho un campo HTML INPUT.

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

e voglio formattare il suo valore e usare una pipe esistente:

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

e ottieni il messaggio di errore:

Impossibile avere una pipe in un'espressione di azione

Come posso usare le pipe in questo contesto?

Risposte:


215

Non è possibile utilizzare gli operatori di espressioni modello (pipe, salva navigatore) all'interno dell'istruzione template:

(ngModelChange)="Template statements"

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

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

Come le espressioni dei modelli, le istruzioni dei modelli utilizzano un linguaggio simile a JavaScript. Il parser di istruzioni template differisce dal parser di espressioni template e supporta specificamente sia le espressioni di assegnazione di base (=) che quelle concatenate (con; o,).

Tuttavia, non è consentita una certa sintassi JavaScript :

  • nuovo
  • operatori di incremento e decremento, ++ e -
  • assegnazione dell'operatore, come + = e - =
  • gli operatori bit a bit | e &
  • gli operatori di espressione del modello

Quindi dovresti scriverlo come segue:

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

Esempio di Plunker


3
Qualcuno può spiegare perché deve essere suddiviso in questo modo? Sto cercando di associare una data a un input con tipo data: [(ngModel)] = "model.endDate | date: 'y-MM-dd'" e la pipe non funzionerà. Tuttavia, se elimini la sintassi della banana e utilizzo la sintassi suddivisa sopra, funziona bene.
Blake Rivell,

Funzionava davvero? non ha funzionato per me. dice Non può avere una pipa in un'espressione d'azione
NoStressDeveloper

4
Questo ha funzionato per me! @BlakeRivell "[]" associa la proprietà unidirezionale dall'origine dati per visualizzare la destinazione a quel punto, è possibile modificare la modalità di visualizzazione con una pipe. Quando si utilizza l'associazione "()" è il contrario per cambiare il formato sarebbe inutile qui. Quindi credo sia per questo che la banana in una scatola "[()]" non funziona con una pipa e dividerla è la strada da percorrere. Puoi leggere di più qui: angular.io/docs/ts/latest/guide/…
Mike Bovenlander

8
Attenzione che nell'esempio il tubo funziona solo in una direzione. Diciamo che item.valueè un numero e lo usi DatePipeper convertirlo in una stringa di date. Quando la data viene modificata, $eventsarà anche una stringa di data e non rientrerà in item.valueDevi invertire ciò che la pipe ha fatto nella tua (ngModelChange)espressione - cioè trasformare la stringa di data in un numero.
Tuupertunut,

3
@Protagonist (ngModelChange)="updateItemValue($event)", quindi crea un updateItemValue(date: string)metodo e al suo interno item.value = someConversionFunction(date); Ora se ti stai chiedendo cosa dovresti usare come funzione di conversione, non lo so. Forse Date.parse()potrebbe funzionare.
Tuupertunut,

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

La soluzione qui è quella di dividere l'associazione in un'associazione unidirezionale e un'associazione di eventi, che la sintassi [(ngModel)]comprende effettivamente. []è una sintassi di associazione unidirezionale ed ()è sintassi di associazione di eventi. Se utilizzato insieme: [()]Angular riconosce questo come scorciatoia e collega un'associazione a due vie sotto forma di un'associazione a una via e un'associazione di eventi a un valore di oggetto componente.

Il motivo che non è possibile utilizzare [()]con una pipe è che le pipe funzionano solo con attacchi unidirezionali. Pertanto, è necessario dividere il tubo per operare solo sull'associazione unidirezionale e gestire l'evento separatamente.

Vedere Sintassi del modello angolare per ulteriori informazioni.


1
Come aggiungo l'espressione condizione come | numero: '3.2-5'?
Protagonista,

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

Vorrei aggiungere un altro punto alla risposta accettata.

Se il tipo di controllo di input non è di testo, la pipe non funzionerà.

Tienilo a mente e risparmia tempo.


si prega gentilmente di aggiungere ulteriori informazioni nella risposta
Inder

1
controlla la libreria angolare ngx-locale-mask che ho creato per mascherare la casella di input per una valuta particolare basata su
impostazioni

6

Ho provato le soluzioni sopra ma il valore che va al modello era il valore formattato che poi restituiva e mi dava errori currencyPipe. Quindi ho dovuto

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

E sulla funzione di addToAmount -> modifica su sfocatura perché ngModelChange mi stava dando problemi con il cursore.

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

E rimuovendo gli altri valori non numerici.

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

abbiamo anche provato la risposta scelta per la percentuale di pipe e abbiamo scritto un metodo come toDecimal () per (ngModelChange) e i 2 metodi si rincorrono. quindi non puoi digitare più di 1 cifra. sorprendente che sia stato così votato
Angela P

1

La mia soluzione è riportata qui sotto searchDetail è un oggetto ..

<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

è necessario utilizzare [ngModel] anziché l'associazione di modelli a due vie con [(ngModel)]. quindi utilizzare l'evento di cambio manuale con (ngModelChange). questa è una regola pubblica per tutti gli input a due vie nei componenti.

perché pipe sull'emettitore di eventi è sbagliato.


0

a causa dell'associazione bidirezionale, per evitare errori di:

ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was 
checked.

puoi chiamare una funzione per cambiare modello in questo modo:

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

andrà bene se esiste una soluzione migliore per prevenire questo errore.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.