Dexter
Dexter

Reputation: 528

how to apply check boxes for parent and children in angular & bootstrap 3.3.7

here what my requirement is :-

when ever i click on the parent its child elements has also get selected and in that also we can deselect what ever we dont want. And on button click the we have to get the selected parent & children names as object

what i did till now :-

i created a list of parents and children and supplied checkbox for the parent and getting the parents values after check n uncheck and getting the value

im stuck how can i select the children in that parent and get values of both parent and children

below is my code

.ts

 @ViewChildren('myItem') item;
  selectedIds = [];
 display:any;
 data:any;

  ngOnInit(){


    // dynamic json 

    this.data = {
  "info": {
    "laptop": {
    },
    "config": {
      "properties": {
        "ram": {
        },
        "processor": {
        },
        "hdd": {

        }
      }
    },
    "link": {

    },
    "name": {

    },
    "company": {
      "properties": {
        "model": {

        },
        "maker": {
          "type": "integer"
        },
        "country": {
          "type": "text"
        },
        "enterprise": {

        }

      }
    }
  }
};


  // varible 

    this.display = this.data['info'];
    console.log(this.display);

  }

  change(data,event){
 if (event.target.checked === true) {
      this.selectedIds.push({id: data, checked: event.target.checked});
      console.log('Selected data ', JSON.stringify(this.selectedIds));
    }
    if (event.target.checked === false) {
      this.selectedIds = this.selectedIds.filter((item) => item.id !== data);
    }


}
getData(){
      const filtered = this.selectedIds.filter(item => item.id)
 console.log(JSON.stringify(filtered));
    }

.html code

<ul class="list-group" *ngFor="let parent of display | keyvalue">
  <li class="list-group-item">  <input  type="checkbox" [value]="parent.key" [(ngModel)]="parent.check"  #myItem  (change)="change(parent.key,$event)">{{parent.key}}</li>
 <ng-container *ngIf="parent.check && parent.value.hasOwnProperty('properties')">
      <ul *ngFor="let child of parent.value.properties | keyvalue">
      <li>
        {{child.key}}
      </li>
      </ul>  
    </ng-container> 
</ul>

<hr>

<button class="btn btn-primary"(click)="getData()">get Data</button>

my stackblitz link

https://stackblitz.com/edit/angular-8vqwsc

parent and child

Upvotes: 0

Views: 1450

Answers (1)

Eliseo
Eliseo

Reputation: 58074

the only thing you need is pass to your function the "children"

(change)="change(parent.key,parent.value.properties,$event)"

then in your function change becomes like

  change(data, children, event) {
    if (event.target.checked === true) {
      this.selectedIds.push({ id: data, checked: event.target.checked });
      for (let child in children) {
        this.selectedIds.push({ id: child, checked: event.target.checked });
      }
    }
    if (event.target.checked === false) {
      this.selectedIds = this.selectedIds.filter((item) => item.id !== data);
      for (let child in children) {
        this.selectedIds = this.selectedIds.filter((item) => item.id !== child);
      }
    }

There are a problem that is show the selected values. For this you need make a function

  isChecked(child) {
    let item = this.selectedIds.find(x => x.id == child.key)
    return item ? item.checked : false
  }

And add (click) to the "children" to change the this.selected

  <ul *ngFor="let child of parent.value.properties | keyvalue">
  <li>
    <input  type="checkbox" [checked]="isChecked(child)" (change)="change(child.key,null,$event)"/>
    {{child.key}}
  </li>
  </ul>  

But I think that there're a better way to do the things. Imagine that your data becomes

this.data2 =[ 
  {
    "id":"laptop","checked":false
    },
    {"id":"config","checked":false,"properties": [
        {"id":"ram","checked":false},
        {"id":"processor","checked":false},
        {"id":"ram","checked":false}
      ]
    },
    {"id":"link","checked":false},
    {"id":"name","checked":false},
    {"id":"company","checked":false,"properties":[
        {"id":"model","checked":false},
        {"id":"maker","checked":false},
        {"id":"country","checked":false},
        {"id":"enterprise","checked":false}

    ]}
]

(I put checked property, but it's not necesary) Your .html becomes easer

<ul *ngFor="let parent of data2">
  <li><input  type="checkbox" [(ngModel)]="parent.checked" (change)="changedChild(parent.checked,parent.properties)"> {{parent.id}}
      <ng-container *ngIf="parent.checked">
        <ul  *ngFor="let child of parent.properties">
      <li>
        <input  type="checkbox" [(ngModel)]="child.checked" />
        {{child.id}}
      </li>
      </ul>  
      </ng-container>
  </li>
</ul>

And the function changedChild

changedChild(value,children)
{
   if (children)
       children.forEach(x=>x.checked=value)
}

Updated adding object to this.selectedChild the functions becomes

change(data, children, event) {
    if (event.target.checked === true) {
      this.selectedIds.push({ id: data, checked: event.target.checked });
      for (let child in children) {
        this.selectedIds[this.selectedIds.length-1][child]=event.target.checked;

      }
    }
    if (event.target.checked === false) {
      this.selectedIds = this.selectedIds.filter((item) => item.id !== data);
    }

}
changeChild(parentKey,childKey,event)
{
    let item:any = this.selectedIds.find(x => x.id == parentKey)
    if (event.target.checked)
      item[childKey]=event.target.checked;
    else
      delete item[childKey];

}

isChecked(parentKey,childKey) {
    let item:any = this.selectedIds.find(x => x.id == parentKey)
    return item ? item[childKey] : false
  }

And the html

<ul class="list-group" *ngFor="let parent of display | keyvalue">
  <li class="list-group-item">  <input  type="checkbox" [value]="parent.key" [(ngModel)]="parent.check"  #myItem  (change)="change(parent.key,parent.value.properties,$event)">{{parent.key}}</li>
 <ng-container *ngIf="parent.check && parent.value.hasOwnProperty('properties')">
      <ul *ngFor="let child of parent.value.properties | keyvalue">
      <li>
         <input  type="checkbox" [checked]="isChecked(parent.key,child.key)" (change)="changeChild(parent.key,child.key,$event)"/>
    {{child.key}}

      </li>
      </ul>  
    </ng-container> 
</ul>

See forked stackblitz

Upvotes: 1

Related Questions