1. 程式人生 > >angular4中ngModel雙向繫結在限制輸入情況下與value值不一致的問題及嘗試的解決方法

angular4中ngModel雙向繫結在限制輸入情況下與value值不一致的問題及嘗試的解決方法

近期公司的一個後臺專案在使用angular4進行開發,隨著專案的推進和迭代開發,需要對有的input框的value值進行限制輸入,例如目前專案的一些input框只允許輸入數字和'.' 這兩種形式的內容。就在input標籤的中添加了(keyup)屬性,將相應的ts檔案中編寫的一個正則驗證方法賦值給該屬性,以便進行驗證,如下所示:

<input type="text" #price [(ngModel)]="normal.price" (keyup)="numTest($event)">元/次 {{normal.price}} ||| {{price.value}}

numTest($event){
   $event.target.value = $event.target.value.replace(/[^\d]/g, '');
}
開始以為這樣的正則是沒有問題的,但是通過實踐發現,該方法有一定侷限性。在開啟中輸入法的時候,當鍵入漢字並使用Space鍵或者Enter鍵或者滑鼠左鍵選擇輸入法羅列的漢字時,該正則對input的value值是有效果的,但是對雙向繫結的“normal.price”是不起作用的。在頁面顯示的
normal.price -> 你好 ||| price.value -> ''(在頁面是不顯示price.value的值的,因為通過正則,已經將該值置為空了,這裡用''表示)

初次遇到這個問題,感覺有些奇怪,印象裡在angularjs的使用過程中並沒有出現同樣的問題,雖然angular2之後使用TypeScript重新編寫了框架,但是雙向繫結這個亮點還是保留的,不應該出現這樣的不一致才對。隨後查看了angular的文件,在核心知識->模板和資料繫結->模板語法中找到了相關的表述:

表述

從該表述中獲知,雙向繫結的實現是模仿input標籤中的[value]、[input]兩個屬性來實現值的變化的。於是就暫時先棄用雙向繫結的便利寫法,迴歸原始:

input type="text" #price [value]="normal.price" (input)="normal.price=$event.target.value" (keyup)="numTest($event)">元/次 {{normal.price}} ||| {{price.value}}
 但結果跟使用雙向繫結的效果一樣,normal.price的值依然沒有進行有效的正則過濾。對此更加疑惑不解,在網上好像也沒能尋求到相同問題的解決辦法。

這個問題搞了一下午還是沒有什麼起色,到了第二天,可能是換了換腦子的緣故,重新梳理了一下這個問題,決定將這個問題分兩步,分別解決:1、怎麼禁止中文輸入法的使用,不能將鍵入選擇的漢字輸入到input框中;2、怎麼同步[(ngModel)]的屬性值與input的value值完全同步的問題。

有了這樣的思路後,首先著手看怎麼禁止中文輸入法,這個網上有好多,相對能找到一些有價值的參考。找到了這篇文章:

input 事件與漢字輸入法:使用compositionend事件解決發現了“compositionend“這個屬性。查看了MDN中關於compositionend 屬性的解釋:

解釋:
查看了翻譯後的文字,當然解釋不一定完全符合原意,有在網上查找了該屬性的一些用法,一般是對input屬性的補充。用於監聽文字的輸入,對中文輸入法起作用。至此,對於第一個問題的解決就有了思路:
<input type="text" #price [(ngModel)]="normal.price" (compositionend)="$event.target.value= ''" (keyup)="numTest($event)">元/次 {{normal.price}} ||| {{price.value}}
這樣,當中文輸入法鍵入漢字時,input框的value值會強制置空,根據這樣的思路,同時再強制雙向繫結的值,也是可行的。 第一個問題解決之後,就著手開始第二個問題的處理,怎樣使normal.price同input的value值保持一致,由於始終沒有完全理清ngModel的實現原理,且還原成原始的value和input屬性後效果相同,在不得已的情況下,又在input標籤中添加了一個屬性ngModelChage,將帶有正則驗證方法的返回值重新賦值給ngModel的屬性值。這樣問題二也能夠間接的解決掉。並且配合前邊的compositionend屬性,使頁面表現同資料的賦值相一致。 最終的結果是這樣子的:
<input type="text" #price [(ngModel)]="normal.price" (ngModelChange)="normal.price=numTestValue($event)" (compositionend)="$event.target.value= ''" (keyup)="numTest($event)">元/次 {{normal.price}} ||| {{price.value}}
 clearNoNum11($event) {
    $event = $event.replace(/[^\d]/g, '');
    return $event;
  };
這樣,算是解決了在有輸入限制的情況下,input框的value值與雙向繫結的值不一致的問題。當然,這裡的解決方案並不是最終、最簡便的,待以後對angular4有更深入的理解後,再進行方法的補充和提煉吧!
Ps: 這裡還有一個疑惑,在angular技術文件中
<input [value]="currentHero.name" (input)="currentHero.name=$event.target.value" > 的對應anglar寫法是
<input [ngModel]="currentHero.name" (ngModelChange)="currentHero.name=$event">
但是在ngModelChage的$event直接就是該input框的value,而不是通常認為的event事件物件。在這裡註明一下,有待後續學習理解。