BoostCake(CakePHP + Bootstrap)でHorizontal formに横並びのテキストボックスを作る
CakePHPBoostCakeを使ってCakePHP & Bootstrapなサイトを作っていると、Horizontal formの中にInline formのような横並びのテキストボックスを作りたい場面が時々出てきます。
例えば名前の「姓」「名」や、郵便番号の上3桁と下4桁などが2つのテキストボックスに分かれている場合、2行に分けて表示せずに1行で横に並んで欲しいんですよね。
色々試行錯誤したところ、バリデーションエラーをきちんとそれぞれのテキストボックスの下部に表示させつつ、レスポンシブにも対応させるとなると、それなりに記述に工夫が必要だったのでメモしておきます。
前提
- CakePHP2.6.10
- BoostCakeプラグイン(導入済み)
- Bootstrap3.3.5
以上の環境で制作しています。
完成形
こんな感じです。 「お名前」「フリガナ」「郵便番号」が横並びを実現した箇所になっています。
PCでもモバイルでも問題なく表示されるかと思います。画面幅を変えて表示を試してみてください。
画面の幅が768px以下の場合、ラベルがテキストボックスの上に移動します。
また、バリデーションエラーがある場合、それぞれのテキストボックスの下に表示されます。
See the Pen bVVzeQ by Seiichiro Sasaki (@sasakichi) on CodePen.
フォームヘルパーのコード
例として「お名前」の部分のフォームヘルパーをハイライト表示しています。
<?php echo $this->Form->create('User', array(
'inputDefaults' => array(
'div' => 'form-group',
'label' => array(
'class' => 'col col-md-3 col-sm-4 control-label'
),
'wrapInput' => 'col col-md-9 col-sm-8',
'class' => 'form-control'
),
'class' => 'well form-horizontal'
)); ?>
<fieldset>
<legend><?php echo __('Fields'); ?></legend>
<?php
if ($this->action === 'edit') {
echo $this->Form->input('id');
}
echo $this->Form->input('username');
echo $this->Form->input('password');
echo $this->Form->input('group_id');
//---------------------------------
// お名前
//---------------------------------
$last_name = $this->Form->input('last_name', array(//+
'div' => ' ',//+
'wrapInput' => 'col col-md-3 col-sm-4 col-xs-6',//+
'placeholder'=>'姓',//+
'label' => array(//+
'text' => 'お名前', //+
'class' => 'col col-md-3 col-sm-4 col-xs-12 control-label'//+
)//+
));//+
echo $this->Form->input('first_name', array(//+
'label' => array('class' => 'sr-only'),//+
'wrapInput' => 'col col-md-3 col-sm-4 col-xs-6',//+
'placeholder'=>'名',//+
'before' => $last_name//+
));//+
//---------------------------------
// フリガナ
//---------------------------------
$last_name_kana = $this->Form->input('last_name_kana', array(
'div' => ' ',
'wrapInput' => 'col col-md-3 col-sm-4 col-xs-6',
'placeholder'=>'セイ',
'label' => array(
'text' => 'フリガナ',
'class' => 'col col-md-3 col-sm-4 col-xs-12 control-label'
)
));
echo $this->Form->input('first_name_kana', array(
'label' => array('class' => 'sr-only'),
'wrapInput' => 'col col-md-3 col-sm-4 col-xs-6',
'placeholder'=>'メイ',
'before' => $last_name_kana
));
//---------------------------------
// 郵便番号
//---------------------------------
$zip_code1 = $this->Form->input('zip_code1', array(
'div' => ' ',
'wrapInput' => 'col col-md-2 col-sm-2 col-xs-3',
'placeholder'=>'000',
'label' => array(
'text' => '郵便番号',
'class' => 'col col-md-3 col-sm-4 col-xs-12 control-label'
)
));
echo $this->Form->input('zip_code2', array(
'label' => array('class' => 'sr-only'),
'wrapInput' => 'col col-md-2 col-sm-2 col-xs-4 add-hyphen',
'placeholder'=>'0000',
'before' => $zip_code1
));
echo $this->Form->input('pref');
echo $this->Form->input('address1');
echo $this->Form->input('address2');
echo $this->Form->input('address3');
echo $this->Form->input('tel');
?>
</fieldset>
<div class="form-group">
<?php
echo $this->Form->submit(__('Submit'), array(
'div' => 'col col-md-9 col-md-offset-3 col-sm-8 col-sm-offset-4',
'class' => 'btn btn-primary btn-lg'
)
);
?>
</div>
<?php echo $this->Form->end(); ?>
やっていることとしては、
フォームヘルパーによる1つめのテキストボックスの出力内容を一度変数に入れ、2つめのテキストボックスの'before'オプションでそれを手前に出力しています。
ラベルは1つめのテキストボックスのものを出力するようにし、2つめのテキストボックスのものは非表示にしています。
1つめのテキストボックスの'after'オプションに2つ目のテキストボックスを出力する方が感覚的にはわかりやすいですが、この場合、2つめのテキストボックスでバリデーションエラーが発生した場合、表示されている1つめのテキストボックスのラベルを.form-errorクラスで囲む良い方法が見つかりませんでした。(即ち、ラベルがエラー色にならない…)
また、1つめのテキストボックスのオプションにある'div' => ' ',ですが、これは通常時はクラス指定のないただのdivタグが出力されるだけですが、バリデーションエラーが発生した場合、.form-errorクラスが付与されます。無用な指定ではありません。
グリッドオプション
テキストボックスの幅の指定にはBootstrapのグリッドシステムを利用しています。
グリッドシステムのクラス指定方法については、Bootstrap 非公式日本語版がわかりやすいかと思いますので、もし理解されていない方は一度読んでから取り組むと良いかと思います。
このコードでは、中型デバイス デスクトップ (≥992px)、小型デバイス タブレット (≥768px)、極小デバイス 携帯電話 (<768px)の3種類について指定しています。
こういった部分ですね。数値によってテキストボックスの幅を変えられますので、フォームの内容によって適宜変更してください。
'wrapInput' => 'col col-md-3 col-sm-4 col-xs-6',
CSS
上記の方法で、横並びのテキストボックスを作るだけなら独自のCSSを追加する必要はありませんが、今回の例では入力必須項目のラベルに赤で「必須」の表示を加えるためと、郵便番号の上3桁と下4桁の間にハイフンを表示するためにCSSを追加しました。一応そちらも載せておきます。
Horizontal form内に横並びのテキストボックスを作るという本旨とは関係ありません。
/* 「必須」ラベル */
form .required .control-label:after {
border-radius: 0.25em;
color: #fff;
display: inline;
font-size: 75%;
font-weight: 700;
line-height: 1;
padding: 0.1em 0.5em;
margin-left: 0.7em;
text-align: center;
vertical-align: baseline;
white-space: nowrap;
background-color: #d9534f;
content: '必須';
}
/* 郵便番号入力、上3桁と下3桁の間のハイフン */
.add-hyphen:before {
content: '-';
font-size: 125%;
display:block;
position: absolute;
top: 0.3em;
left: -0.3em;
}