質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.62%

JQuery でhidden項目の設定や色の切り替えがうまくいきません

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,336

hidepon

score 188

JQuery でボタンの色の切り替えやhidden項目の設定などをしようとしていますが、
構造が複雑すぎて混迷を深めています。

仕様としては
ラベルをクリックすると、その背景色が変更されます。(そのラベルのクラス属性にcheckedが追加されます。)そして、リストにその名称が追加されると同時にPOST用にhidden要素が追加されます。逆に、もう一度クリックすると色は白色に戻ります。(クラス属性からcheckedが削除されます。)
下記のようなプログラムを作成したのですが、デバッグ用のalertが異なる出力をして
色が反転しません。リストから削除されなかったり、hidden項目が削除されなかったりします。(リストからの削除とかの処理はまだ追加していません)

$('#additional_member').on('click', '.sb_member', function(){
    var index    =    $(".sb_member").index(this) + 1;
    var val        =    $("#sidebar_member" + index).val();
    var str        =    $("span#member_name" + index).html();
    //現在のラベルがチェックされているとき
    if ( $("label#label_sb" + index).hasClass("checked") ){
        var prm        =    "li#list_elm" + index;
        $(prm).remove();
        var hidden_prm    =    "#member_id" + index;;
        $(hidden_prm).remove();
        $("label#label_sb" + index).removeClass('checked');
    }else{
        var count_li    =    $("ul#member_list li").length;
        $('<input>').attr({
            type: 'hidden',
            class: 'member',
            id: 'member_id' + index ,
            name: 'member[]',
            value: val
        }).appendTo('div#add_member');
        $("label#label_sb" + index).addClass('checked');
        //string for assigned member section
        var str_li = '<li id="list_elm' + (count_li + 1) + '">' + str + '</li>';
        $('ul#member_list').append(str_li);
    }
});

//HTML
//ラベルボタンを押すと色が反転する。(checked属性が追加)
//もう一度押すと色が反転する(checked属性が削除)

 <div class="checkbox" id="additional_member">
    <input type="checkbox" name="checkbox_member" id="sidebar_member1" class="cb_member" value="3254" />
    <label for="label_sb1" class="sb_member" id="label_sb1"><span id="member_name1">高木 優斗</span></label>
    <input type="checkbox" name="checkbox_member" id="sidebar_member2" class="cb_member" value="1895" />
    <label for="label_sb2" class="sb_member" id="label_sb2"><span id="member_name2">吉岡 健二</span></label>
</div>

//HTML(部分抜粋)
//hidden項目を設定する場所
<div id="add_member"></div>

//メンバー一覧を設定する場所
<ul id="member_list"></ul>

ラベルにcheckedが付いていないのに、if条件判定で反対の条件に処理されます。
また複数のラベルに対して処理の影響が及んでしまったりと挙動がおかしい状態になります。

質問の意図が伝わるか不安ですが、宜しくお願いいたします。

(追記)

現状のHTML
  <div class="checkbox" id="additional_member">
<input type="checkbox" name="checkbox_member" id="sidebar_member1" class="cb_member" value="155" /><label for="sidebar_member1" class="sb_member" id="label_sb1"><span id="member_name1">山本 浩二</span></label>
<input type="checkbox" name="checkbox_member" id="sidebar_member2" class="cb_member" value="155" /><label for="sidebar_member2" class="sb_member" id="label_sb2"><span id="member_name2">高橋 賢一</span></label>
</div>
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+2

結論を一言で言うと、

var str_li = '<li id="list_elm' + (count_li + 1) + '">' + str + '</li>';


この行を

var str_li = '<li id="list_elm' + index + '">' + str + '</li>';


にすれば直るでしょう。

ラベルをクリックしたらそのメンバーのidがリストに追加されたり削除されたりするという処理のはずなのに、この追加処理だけ現在のメンバー一覧の数に応じたidが振られてしまっています。

ブラウザでF12を押したらデベロッパーツールと言うものが出てきます。
デベロッパーツールを使えば、現在各タグがどんな状態にあるのか(どんなidが振られているのか)確認できますので、デバッグに便利ですよ。

修正点追記

