ใช้ท่อภายใน ngModel กับองค์ประกอบ INPUT ในเชิงมุม


144

ฉันมีช่องป้อน HTML

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

และฉันต้องการจัดรูปแบบค่าและใช้ไพพ์ที่มีอยู่:

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

และได้รับข้อความแสดงข้อผิดพลาด:

ไม่สามารถมีไพพ์ในนิพจน์การดำเนินการ

ฉันจะใช้ไพพ์ในบริบทนี้ได้อย่างไร

คำตอบ:


215

คุณไม่สามารถใช้โอเปอเรเตอร์นิพจน์เทมเพลต (ไพพ์, บันทึกเนวิเกเตอร์) ภายในคำสั่งเทมเพลต:

(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" />

ตัวอย่างพลั่ว


3
มีคนอธิบายได้ไหมว่าทำไมต้องแยกออกเป็นเช่นนี้ ฉันกำลังพยายามผูกวันที่เข้ากับอินพุตด้วยวันที่ประเภท: [(ngModel)] = "model.endDate | วันที่: 'y-MM-dd'" และไพพ์จะไม่ทำงาน อย่างไรก็ตามถ้าฉันทำไปกับไวยากรณ์กล้วยและใช้แยกออกไวยากรณ์ข้างต้นก็ทำงานได้ดี
Blake Rivell

มันใช้งานได้จริงเหรอ? มันไม่ได้ผลสำหรับฉัน มันบอกว่าไม่สามารถมีไปป์ในการแสดงออกการกระทำ
NoStressDeveloper

4
สิ่งนี้ใช้ได้สำหรับฉัน! @BlakeRivell "[]" ผูกคุณสมบัติทางเดียวจากแหล่งข้อมูลเพื่อดูเป้าหมาย ณ จุดนั้นคุณสามารถเปลี่ยนวิธีการแสดงด้วยไพพ์ได้ เมื่อใช้การผูก "()" มันเป็นวิธีอื่นในการเปลี่ยนรูปแบบจะไร้ประโยชน์ที่นี่ ดังนั้นฉันคิดว่านั่นเป็นเหตุผลว่าทำไมกล้วยถึงอยู่ในกล่อง "[()]" ไม่ทำงานกับท่อและแยกมันเป็นวิธีที่จะไป คุณสามารถอ่านเพิ่มเติมได้ที่นี่: angular.io/docs/ts/latest/guide/…
Mike Bovenlander

8
ระวังว่าในตัวอย่างไปป์นั้นใช้ได้กับทิศทางเดียวเท่านั้น สมมติว่าitem.valueเป็นตัวเลขและคุณใช้DatePipeในการแปลงเป็นสตริงวันที่ เมื่อแก้ไข$eventวันที่แล้วสตริงนั้นก็จะเป็นสตริงวันที่และจะไม่พอดีกับitem.valueคุณคุณจะต้องย้อนกลับสิ่งที่ไพพ์ได้กระทำใน(ngModelChange)นิพจน์ของคุณนั่นคือเปลี่ยนสตริงวันที่กลับเป็นตัวเลข
Tuupertunut

3
@Protagonist (ngModelChange)="updateItemValue($event)"จากนั้นสร้างupdateItemValue(date: string)วิธีการและข้างในitem.value = someConversionFunction(date); ตอนนี้ถ้าคุณถามว่าสิ่งที่คุณควรใช้เป็นฟังก์ชันการแปลงฉันไม่รู้ อาจDate.parse()จะทำงานได้
Tuupertunut

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

วิธีแก้ปัญหาที่นี่คือการแยกการเชื่อมโยงเป็นการเชื่อมโยงทางเดียวและการผูกเหตุการณ์ - ซึ่งไวยากรณ์[(ngModel)]จริง ๆ แล้วไซเบอร์ []เป็นไวยากรณ์การเชื่อมโยงทางเดียวและ()เป็นไวยากรณ์การเชื่อมโยงเหตุการณ์ เมื่อใช้ร่วมกัน -[()] Angular จดจำสิ่งนี้ว่าเป็นการจดชวเลขและเชื่อมโยงการผูกมัดแบบสองทางในรูปแบบของการเชื่อมโยงทางเดียวและเหตุการณ์ผูกกับค่าวัตถุส่วนประกอบ

เหตุผลที่คุณไม่สามารถใช้ [()]กับไปป์นั้นได้เพราะไพพ์ทำงานได้กับการผูกทางเดียวเท่านั้น ดังนั้นคุณจะต้องแยกออกไปป์เพื่อใช้งานในการผูกทางเดียวและจัดการเหตุการณ์แยกต่างหาก

ดูไวยากรณ์เทมเพลตเชิงมุมสำหรับข้อมูลเพิ่มเติม


1
ฉันจะเพิ่มนิพจน์เงื่อนไขเช่น | ได้อย่างไร หมายเลข: '3.2-5'
ตัวเอก

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

ฉันต้องการเพิ่มอีกหนึ่งจุดให้กับคำตอบที่ยอมรับได้

ถ้าประเภทของอินพุตควบคุมของคุณไม่ใช่ข้อความไพพ์จะไม่ทำงาน

เก็บไว้ในใจและประหยัดเวลาของคุณ


โปรดพิจารณาเพิ่มข้อมูลเพิ่มเติมในคำตอบของคุณ
Inder

1
ตรวจสอบ ngx-locale-mask ไลบรารี่เชิงมุมซึ่งฉันได้ทำไว้เพื่อปกปิดกล่องอินพุตสำหรับสกุลเงินเฉพาะโดยอิงตามโลแคลเชิงมุม
ทิบินโทมัส

6

ฉันลองวิธีแก้ปัญหาข้างต้นแล้วค่าที่ไปยังแบบจำลองนั้นเป็นค่าที่จัดรูปแบบแล้วส่งคืนและให้ข้อผิดพลาด currencyPipe ให้ฉัน ดังนั้นฉันต้อง

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

และในฟังก์ชั่นของ addToAmount -> การเปลี่ยนแปลงความไม่ชัดทำให้ 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();
  }

เรายังลองคำตอบที่เลือกสำหรับ Percent pipe และเขียนวิธีเช่น toDecimal () สำหรับ (ngModelChange) และ 2 วิธีการไล่ล่าซึ่งกันและกัน ดังนั้นคุณไม่สามารถพิมพ์ได้มากกว่า 1 หลัก น่าประหลาดใจที่มีผู้สนับสนุนมาก
แองเจล่าพี

1

โซลูชันของฉันมีให้ที่นี่ด้านล่างค้นหารายละเอียดเป็นวัตถุ ..

<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) นี่เป็นกฎสาธารณะสำหรับอินพุตทั้งสองทางในส่วนประกอบ

เพราะไปป์ในอีซีเตอร์ของเหตุการณ์ผิดไป


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

มันจะดีถ้ามีทางออกที่ดีกว่าเพื่อป้องกันข้อผิดพลาดนี้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.