1

I have a situation in Angular 2. Where i have to iterate through ngFor based on child. My component should be capable of rendering list based on the Input given. So here is the data structure

[
 {
   name: 'ABCD',
   child:[
     name: 'A1',
     child:[
      name: 'A1.1',
      child:[....]
     ]
   ] 
 }
]

Now i tried rendering this structure inside my template by using component life cycle ngOnInit by manipulating DOM and it is working.

Is there any other way without manipulating DOM in angular 2? may be by using ngFor inside template or something else. I tried many things but no luck.

UPDATE: Tried DOM manipulation

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'multiple-drop-down',
  template: `
  <div class="dropdown">
    <button id="dLabel" type="button" class="btn btn-primary"
    data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                 {{selected.size}} item selected<span class="caret"></span>
    </button>
    <ul class="dropdown-menu treeview" aria-labelledby="dropdownMenu">
        <li id="item-lists">
            <a href="javascript:void(0);" (click)="toggleItemSelect($event)">
                <input (change)="selectAll($event)" type="checkbox" id="checkbox-select-all">
                <label for="tall" class="custom-unchecked">Select All</label>
            </a>
        </li>
    </ul>
  </div>
   `,
 })
 export class MultipleDropDownComponent implements OnInit {
 menuItemList: Array<MenuObject>;
 selected: Set<string>;

 constructor() {
   this.selected = new Set<string>();
   this.menuItemList = [
     { name: 'item 1', id: 'A', child: [
       { name: 'item 1.1', id: 'A1', child: [
           { name: 'item 1.11', id: 'Aa1', child: []},
           { name: 'item 1.12', id: 'Aa2', child: []},
           { name: 'item 1.13', id: 'Aa3', child: []}
       ]},
       { name: 'item 1.2', id: 'A2', child: []}]},
    { name: 'item 2', id: 'B', child: []},
    { name: 'item 3', id: 'C', child: []},
    { name: 'item 4', id: 'D', child: []}];
  }

  ngOnInit() {

    // calling render method to populate dropdown values
    this.renderChildElements('item-lists', this.menuItemList , 'first');
  }

  renderChildElements(id: string, items: MenuObject[], key: string): void {
    let parent = this.createULElement(id, key);
    items.forEach((element: MenuObject) => {
        let Li = document.createElement('li');
        Li.setAttribute('id', element.id);
        Li.innerHTML = `<a href="javscript:void(0);"
                        (click)="toggleItemSelect($event)">
                        <input type="checkbox" name="` + element.name + `"
                        id="` + element.id + `" (click)="toggleMultiSelect($event, ` + element + `)">
                        <label for="tall-1" class="custom-unchecked">` + element.name + `</label>
                        </a>`;
        document.querySelector('#' + parent).appendChild(Li);

        // this condition is responsible for recurrsion process
        if ( element.child.length > 0 ) {
            this.renderChildElements(element.id, element.child, element.id);
        }
    });
  }
  createULElement(parentId: string, childId: string): string {
    let ulId = childId + 'ul';
    let newUl = document.createElement('ul');
    newUl.setAttribute('id', ulId);
    document.querySelector('#' + parentId).appendChild(newUl);
    return ulId;
  }
}
export interface MenuObject {
   id: string;
   name: string;
   child?: MenuObject[];
}
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
Rohit
  • 35
  • 4
  • Something like http://stackoverflow.com/questions/38821475/recursive-component-loading-with-recursive-array/38822751#38822751 ? – Günter Zöchbauer Sep 16 '16 at 07:20
  • This might also be interesting for your use case (not required) http://stackoverflow.com/questions/37602561/ng2-equivalent-of-require/37606138#37606138 – Günter Zöchbauer Sep 16 '16 at 07:25
  • @GünterZöchbauer no this is just an iteration of item. As you can see my array as n number of child data. And my ngFor should be smart enough to check if it has child it should iterate with the data and again each set of data has its own child. I hope that you are understanding what am trying to achieve. – Rohit Sep 16 '16 at 07:25
  • http://stackoverflow.com/questions/37602561/ng2-equivalent-of-require/37606138#37606138 This link has limits. we can iterate only upto one or two level. And my component is common hence it should be doing this by itself. I have achieved this via DOM manipulation but thats seems not right in angular 2 – Rohit Sep 16 '16 at 07:28
  • It would be easier if you would add the code that shows what you tried. You just need an `*ngIf` that recognizes if the item is a `name` or a `child`. In case of `name` show the name, in case of `child`, add a child and pass the data to the child. This can go on until your browser runs out of memory ;-) – Günter Zöchbauer Sep 16 '16 at 07:28
  • Updated with existing code – Rohit Sep 16 '16 at 07:35

1 Answers1

0

This should do what you want:

@Component({
  selector: 'child',
  template: `
<div>{{data?.name}}</div>
<child [data]="data?.child]></child>`
})
class ChildComponent {
  @Input() data;
}
@Component({
  selector: 'my-app',
  template: `
<child [data]="data?.child]></child>`
})
class ChildComponent {
data = [
 {
   name: 'ABCD',
   child:[{
     name: 'A1',
     child:[{
      name: 'A1.1',
      child:[....]
     }]
   }] 
 }
];
}
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567