title: Best approach to create recursive treeview dynamically from data API
body: <p>I'm learning Angular 2, trying to build an expandable tree-view from a (potentially very large) third-party API.  The API has an underlying structure like this:</p>
  
  <pre><code>- Home (id: 1053)
  - - Rugby League (id: 1054)
  - - - Super League (id: 1103)
  - - - - Castleford Tigers (id: 1111)
  - - - - Catalans Dragons (id: 1110)
  - - - - Huddersfield Giants (id: 1116)
  - - - - Hull FC (id: 1108)
  - - - Championship (id: 1104)
  - - - - Batley Bulldogs (id: 1120)
  - - - - Bradford Bulls (id: 1118)
  - - - - Dewsbury Rams (id: 1124)
  - - - - Featherstone Rovers (id: 1121)
  - - Football (id: 1056)
  - - - Premier League (id: 1057)
  - - - - AFC Bournemouth (id: 1059)
  - - - - etc
  - - - - etc
  </code></pre>
  
  <p>The API is set up such that I pass an id and it returns a simple JSON array of the children (only) of that node.  So, for example I call: <code>http://www.example.com/api/contentNodes/?parentId=1053</code> and it returns:</p>
  
  <pre><code>[
    {"Id":1054,"Name":"Rugby League","HasChildren":true},
    {"Id":1056,"Name":"Football","HasChildren":true}
  ]
  </code></pre>
  
  <p>(<code>HasChildren</code> represents whether or not the node has child nodes.)</p>
  
  <p>Note, because the data-set will eventually be large I want to 'pull in' more data from the API progressively as the tree branches are opened, rather than dumping the entire data-set in there and rendering that out in my app.</p>
  
  <p>I've set up an Angular 2 app which can be seen here: <a href="http://plnkr.co/edit/QQ1OKCbd4pDptpSVbWch?p=preview" rel="noreferrer">http://plnkr.co/edit/QQ1OKCbd4pDptpSVbWch?p=preview</a></p>
  
  <p>The key component is the `app/content-list.component.ts' file:</p>
  
  <pre><code>import {Component, OnInit}  from 'angular2/core';
  import {ContentNode}        from './content-node';
  import {ContentService}     from './content.service';
  
  @Component({
      selector: 'content-list',
      template: `
          &lt;ol class="tree"&gt;
              &lt;li *ngFor="#contentNode of contentNodes" class="tree__branch" [ngClass]="{'tree__branch--has-children': contentNode.HasChildren}"&gt;
                  &lt;a *ngIf="contentNode.HasChildren" (click)="toggleBranch(contentNode.Id)" class="toggle"&gt;+&lt;/a&gt; {{ contentNode.Name }}
              &lt;/li&gt;
          &lt;/ol&gt;
          &lt;div class="error" *ngIf="errorMessage"&gt;{{errorMessage}}&lt;/div&gt;
      `
  })
  export class ContentListComponent implements OnInit {
  
      constructor (private _contentService: ContentService) {}
  
      errorMessage: string;
      private _startNodeId: number = 1053;
  
      contentNodes: ContentNode[];
  
      ngOnInit() { 
          this.getContentNodes();
      }
  
      getContentNodes() {
          this._contentService.getContentNodes(this._startNodeId)
              .subscribe(
                  contentNodes =&gt; this.contentNodes = contentNodes,
                  error =&gt;  this.errorMessage = &lt;any&gt;error
              );
      }
  
      toggleBranch(branchId:number){
          console.log('branchId: ' + branchId);
      }
  }
  </code></pre>
  
  <p>You'll see here that I'm calling my service which returns the JSON as above, by being passed a parentId of 1053.</p>
  
  <p>I've now hit a wall in being able to progressively load the child nodes of the treeview when the <code>+</code> button is clicked, into the nested HTML list (<code>&lt;ol&gt;</code>).</p>
  
  <p>What would be the best approach here, to achieve this in a really neat way?</p>
  
  <p>My next step will be to ensure that the app doesn't make excessive API calls, but my immediate concern is just to get a running treeview hooked up and working.</p>
  
  <p>I've seen <a href="http://www.syntaxsuccess.com/viewarticle/recursive-treeview-in-angular-2.0" rel="noreferrer">this example of a recursive treeview</a> but it seems (a) a little buggy (in that there are empty <code>&lt;ol&gt;&lt;/ol&gt;</code> elements rendered in the HTML when child nodes are empty etc); and (b) it seems to be set up in a very 'hard-coded' kind of a way and I'm not experienced enough to confidently refactor it.</p>
  
  <p>Many thanks.</p>
  
  <p><em>Note, for security reasons I can't open up the API to public requests unfortunately, which makes testing this on Plunkr a little difficult, I realise.  For the moment my example uses just a static, single level JSON data-set.</em></p>