DOM

【JavaScript】 div内のinput要素を一括でdisabledする

更新日:2022/12/08

div内のinput要素を一括で使用不可したい場合、次のコードで実現できます。

document.querySelectorAll("div#id input").forEach( e => e.disabled = true );
※divのid属性を"id"とする

しかしinput要素にも個別にdisabledを設定していて、その状態を維持したいときは、上の方法では問題があります。

そこでいくつかの方法を考えてみました。

 

上の方法の問題点

何が問題なのか、簡単に説明します。
例として、次のコードを用意しました。


<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <script>

        window.addEventListener( "DOMContentLoaded" , ()=> {
            const checkBox = document.getElementById("checkbox");

            checkBox.addEventListener("change" , () => {
                document.querySelectorAll("div#id input")
                    .forEach( e => e.disabled = checkBox.checked );
                });
        });

    </script>
</head>
<body>
    <label><input id="checkbox" type="checkbox">全て使用不可にする</label>
    
    <div id="id" style="border:1px solid black;">
        <label>text:<input type="text" disabled="disabled" ></label>(使用不可)<br>
        <label><input type="checkbox">checkbox(使用可)</label>
    </div>

</body>
</html>

上のコードを実行すると、下のようになります。

(使用不可)

このとき初期状態として、枠線内のテキストボックスが使用不可、チェックボックスは使用可能です。

次に「全て使用不可にする」にチェックを入れると、枠線内のinput要素全てが使用不可となります。

そして「全て使用不可にする」にチェックを外すと、枠線内のinput要素全てが使用可能となります。

ここが問題点です。

チェックを外したとき、初期状態で使用不可であったテキストボックスは、使用不可のままでいてほしいのです。

そこで対処法をいくつか考えていきます。

 

対処法1:data属性を使用する

input要素のdata属性にdisabledの状態を保存しておき、必要に応じて取り出すことで問題点に対処します。


<script>
    window.addEventListener( "DOMContentLoaded" , ()=> {
        const checkBox = document.getElementById("checkbox");

        document.querySelectorAll("div#id input")
            .forEach( e => e.setAttribute("data-disabled",e.disabled));

        checkBox.addEventListener("change" , () => {
            document.querySelectorAll("div#id input")
                .forEach( e => {
                    if( checkBox.checked ) { // 使用不可にする
                        e.setAttribute("data-disabled",e.disabled);
                        e.disabled = true;
                    }else{
                        e.disabled = e.getAttribute("data-disabled") === "true";
                    }
                } );
            });
});
</script>

data-disabledは『要素.dataset.disabled』という形式で参照できますが、古いブラウザは対応していないのでsetAttribute()とgetAttribute()を使用しています。

上のコードを実行してみます。

(使用不可)

想定したとおりに動作しました。

 

対処法2:疑似要素(after)でフタをする

二つ目の方法は、divの疑似要素をdivの上に被せてinput要素を操作できなくします。


<script>

    window.addEventListener( "DOMContentLoaded" , ()=> {
        const checkBox = document.getElementById("checkbox");

        checkBox.addEventListener("change" , () =>
                document.getElementById("id")
                       .classList.toggle("disabled",checkBox.checked )
            );
    });
</script>
<style>
    div.disabled{
        position: relative;
    }
    div.disabled:after{
        content: "";
        position: absolute;
        top:0;
        left: 0;
        bottom: 0;
        right: 0;
        cursor: not-allowed;
        background: rgba(255,255,255,.5);
    }
    div.disabled::before{
        content: "使用できません";
        position: absolute;
        top:40%;
        left: 40%;
        color:red;
        z-index: 10;
        cursor: not-allowed;
    }
</style>

上のコードは疑似要素のクラスを用意しておき、それを付けたり外したりしています。

div.disabled::beforeは『使用できません』と表示しているだけです。
基本的には必要ありません。

実行すると、次のようになります。

(使用不可)

手っ取り早いので、僕はこの方法がお気に入りです。

 

対処法3:cssのみでdiv要素を使用不可にする

最後は対処2よりももっとお手軽に、cssのみでdiv要素を使用不可にします。

その前に、今まで使用していたhtmlのbody要素を少し変更します。

htmlを少し変更

<body>
    <input id="checkbox" type="checkbox"><label for="checkbox">全て使用不可にする</label>

    <div id="id" style="border:1px solid black;">
        <label>text:<input type="text" disabled="disabled" ></label>(使用不可)<br>
        <label><input type="checkbox">checkbox(使用可)</label>
    </div>
</body>

問題点として紹介した例<label><input></label> と並んでいたタグを、<input><label></label>の順に入れ替えています。

