0

I have a JSON file with hierarchical data:

[
  {
    "id": 0,
    "label": "Gap Inc.",
    "value": "Gap Inc",
    "checked": false,
    "children": [
      {
        "id": 0,
        "label": "Banana Republic",
        "value": "Banana Republic",
        "checked": false
      },
      {
        "id": 1,
        "label": "Gap",
        "value": "Gap ",
        "checked": false
      },
      {
        "id": 2,
        "label": "Hill City",
        "value": "Hill City",
        "checked": false
      },
      {
        "id": 3,
        "label": "Old Navy",
        "value": "Old Navy",
        "checked": false
      }
    ]
  },
  {
    "id": 1,
    "label": "Home Depot",
    "value": "Home Depot",
    "checked": false,
    "children": []
  },
  {
    "id": 2,
    "label": "TJX",
    "value": "TJX Companies",
    "checked": false,
    "children": [
      {
        "id": 0,
        "label": "TJ Maxx",
        "value": "TJ Maxx ",
        "checked": false
      },
      {
        "id": 1,
        "label": "Marshalls",
        "value": "Marshalls",
        "checked": false
      },
      {
        "id": 2,
        "label": "Home Goods",
        "value": "Home Goods",
        "checked": false
      }
    ]
  }
]

I am using it to create a set of nested HTML lists with checkboxes:

<ul class="list-unstyled">
  <li *ngFor="let parent of accountList; let q = index">
     <div class="form-check">
         <input id="parent-{{q}}"
                class="form-check-input"
                type="checkbox"
                [(ngModel)]="parent.checked"
                (click)="selectChildren(parent, $event)"
                [indeterminate]="selectedChildren.length">
         <label for="parent-item" class="form-check-label">
           {{parent.label}}
         </label>
     </div>

     <ul class="list-unstyled pl-4">
         <li *ngFor="let child of parent.children; let i = index;">
             <div class="form-check">
                  <input id="child-{{i}}"
                         class="form-check-input"
                         type="checkbox"
                         [(ngModel)]="child.checked"
                         (click)="selectChild(child, $event)">
                  <label for="child-{{i}}" class="form-check-label">
                       {{child.label}}
                   </label>
             </div>
         </li>
     </ul>
   </li>
</ul>

What's supposed to happen

If you click a parent checkbox, it checks all the children. If you click only one child, its parent is set to indeterminate.

What DOES happen

If you click a parent checkbox, it checks all the children. If you click only one child, ALL parents are set to indeterminate.

I assume I screwed up something somewhere. I think I have mapped the indeterminate attribute to the length of any selected children (here selectedChildren instead of only the children of the given parent. Not sure how to fix that...

Here is the typescript:

selectedChildren = [];

selectChildren = function(data, event) {
    const parentChecked = !data.checked;
    data.children.forEach((child, key2) => {
      child.checked = parentChecked;
    });
  };

  selectChild = (data, event) => {
    if (this.selectedChildren.indexOf(data.id) === -1) {
      this.selectedChildren.push(data.id);
      data.checked = true;
    } else {
      this.selectedChildren.splice(this.selectedChildren.indexOf(data.id), 1);
      data.checked = false;
    }
  };
Steve
  • 14,401
  • 35
  • 125
  • 230
  • Is selectChild being called multiple times when you click a child checkbox? – IrkenInvader Apr 23 '19 at 19:40
  • No, it seems to be called as expected. My issue seems to be all the parent checkboxes' indeterminate attribute is linked to an array length which includes _any_ children — how do I make sure the parent only looks for its _own_ children? – Steve Apr 23 '19 at 19:50

0 Answers0