input要素の数値を3桁カンマ区切り

input要素の数値を3桁カンマにする方法

Pocket

入力フォームが数値で桁数が大きい場合に何桁入力したか見づらい場合があり、フォーム上カンマ区切りで表示して欲しいという結構無茶な依頼を受けたので、Javascriptを使ってCakePHP流にそれに対応してみた。

ポイントは以下

  • Inputフォームに数字を入力したら即座に3桁カンマ区切りに
  • 実際にsubmitされる値はnumeric(カンマなし)
  • Javascriptを使う
  • CakePHPの標準になるべく従う

実装の概要

  • 独自にForm->input()のラッパーとなるHelperを作る
  • カンマ区切り変換Javascriptを作る
  • 呼び出す箇所でForm->inputの代わりに独自Helperを使う

呼び出し箇所

$this->Form->input()を呼ぶ代わりに自作ヘルパーを呼ぶ。呼び出し方は$this->Form->input()と全く同じにしておく。

<?= $this->U->inputNum('field', $options) ?>

ヘルパーの内容

ここでは、UHelperとした。呼び出されるメソッドはinputNum()とした。

class UHelper extends AppHelper {
   public $helpers = array('Html', 'Form');
   static $initInputNum = false;

   public function inputNum($fieldName, $options = array()) {
   // Init input data
      if (self::$initInputNum === false) {
         $this->Html->scriptStart(array('inline' => false)); ?>
$(function() {
mytool.initInputNum();
});
<? $this->Html->scriptEnd();
         self::$initInputNum = true;
      }

      $class_comma = 'thousand-separator-commas';
      $class_num   = 'thousand-separator-num';
      // add $class_comma into the input class
      if (array_key_exists('class', $options)) {
         if (is_array($options['class'])) $options['class'][] = $class_comma;
         elseif (is_string($options['class'])) $options['class'] .= ' '.$class_comma;
      }
      // stock div option for later
      $divOptions = array();
      if (array_key_exists('div', $options)) {
         $divOptions = $options['div'];
      }
      $options['div'] = false;
      $input = $this->Form->input($fieldName.'_comma',  $options) . $this->Form->hidden($fieldName, array('class' => $class_num));

      if ($divOptions !== false) {
         $input = $this->Html->tag('div', $input, $divOptions);
      }
      return $input;
   }
}

mytool.initInputNum() というカンマ区切り制御用Javascriptを呼び出す。(※:jqueryが必要)

static $initInputNumを使って、mytool.initInputNum()の呼び出しが1度しかレンダーされない様に制御しておく。

inputフォームは表示専用のフォームと実際に保存されるhiddenフォームの二つを用意する。

表示用フォームにthousand-separator-commasというクラスをセット。hiddenフォームにthousand-separator-numというクラスをセットする。(Jsで利用するため)

Helper内で$this->Form->inputを呼び出して実際にフォームを作成するが、この際二つのフォームがhtml構造上となりに並ぶ様にdivはfalseとしておく。

UHelper::inputNum()に渡された$optionsのdiv設定に従って二つのフォーム両方を囲む様にdivを作成する。

カンマ区切り制御用Javascript

mytoolという名前空間にinitInputNum()関数とaddCommas()関数を用意する。

var mytool = (function(exports) {
   // Init numeric inputs
   exports.initInputNum = function() {
      // Bind handler to numeric inputs
      $(".thousand-separator-commas").each(function(){
         $(this).bind('keyup', function() {
            var num = $(this).val();
            var comma = /,/g;
            num = num.replace(comma,'');

            // Allows only numeric data
            if(num.match(/[^0-9]+/)){
               num = num.replace(/[^0-9]+/g,"");
            }
            $(this).next(".thousand-separator-num").val(num);
            var numCommas = exports.addCommas(num);
            $(this).val(numCommas);
         });
      });
      // Initialize comma-separated-input-text from the hidden field.
      $(".thousand-separator-num").each(function(){
         var num = $(this).val();
         var comma = /,/g;
         num = num.replace(comma,'');
         var numCommas = exports.addCommas(num);
         $(this).prev(".thousand-separator-commas").val(numCommas);
      });
   };
   exports.addCommas = function(nStr) {
      nStr += '';
      var comma = /,/g;
      nStr = nStr.replace(comma,'');
      x = nStr.split('.');
      x1 = x[0];
      x2 = x.length > 1 ? '.' + x[1] : '';
      var rgx = /(\d+)(\d{3})/;
      while (rgx.test(x1)) {
         x1 = x1.replace(rgx, '$1' + ',' + '$2');
      }
      return x1 + x2;
   };

   return exports;
})({});

addCommas()関数は渡された引数の文字列を3桁ずつのカンマ区切りに変換する低次元関数。

initInputNum()関数はthousand-separator-commasクラスがセットされた入力フォーム全てにkeyupのハンドラをバインドする。また、CakePHPがモデルにセットしたデフォルト値が、hidden側のフォーム(thousand-separator-num側)にセットされるので、これをthousand-separator-commas側にコピーして初期化する。

keyupのハンドラでは、入力された表示用フォームの値を取得して、数値のみを許可しつつ値を実際のhiddenフォームにセットし、自身のフォームに対してはカンマ区切りに変換した値を再セットする。

 

記事が役に立ったらぜひシェアをお願いします。

Pocket

Leave a Reply

Your email address will not be published. Required fields are marked *