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?

Einsam
quelle

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

Yurzui
quelle
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 .

KnowHoper
quelle
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.

Tibin Thomas
quelle
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();
  }
cabaji99
quelle
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">
Bhasker Der Navigator
quelle
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.

hamid_reza hobab
quelle
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.

Mohammad Reza Mrg
quelle