はじめに
この記事の筆者はひよっこWebエンジニア(2年目)で、jQueryとJavaScriptはほぼ未経験です。
温かい目で見ていただけると幸いですm(_ _)m
コード例はPHPで動的に書いたものを説明しやすくするためにHTMLに書き直し、なおかつ読みやすいように調整したものですので、間違っているかもしれません。
背景
自社サービスにおいて、cloneを使う機会があったので、
また使う事になったときのためにまとめておくことにしました。
使った技術
- PHP
- JS
- jQuery
- jQuery Mobile
- CSS
- jQuery
- jQuery Mobile
jQuery編
コード例
<table>
<tr id="like_fruits_1">
<th>
<label>好きなフルーツ</label>
<input type="hidden" id="like_fruits_count" value="1">
</th>
<td>
<select name="fruits[1]" class="select">
<option value="">--</option>
<option value="apple">りんご</option>
<option value="orange">オレンジ</option>
<option value="water_melon">スイカ</option>
<option value="melon">メロン</option>
</select>
<button type="button" id="add_like_fruits_button" class="button button-pill button-primary" style="width: 100px;"><i class="fa fa-plus-square"></i> 追加</button>
<button type="button" id="delete_like_fruits_button" class="button button-pill button-caution" style="width: 100px;"><i class="fa fa-trash"></i> 削除</button>
</td>
</tr>
<tr id="clone_like_fruits_template" style="display: none">
<th></th>
<td>
<select name="fruits[xxx]" class="select">
<option value="">--</option>
<option value="apple">りんご</option>
<option value="orange">オレンジ</option>
<option value="water_melon">スイカ</option>
<option value="melon">メロン</option>
</select>
</td>
</tr>
</table>
<script type=text/javascript>
$(document).ready(function() {
// 削除ボタンを無効化する
$('#delete_like_fruits_button').prop('disabled', true);
});
// 追加ボタンをクリックしたときの処理
$(document).on('click', '#add_like_fruits_button', function() {
// 追加ボタンが押下されたら削除ボタンを有効化する
$('#delete_like_fruits_button').prop('disabled', false);
// 今ある要素数を取得
let creation_times = +$('#like_fruits_count').val();
// 追加したあとの要素数を保存
$('#like_fruits_count').val(creation_times + 1);
// clone_like_fruits_templateのクローンを作成
let copy = $('#clone_like_fruits_template').clone(true);
// xxxを置換
copy.html(function(i, oldHTML) {
return oldHTML.replace(/xxx/g, creation_times+1)
});
// styleを外す。
copy.prop('style', false);
// 属性を付加する
copy.attr('id', 'like_fruits_'+(creation_times+1));
// 現要素の一番最後に格納
copy.insertAfter('#like_fruits_'+creation_times);
});
// 削除ボタンをクリックしたときの処理
$(document).on('click', '#delete_like_fruits_button', function() {
// 今ある要素数を取得
let creation_times = +$('#like_fruits_count').val();
// 削除した後の個数を保存する
$('#like_fruits_count').val(creation_times - 1);
// 項目の一番最後の行を削除する
$('#like_fruits_'+creation_times).remove();
// 一番最初の要素は消せないように削除ボタンを無効化する
if (creation_times <= 2) {
$('#delete_like_fruits_button').prop('disabled', true);
}
});
</script>
で定義して、「追加」を押すと、
<table>
<tr id="like_fruits_1">
<th>
<label>好きなフルーツ</label>
<input type="hidden" id="like_fruits_count" value="2">
</th>
<td>
<select name="fruits[1]" class="select">
<option value="">--</option>
<option value="apple">りんご</option>
<option value="orange">オレンジ</option>
<option value="water_melon">スイカ</option>
<option value="melon">メロン</option>
</select>
<button type="button" id="add_like_fruits_button" class="button button-pill button-primary" style="width: 100px;"><i class="fa fa-plus-square"></i> 追加</button>
<button type="button" id="delete_like_fruits_button" class="button button-pill button-caution" style="width: 100px;"><i class="fa fa-trash"></i> 削除</button>
</td>
</tr>
<tr id="like_fruits_2">
<th></th>
<td>
<select name="fruits[2]" class="select">
<option value="">--</option>
<option value="apple">りんご</option>
<option value="orange">オレンジ</option>
<option value="water_melon">スイカ</option>
<option value="melon">メロン</option>
</select>
</td>
</tr>
<tr id="clone_like_fruits_template" style="display: none">
<th></th>
<td>
<select name="fruits[xxx]" class="select">
<option value="">--</option>
<option value="apple">りんご</option>
<option value="orange">オレンジ</option>
<option value="water_melon">スイカ</option>
<option value="melon">メロン</option>
</select>
</td>
</tr>
</table>
<script type=text/javascript>
$(document).ready(function() {
// 削除ボタンを無効化する
$('#delete_like_fruits_button').prop('disabled', true);
});
// 追加ボタンをクリックしたときの処理
$(document).on('click', '#add_like_fruits_button', function() {
// 追加ボタンが押下されたら削除ボタンを有効化する
$('#delete_like_fruits_button').prop('disabled', false);
// 今ある要素数を取得
let creation_times = +$('#like_fruits_count').val();
// 追加したあとの要素数を保存
$('#like_fruits_count').val(creation_times + 1);
// clone_like_fruits_templateのクローンを作成
let copy = $('#clone_like_fruits_template').clone(true);
// xxxを置換
copy.html(function(i, oldHTML) {
return oldHTML.replace(/xxx/g, creation_times+1)
});
// styleを外す。
copy.prop('style', false);
// 属性を付加する
copy.attr('id', 'like_fruits_'+(creation_times+1));
// 一番最後に格納
copy.insertAfter('#like_fruits_'+creation_times);
});
// 削除ボタンをクリックしたときの処理
$(document).on('click', '#delete_like_fruits_button', function() {
// 今ある要素数を取得
let creation_times = +$('#like_fruits_count').val();
// 削除した後の個数を保存する
$('#like_fruits_count').val(creation_times - 1);
// 一番最後の行を削除する
$('#like_fruits_'+creation_times).remove();
// 一番最初は消せないように削除ボタンを無効化する
if (creation_times <= 2) {
$('#delete_like_fruits_button').prop('disabled', true);
}
});
</script>
みたいな感じに展開されるように作った。
jQueryは初心者でも結構あっさり実装できた。
jQuery Mobile編
コード例
<table>
<tr id="like_fruits_1">
<th>
<label>好きなフルーツ</label>
<input type="hidden" id="like_fruits_count" value="1">
</th>
<td>
<select name="fruits[1]" class="select">
<option value="">--</option>
<option value="apple">りんご</option>
<option value="orange">オレンジ</option>
<option value="water_melon">スイカ</option>
<option value="melon">メロン</option>
</select>
<button type="button" id="add_like_fruits_button" class="button button-pill button-primary" style="width: 100px;"><i class="fa fa-plus-square"></i> 追加</button>
<button type="button" id="delete_like_fruits_button" class="button button-pill button-caution" style="width: 100px;"><i class="fa fa-trash"></i> 削除</button>
</td>
</tr>
<tr id="clone_like_fruits_template" style="display: none">
<th></th>
<td>
<my-select name="fruits[xxx]" class="select">
<option value="">--</option>
<option value="apple">りんご</option>
<option value="orange">オレンジ</option>
<option value="water_melon">スイカ</option>
<option value="melon">メロン</option>
</my-select>
</td>
</tr>
</table>
<script type=text/javascript>
$(document).ready(function() {
// 削除ボタンを無効化する
$('#delete_like_fruits_button').attr('class', 'button button-pill button-caution button-large ui-btn-inline ui-shadow ui-link disabled');
});
// 追加ボタンをクリックしたときの処理
$(document).on('click', '#add_like_fruits_button', function() {
// 追加ボタンが押下されたら削除ボタンを有効化する
$('#delete_like_fruits_button').attr('class', 'button button-pill button-caution button-large ui-btn-inline ui-shadow ui-link');
// 今ある要素数を取得
let creation_times = +$('#like_fruits_count').val();
// 追加したあとの要素数を保存
$('#like_fruits_count').val(creation_times + 1);
// clone_like_fruits_templateのクローンを作成
let copy = $('#clone_like_fruits_template').clone(true);
// xxxを置換。my-selectを置換
copy.html(function(i, oldHTML) {
return oldHTML.replace(/xxx/g, creation_times+1).replace(/my-select/g, 'select')
});
// styleを外す。
copy.prop('style', false);
// 属性を付加する
copy.attr('id', 'like_fruits_'+(creation_times+1));
// 一番最後に格納
copy.insertAfter('#like_fruits_'+creation_times).trigger('create');
});
// 削除ボタンをクリックしたときの処理
$(document).on('click', '#delete_like_fruits_button', function() {
// 今ある要素数を取得
let creation_times = +$('#like_fruits_count').val();
// 一番最初の要素しか無いときは何も処理をさせない
if (creation_times === 1) {
return;
}
// 削除した後の個数を保存する
$('#like_fruits_count').val(creation_times - 1);
// 一番最後の行を削除する
$('#like_fruits_'+creation_times).remove();
// 一番最初は消せないように削除ボタンを無効化する
if (creation_times <= 2) {
$('#delete_like_fruits_button').attr('class', 'button button-pill button-caution button-large ui-btn-inline ui-shadow ui-link disabled');
return;
}
});
</script>
で定義して、「追加」を押すと、
<table>
<tr id="like_fruits_1">
<th>
<label>好きなフルーツ</label>
<input type="hidden" id="like_fruits_count" value="2">
</th>
<td>
<select name="fruits[1]" class="select">
<option value="">--</option>
<option value="apple">りんご</option>
<option value="orange">オレンジ</option>
<option value="water_melon">スイカ</option>
<option value="melon">メロン</option>
</select>
<button type="button" id="add_like_fruits_button" class="button button-pill button-primary" style="width: 100px;"><i class="fa fa-plus-square"></i> 追加</button>
<button type="button" id="delete_like_fruits_button" class="button button-pill button-caution" style="width: 100px;"><i class="fa fa-trash"></i> 削除</button>
</td>
</tr>
<tr id="like_fruits_2">
<th></th>
<td>
<select name="fruits[2]" class="select">
<option value="">--</option>
<option value="apple">りんご</option>
<option value="orange">オレンジ</option>
<option value="water_melon">スイカ</option>
<option value="melon">メロン</option>
</select>
</td>
</tr>
<tr id="clone_like_fruits_template" style="display: none">
<th></th>
<td>
<my-select name="fruits[xxx]" class="select">
<option value="">--</option>
<option value="apple">りんご</option>
<option value="orange">オレンジ</option>
<option value="water_melon">スイカ</option>
<option value="melon">メロン</option>
</my-select>
</td>
</tr>
</table>
<script type=text/javascript>
$(document).ready(function() {
// 削除ボタンを無効化する
$('#delete_like_fruits_button').attr('class', 'button button-pill button-caution button-large ui-btn-inline ui-shadow ui-link disabled');
});
// 追加ボタンをクリックしたときの処理
$(document).on('click', '#add_like_fruits_button', function() {
// 追加ボタンが押下されたら削除ボタンを有効化する
$('#delete_like_fruits_button').attr('class', 'button button-pill button-caution button-large ui-btn-inline ui-shadow ui-link');
// 今ある要素数を取得
let creation_times = +$('#like_fruits_count').val();
// 追加したあとの要素数を保存
$('#like_fruits_count').val(creation_times + 1);
// clone_like_fruits_templateのクローンを作成
let copy = $('#clone_like_fruits_template').clone(true);
// xxxを置換。my-selectを置換
copy.html(function(i, oldHTML) {
return oldHTML.replace(/xxx/g, creation_times+1).replace(/my-select/g, 'select')
});
// styleを外す。
copy.prop('style', false);
// 属性を付加する
copy.attr('id', 'like_fruits_'+(creation_times+1));
// 一番最後に格納
copy.insertAfter('#like_fruits_'+creation_times).trigger('create');
});
// 削除ボタンをクリックしたときの処理
$(document).on('click', '#delete_like_fruits_button', function() {
// 今ある要素数を取得
let creation_times = +$('#like_fruits_count').val();
// 一番最初の要素しか無いときは何も処理をさせない
if (creation_times === 1) {
return;
}
// 削除した後の個数を保存する
$('#like_fruits_count').val(creation_times - 1);
// 一番最後の行を削除する
$('#like_fruits_'+creation_times).remove();
// 一番最初は消せないように削除ボタンを無効化する
if (creation_times <= 2) {
$('#delete_like_fruits_button').attr('class', 'button button-pill button-caution button-large ui-btn-inline ui-shadow ui-link disabled');
return;
}
});
</script>
これでほぼjQueryと同じ感じに展開された。
名前は似ているが、実は結構違った「jQuery」と「jQuery Mobile」
「jQuery Mobile」は「Mobile」とつくだけだから、「jQuery」で書いたコードがそのまま動くでしょ。なんて軽く思っていたら違う部分が結構あった。
jQuery Mobileでは、cloneで追加されたセレクトボックスを選択しても、画面上に反映されなかった。
これの解消に2日くらい時間を要した。
理由は、DOMとしてレンダリングされたとき、すでに「jQuery Mobile」によってselect
がui-select
に変換されていたからだった。
今回は対処法としてDOMの段階ではmy-select
みたいな「jQuery Mobile」に勝手に変換されないようにして解決させた。
さすがに「Java」と「JavaScript」のように全く違う言語とまではいかないけど、それでも結構違った。