【jQuery dynatree】チェックボックスを押した時に、子ノードをdisabledにする方法（代替案）

# はじめに
<font color="silver">※本当はチェックボックスを選択した時に、子ノードを disabled にしたかったのですが、
そういうオプションがないので実装できませんでした . . .
（ツリーをまるごと disabled にすることは可能）</font>

そこで今回はその代用として、dynatreeで以下のような動きを実装する方法を記載します。

**実装する挙動**
チェックボックス：選択時
→・子ノードのチェックボックスを全て外す
<font color="white">→</font>・子ノードのチェックボックスを選択できないようにする（フォントの色は変化しない）

チェックボックス：選択解除時
→・子ノードのチェックボックスを選択できるようにする
（チェックボックスは全て外れたまま）
![GIF 2020-12-28 0-58-37.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/650537/07f27888-3fac-a1c6-bdd0-185392cf998c.gif)


<font color="blue">※チェックボックス：選択時に子ノードのチェックボックスを全てONにしたい場合は、`selectMode: 3`とすればOKです。</font>

# 実装する（onSelect）
ソースコードの全体像はこのページの末尾に記載します。
ここではツリーの構成を示す **children** オプションと、チェックボックスを押したときの動きを制御する **onSelect** オプションに関してのみ抜粋して記載します。

```.js:ツリーの要素（children）
// children ここでツリーのノードを初期化することができます。
children: [
    // title 表示名を指定します。
    {title: "ファイル1"},
    // isFolder フォルダかどうか指定します。
    {title: "フォルダ", isFolder: true,
        children: [
            {title: "子ファイル1"},
            {title: "子ファイル2"}
        ]
    },
    {title: "ファイル2",
        children: [
            {title: "子ファイル3"},
            {title: "子ファイル4"}
        ]
    }
],
```

```.js:今回の実装部分（onSelect）
// onSelect チェックボックスを選択または選択解除した時の処理を書きます。
// 第1引数(flag): 選択ならtrue、選択解除ならfalse
// 第2引数(dtnode): 選んだノードの情報
onSelect: function(flag, dtnode) {
    // 選択時(→ flag = true)
    if (flag) {
        // visit 全ての子ノードに対して処理を実行します
        dtnode.visit(function(childNode) {
            // 子ノードを選択解除します
            childNode.select(false);
            // 子ノードを選択不可にします
            childNode.data.unselectable = true;
        });
    }
    // 選択解除時(→ flag = false)
    else {
        dtnode.visit(function(childNode) {
            // 子ノードを選択可に戻します
            childNode.data.unselectable = false;
        });
    }
}
```


