Verwenden von Pipes in ngModel für INPUT-Elemente in Angular


142

Ich habe ein HTML-EINGABE-Feld.

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

und ich möchte seinen Wert formatieren und eine vorhandene Pipe verwenden:

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

und erhalten Sie die Fehlermeldung:

Ein Aktionsausdruck kann keine Pipe enthalten

Wie kann ich in diesem Zusammenhang Rohre verwenden?

Antworten:


213

Sie können keine Template-Ausdrucksoperatoren (Pipe, Save Navigator) in der Template-Anweisung verwenden:

(ngModelChange)="Template statements"

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

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

Vorlagenanweisungen verwenden wie Vorlagenausdrücke eine Sprache, die wie JavaScript aussieht. Der Parser für Vorlagenanweisungen unterscheidet sich vom Parser für Vorlagenausdrücke und unterstützt insbesondere sowohl grundlegende Zuweisungs- (=) als auch Verkettungsausdrücke (mit; oder,).

Bestimmte JavaScript-Syntax ist jedoch nicht zulässig :

  • Neu
  • Inkrement- und Dekrementoperatoren, ++ und -
  • Operatorzuweisung wie + = und - =
  • die bitweisen Operatoren | und &
  • die Vorlagenausdrucksoperatoren

Sie sollten es also wie folgt schreiben:

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

Plunker Beispiel


3
Kann jemand erklären, warum es so aufgeteilt werden muss? Ich versuche, ein Datum an eine Eingabe mit dem Typ Datum zu binden: [(ngModel)] = "model.endDate | date: 'y-MM-dd'" und die Pipe funktioniert nicht. Wenn ich jedoch die Bananensyntax abschaffe und die oben genannte Split-Out-Syntax verwende, funktioniert dies einwandfrei.
Blake Rivell

Hat das wirklich funktioniert? es hat bei mir nicht funktioniert. Es heißt, dass in einem Aktionsausdruck keine Pipe vorhanden sein kann
NoStressDeveloper

4
Das hat bei mir funktioniert! @BlakeRivell "[]" bindet die Eigenschaft in eine Richtung von der Datenquelle an das Ansichtsziel. An diesem Punkt können Sie die Anzeige mit einer Pipe ändern. Bei Verwendung der Bindung "()" ist es umgekehrt, das Format zu ändern, wäre hier nutzlos. Ich denke, deshalb funktioniert die Banane in einer Schachtel "[()]" nicht mit einer Pfeife, und das Teilen ist der richtige Weg. Sie können mehr darüber hier lesen: angular.io/docs/ts/latest/guide/…
Mike Bovenlander

8
Beachten Sie, dass im Beispiel das Rohr nur in eine Richtung funktioniert. Angenommen, es item.valuehandelt sich um eine Zahl, mit der Sie DatePipesie in eine Datumszeichenfolge konvertieren. Wenn das Datum bearbeitet wird, ist das $eventauch eine Datumszeichenfolge und passt nicht wieder hinein. item.valueSie müssen umkehren, was die Pipe in Ihrem (ngModelChange)Ausdruck getan hat - dh die Datumszeichenfolge wieder in eine Zahl umwandeln.
Tuupertunut

3
@Protagonist (ngModelChange)="updateItemValue($event)", dann erstelle eine updateItemValue(date: string)Methode und darin. item.value = someConversionFunction(date); Wenn du nun fragst , was du als Konvertierungsfunktion verwenden sollst, weiß ich es nicht. Vielleicht Date.parse()könnte es funktionieren.
Tuupertunut

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

Die Lösung besteht darin, die Bindung in eine Einwegbindung und eine Ereignisbindung aufzuteilen - was die Syntax [(ngModel)]tatsächlich umfasst. []ist eine Einwegbindungssyntax und ()eine Ereignisbindungssyntax. Bei gemeinsamer Verwendung [()]erkennt Angular dies als Abkürzung und verdrahtet eine bidirektionale Bindung in Form einer einseitigen Bindung und einer Ereignisbindung an einen Komponentenobjektwert.

Der Grund, den Sie [()]mit einem Rohr nicht verwenden können, ist, dass Rohre nur mit Einwegbindungen funktionieren. Daher müssen Sie das Rohr aufteilen, um nur die Einwegbindung zu bearbeiten und das Ereignis separat zu behandeln.

Weitere Informationen finden Sie unter Angular Template Syntax .


1
Wie füge ich den Bedingungsausdruck wie | hinzu? Nummer: '3.2-5'?
Protagonist

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

Ich möchte der akzeptierten Antwort noch einen Punkt hinzufügen.

Wenn der Typ Ihres Eingabesteuerelements kein Text ist, funktioniert die Pipe nicht.

Denken Sie daran und sparen Sie Zeit.


Bitte erwägen Sie, weitere Informationen in Ihre Antwort aufzunehmen
Inder

1
Überprüfen Sie die Winkelbibliothek ngx-locale-mask, die ich erstellt habe, um das Eingabefeld für eine bestimmte Währung basierend auf dem Winkelgebietsschema zu maskieren
Tibin Thomas

6

Ich habe die oben genannten Lösungen ausprobiert, aber der Wert, der an das Modell geht, war der formatierte Wert, der zurückgegeben wurde und mir CurrencyPipe-Fehler gab. Also musste ich

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

Und über die Funktion von addToAmount -> Änderung bei Unschärfe, weil ngModelChange mir Cursorprobleme bereitete.

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

Und Entfernen der anderen nicht numerischen Werte.

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

Wir haben auch die gewählte Antwort für Percent Pipe ausprobiert und eine Methode wie toDecimal () für (ngModelChange) geschrieben, und die beiden Methoden verfolgen sich gegenseitig. Sie können also nicht mehr als eine Ziffer eingeben. überraschend, dass es so sehr positiv bewertet wurde
Angela P

1

Meine Lösung ist unten angegeben. SearchDetail ist ein Objekt.

<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

Sie müssen [ngModel] anstelle der bidirektionalen Modellbindung mit [(ngModel)] verwenden. Verwenden Sie dann das manuelle Änderungsereignis mit (ngModelChange). Dies ist eine öffentliche Regel für alle bidirektionalen Eingaben in Komponenten.

weil Pipe-on-Event-Emitter falsch ist.


0

wegen der Zwei-Wege-Bindung, um Fehler zu vermeiden von:

ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was 
checked.

Sie können eine Funktion zum Ändern des Modells wie folgt aufrufen:

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

Es ist gut, wenn es eine bessere Lösung gibt, um diesen Fehler zu verhindern.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.