LoginSignup
0

More than 1 year has passed since last update.

posted at

updated at

Organization

jQueryとjQuery Mobileでcloneしてみた

はじめに

この記事の筆者はひよっこ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」によってselectui-selectに変換されていたからだった。
今回は対処法としてDOMの段階ではmy-selectみたいな「jQuery Mobile」に勝手に変換されないようにして解決させた。

さすがに「Java」と「JavaScript」のように全く違う言語とまではいかないけど、それでも結構違った。

最後に、今回作成した成果物をご紹介

jQuery

追加ボタンを押す前
スクリーンショット 2020-12-12 20.38.32.png

追加ボタンを押した後
スクリーンショット 2020-12-12 20.38.49.png

jQuery Mobile

追加ボタンを押す前
スクリーンショット 2020-12-12 20.39.26.png

追加ボタンを押した後
スクリーンショット 2020-12-12 20.39.40.png

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
0