# 補足
### ◆  使用したコマンドに関して
今回使用した、**onSelect** , **node.visit** , **node.select** , **node.data.unselectable** 等に関しては、[後述のマニュアル](#-dynatree-の参考資料)に説明が載っているので、ご参照ください。 

|コマンド|マニュアル内の記載場所|
|:-----:|:-------|
|onSelect|**4.1 Tree options** ／ **5.3 Handling selection events**|
|node.visit|**8.3 DynaTreeNode class members**|
|node.select|**8.3 DynaTreeNode class members**|
|node.data.unselectable|**4.2.1 Node options** ／ 8.3 DynaTreeNode class members の **Attribute 'data'** |

**node.data.～** だけ補足しておくと、
**node.data.～** とすることで、**children**で設定できるオプション（**title** や **isFolder** など）の値を参照できます。
ただし、変更するオプションによっては、**node.render()** によってノードを再描画する必要があります。（今回は必要なし）

```.js:再描画が必要な例-1
// 例1. チェックボックス選択時、子ノードの名称変更（title）

...
// 選択時(→ flag = true)
if(flag) {
    dtnode.visit(function(childNode) {
        // 子ファイル名を「hoge」に変更
        childNode.data.title = "hoge";
        // 子ノードを再描画
        childNode.render();  
    });
}
...
```
**↓↓ ◆ 画面の動き（例1） ↓↓**
![GIF 2020-12-28 1-45-19.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/650537/e22ff912-a5ba-20c4-450e-f1aa879fe7a1.gif)

---

```.js:再描画が必要な例-2
// 例2. チェックボックス選択時、 ファイルアイコン → フォルダアイコンに変更（isFolder）

...
// 選択時(→ flag = true)
if(flag) {
    // 選択したノード(dtnode)を「 isFolder: true 」に設定
    dtnode.data.isFolder = true;
    // 選択したノードを再描画
    dtnode.render();
}
...
```
**↓↓ ◆ 画面の動き（例2） ↓↓**
![GIF 2020-12-28 1-42-56.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/650537/d175b759-d7de-3bd7-beca-f82fd103893e.gif)

---
### ◆ dynatree の参考資料
dynatreeの仕様に関しては色々調べた中では、マニュアルが一番丁寧かつ詳しく説明されていたので、
まずはそちらに目を通してみることをお勧めします。
また、古いバージョンのマニュアルより新しいバージョンのマニュアルの方が、情報に漏れがなくより分かりやすい内容になっているので、
ネットで（古い）マニュアルのページを見るよりも、新しいバージョンのマニュアルをダウンロードすることをお勧めします。
<font color="silver">（扱っているdynatreeのバージョンが古い場合、使えない機能があるかもしれないのでご注意ください）</font>

新しいバージョンのマニュアルは https://github.com/mar10/dynatree で、**`Code > Download ZIP`** で **dynatree-master.zip** をダウンロードして、zipファイル内の
dynatree-master\doc\\**dynatree-doc.html** を開けば見ることができます。

---
### ◆ソースコード全体
ソースコードは[こちら](https://www.hos.co.jp/blog/20130430/)から拝借しました。（一部変更）

```（onSelectの項目を追加）.html
<html><head>
<meta charset="utf-8">
<link href="css/skin-vista/ui.dynatree.css" rel="stylesheet" type="text/css" id="skinSheet">
<style type="text/css">
<!--body {width: 400px;}-->
</style>
</head>
<body>
    <h5>Dynatreeのサンプルです。</h5>
 
    <div id="tree"></div>
 
    <script type="text/javascript" src="js/jquery-3.5.1.js"></script>
    <script type="text/javascript" src="js/jquery-ui.custom.js"></script>
    <script type="text/javascript" src="js/jquery.dynatree.js"></script>
 
    <script>
        var tree = $("#tree").dynatree({
            // children ここでツリーのノードを初期化することができます。
            children: [
                // title 表示名を指定します。
                {title: "ファイル1"},
                // isFolder フォルダかどうか指定します。
                {title: "フォルダ", isFolder: true,
                    children: [
                        {title: "子ファイル1"},
                        {title: "子ファイル2"}
                    ]
                },
                {title: "ファイル2",
                    children: [
                        {title: "子ファイル3"},
                        {title: "子ファイル4"}
                    ]
                }
            ],
            // checkbox チェックボックスの表示非表示を指定します。
            checkbox: true,
            // selectMode チェックボックスの選択形式を指定します。 1:単一, 2:複数, 3:複数で親選択時、子も全選択される
            selectMode: 2,
			
// ◆◆◆◆◆ 今回の実装部分： ここから ↓↓ ◆◆◆◆◆
			// onSelect チェックボックスを選択または選択解除した時の処理を書きます。
			// (第1引数(flag): 選択ならtrue、選択解除ならfalse; 第2引数(dtnode): 選んだノードの情報)
			onSelect: function(flag, dtnode) {
				// 選択時(→ flag = true)
				if (flag) {
					// visit 全ての子ノードに対して処理を実行します
					dtnode.visit(function(childNode) {
						// 子ノードを選択解除します
						childNode.select(false);
						// 子ノードを選択不可にします
						childNode.data.unselectable = true;
					});
				}
				// 選択解除時(→ flag = false)
				else {
					dtnode.visit(function(childNode) {
						// 子ノードを選択可に戻します
						childNode.data.unselectable = false;
					});
				}
			}
// ◆◆◆◆◆ 今回の実装部分： ここまで ↑↑ ◆◆◆◆◆
        });
    </script>
</body></html>
```