次のcssの都合上、このようにしています。

css

div#id{
        position: relative;
}
#checkbox:checked ~ div#id:after{
        content: "";
        position: absolute;
        top:0;
        left: 0;
        bottom: 0;
        right: 0;
        cursor: not-allowed;
        background: rgba(255,255,255,.5);
}

対処法2のcssとほぼ同じです。

cssでchecked疑似要素を使用すると、チェックボックス要素がチェックされたときのスタイルを指定できます。

上の例ではチェックボックスがチェックされたときに、div要素全体をafter要素で覆っています。

ちなみにセレクタの ~ は、同じ階層にある要素を選択します。
このセレクタを成り立たせるために、htmlを変更しました。

表示すると、次のようになります。

(使用不可)

 

対処法3応用例

対処法3で紹介したchecked疑似要素を使用した例をいくつか紹介します。

ボタンで切り替え

radioボタンを使用して、ON/OFFの切り替えボタンを設置する例です。

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">

<style>
    #cbox1,#cbox2{
        display: none;
    }
    #cbox1 ~ .labelbox label{
        border: 1px solid #666;
        padding: 5px;
    }
    #cbox1:checked ~ .labelbox #cbox1label,#cbox2:checked ~ .labelbox #cbox2label{
        background: aquamarine;
    }
    div#id1,div#id2{
        position: relative;
        margin: 1em 0;
    }
    #cbox2:checked ~ div#id:after{
        content: "";
        position: absolute;
        top:0;
        left: 0;
        bottom: 0;
        right: 0;
        cursor: not-allowed;
        background: rgba(255,255,255,.5);
    }
    .labelbox{
        display: flex;
    }
</style>
</head>
<body>
    <input id="cbox1" type="radio" name="cbox"  checked="checked">
    <input id="cbox2" type="radio" name="cbox" >
    <div class="labelbox">
        <label id="cbox1label" for="cbox1">ON</label>
        <label id="cbox2label" for="cbox2">OFF</label>
    </div>
    <div id="id" style="border:1px solid black;">
        <label>text:<input type="text" disabled="disabled" ></label>(使用不可)<br>
        <label><input type="checkbox">checkbox(使用可)</label>
    </div>
</body>
</html>

radioボタンは display: none; で非表示していますが、labelタグで文字を対応付けていることで、文字のクリックで選択可能となっています。

実行すると、次のようになります。


    
    
(使用不可)

ボタンで表示内容を変更

radioボタンを使用して、表示する内容を切り替える例です。

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">

<style>
    #cbox1,#cbox2{
        display: none;
    }
    #cbox1 ~ .labelbox label{
        border: 1px solid #666;
        padding: 5px;
    }
    #cbox1:checked ~ .labelbox #cbox1label,#cbox2:checked ~ .labelbox #cbox2label{
        background: aquamarine;
    }
    div#id1,div#id2{
        margin: 1em 0;
    }
    #cbox1:checked ~ div#id1,#cbox2:checked ~ div#id2{
        display: none;
    }
    .labelbox{
        display: flex;
    }
</style>
</head>
<body>
    <input id="cbox1" type="radio" name="cbox" checked="checked" >
    <input id="cbox2" type="radio" name="cbox" >
    <div class="labelbox">
        <label id="cbox1label" for="cbox1">ON</label>
        <label id="cbox2label" for="cbox2">OFF</label>
    </div>
    <div id="id1" style="border:1px solid black;">
        <p>現在OFFです</p>
    </div>
    <div id="id2" style="border:1px solid black;">
        <p>現在ONです</p>
    </div>
</body>
</html>

表示するdiv要素を二つ作成して、ボタンの選択に応じて表示・非表示を切り替えています。


    
    

現在OFFです

現在ONです

この例は、切り替えボタンを増やすことでタブ表示に利用することができます。

更新日:2022/12/08

書いた人(管理人):けーちゃん

スポンサーリンク

記事の内容について

null

こんにちはけーちゃんです。
説明するのって難しいですね。

「なんか言ってることおかしくない?」
たぶん、こんなご意見あると思います。

裏付けを取りながら記事を作成していますが、僕の勘違いだったり、そもそも情報源の内容が間違えていたりで、正確でないことが多いと思います。
そんなときは、ご意見もらえたら嬉しいです。

掲載コードについては事前に動作確認をしていますが、貼り付け後に体裁を整えるなどをした結果動作しないものになっていることがあります。
生暖かい視線でスルーするか、ご指摘ください。

ご意見、ご指摘はこちら。
https://note.affi-sapo-sv.com/info.php

 

このサイトは、リンクフリーです。大歓迎です。