おかしい挙動の原因は、label関連の指定がおかしかったせいもあったようですね。

 <div class="checkbox" id="additional_member">
    <input type="checkbox" name="checkbox_member" id="sidebar_member1" class="cb_member" value="3254" />
    <label for="sidebar_member1" class="sb_member" id="label_sb1"><span id="member_name1">高木 優斗</span></label>
    <input type="checkbox" name="checkbox_member" id="sidebar_member2" class="cb_member" value="1895" />
    <label for="sidebar_member2" class="sb_member" id="label_sb2"><span id="member_name2">吉岡 健二</span></label>
</div>

</label>指定がないせいで、吉岡 健二のほうをクリックしたら、高木 優斗のほうもクリックされたことになっていました。
また、labelfor指定がチェックボックスのidになっていないせいで、クリックしてもチェックボックスのチェックが付かない状態でした。

あと、checkedについて勘違いされているような気がしますので念のため書いておきますが、ラベルにcheckedクラスをつけるのと、チェックボックスをチェック状態にするのには関連性はありませんよ。

上述のindex記述と、label部分の修正を行えば正常動作しますが、せっかくなので、おすすめの記述を書いておきます。

<!DOCTYPE HTML>
<html>
<head></head>
<body>
<div class="checkbox" id="additional_member">
    <label>
        <input type="checkbox" name="checkbox_member" class="cb_member" data-member="1" value="3254" />
        <span>高木 優斗</span>
    </label>
    <label>
        <input type="checkbox" name="checkbox_member" class="cb_member" data-member="2" value="1895" />
        <span>吉岡 健二</span>
    </label>
</div>

<div id="add_member"></div>

<ul id="member_list"></ul>

<script src="http://code.jquery.com/jquery-3.2.1.min.js"></script>
<script>
$('#additional_member').on('click', '.cb_member', function(){
    var $elem = $(this);
    var member_id  = $elem.data("member");
    var val = $elem.val();
    var str = $elem.parents("label").find("span").text();
    //チェックボックスはチェック状態か?
    if ( $elem.prop('checked') ){
        $('<input>').attr({
            type: 'hidden',
            class : 'member',
            id: 'member_id' + member_id,
            name: 'member[]',
            value: val
        }).appendTo('#add_member');
        var str_li = '<li id="list_elm' + member_id + '">' + str + '</li>';
        $('#member_list').append(str_li);
        $elem.addClass('checked');
    }else{
        $("#member_id" + member_id).remove();
        $("#list_elm" + member_id).remove();
        $elem.removeClass('checked');
    }
});
</script>
</body>
</html>

この記述のポイントはこんなところです。

  • labelforでid指定すると項目が増えるごとにマジックナンバーの入力が増えるため、<label>~</label>で囲む方を利用します。
  • また、labelを囲み方式することで、メンバーidは一箇所だけ入力しておけば、parents,findを駆使して同一グループ内のデータを取り出せるようになります。
  • クリック判定はラベルではなくチェックボックスで行います。
  • これは私個人のルールですが、indexという変数名は、配列内の順番を示すときにだけ使い、idをベースとした管理をするときは**_idのような変数にします。目的に沿った変数名にしておくと、余計な混乱を招きません。
  • .prop('checked')でチェック状態かどうかを取得できますので、それを利用します。checkedクラスを付ける意味はこれでほとんどありませんが、CSSの都合でつけておきたいかもしれませんので一応残しています。
  • 追加する3項目をA,B,Cという順番で処理するなら、削除するときもA,B,Cの順番で処理します。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/08/06 21:47

    .onによる登録はイベントの追加なので、もしここを2回通っているなら2回登録されてしまいます。
    .on('click', の上の行にalertを置いて確認してみてください。
    それでもわからないなら、状況を再現可能な最小限のHTMLを作って、ここに追記してください。

    キャンセル

  • 2017/08/06 22:30

    一度 click イベントの1行目にalertを置いてみます。
    一応、現状のコードを追記しますので、お願いいたします。
    何度も何度も申し訳ございません。よろしくお願いいたします。

    キャンセル

  • 2017/08/06 22:53

    状況がわかりました。 ご指摘の通りクリックイベントの上に追記したところ、ページの読み込み時にalert が表示されました。ロード時にclass属性にcheckedが追加されているようです、。この時ってどのように対処したら良いのでしょうか?ご教授頂ければ幸いです。何度もスミマセン。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.62%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る