pirosikick's diary

君のハートにunshift

IME確定前の入力内容をngModelで取得する

ngModelはIME入力確定後に入力内容が変数に反映される。確定前の「はてn」みたいな入力途中の内容は取得できない。

確定前の内容も反映したいときに、上記のようなDirectiveを作るのもありだが、Angular1.3からngModelOptionsが導入され、updateOnでngModelの更新イベントを指定できるようになったので、

<!-- inputイベント発生時にngModelを更新する -->
<input type="text" ng-model="text" ng-model-options="{ 'updateOn': 'input' }">

これで簡単にできる!、、、かと思いきや、上記でも確定後更新となってしまう。。

バグかなーと思いソースを読むとこのあたりIME入力開始〜確定(compositionstartイベントからcompositionendイベントまで)まで更新をストップする処理が書かれている。1.2.2から導入されていて、意図はここに書いていた。

ngModelは(かなり大まかにだけど。。。)、①inputイベントで入力内容を監視、一時的に内部の変数に保持し、②updateOnで指定されているイベント発生、③ngModelで指定されている変数にその内部変数の値をコピーする、という流れになっていて、「一時的に内部の変数に保持」のところがそもそも更新されていないのでupdateOnで指定しても動作しない。

Directiveを使わない解決方法

下記のように特定のinputだけ、compositionstartイベントとcompositionendイベントをstopImmediatePropagationでストップすれば、Directiveを作らずに問題を解決できるのでおすすめや!!

<!doctype html>
<body ng-app="App">
  <p>{{ text }}</p> 
   
  <input type="text" ng-model="text" class="disabled-composition-events">
  
  <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
  <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.min.js"></script>

  <script>
     angular.module('App', [])
      .run(function () {
        
        // compositionstart, compositionendをストップする
        angular
          .element('.disabled-composition-events')
          .on('compositionstart compositionend', function (e) {
            e.stopImmediatePropagation();
          });
        
      });
  </script>

</body>