1
votes

I'm trying to bind to input properties on a child component inside of a ngFor loop to create a menu structure. I haven't been able to find anything in my searches to help, so I'm posting this question.

I'm storing the menu structure in code in the sidebar component as an array of MenuItemComponents -> MenuStructure

sidebar.component.ts: (Parent component)

export class SidebarComponent implements AfterViewInit {

  MenuStructure: MenuItemComponent[] = [];

  ngAfterViewInit() {
    //Define and Add Dashboard
      var dashboard = new MenuItemComponent(null);
      dashboard.title = 'Dashboard';
      dashboard.iconName = 'dashboard';

    //Define Documentation
      var documentation = new MenuItemComponent(null);
      documentation.title = 'Documentation';
      documentation.iconName = 'insert drive file';

    this.MenuStructure.push(dashboard);
    this.MenuStructure.push(documentation);
  }
}

This is the child component (aka. the building block of the menu):

menu-item.component.ts:

@Component({
  selector: 'app-menu-item',
  templateUrl: './menu-item.component.html',
  styleUrls: ['./menu-item.component.css']
})
export class MenuItemComponent implements OnInit {
  @Input() iconName: string;
  @Input() title: string;
  @Input() children: MenuItemComponent[] = [];
  @Input() routeLink: string = '';

  constructor(private parent: MenuItemComponent) { }

menu-item.component.html:

<a><i class="material-icons">{{iconName}}</i><span>{{title}}</span>
    <i class="material-icons" >&#xE313;</i> 
</a>

The above template is used in a ngFor loop in the sidebar template...

sidebar.component.html:

  <ul>
    <li *ngFor="let item of MenuStructure">
        <app-menu-item [title]='item.title' [iconName]='item.iconName'>
        </app-menu-item>
    </li>
  </ul>

However when trying to implement this, I get the following template error:

Template parse errors:
Cannot instantiate cyclic dependency! MenuItemComponent ("<ul>
        <li *ngFor="let item of MenuStructure">
            [ERROR ->]<app-menu-item [title]='item.title' [iconName]='item.iconName'>
            </app-menu-item>
      "): SidebarComponent@9:12

Can anyone shed some light on why it is complaining / a fix, and/or a better way to do this in angular 2?

1
sorry I checked. you are right.So i deleted my answer. I think in your case it is a dependency-injection error. constructor(private parent: MenuItemComponent) i think you are getting error because of this.Are you sure you can use routeLink directly because it is used by router & and its a kind of special variable ?Amit kumar
routeLink is not in use in my simplified example, but you were right about the MenuItemComponent being injected into the constructor, I don't think the dependency injector was smart enough to create a seperate reference and/or I've got the design wrong, so I'll have to try and figure out how to add a reference to the parent without passing it into the constructor (prob will just use property injection).MikeDub

1 Answers

0
votes

As pointed out by Amit, the error I was getting was generated from passing private parent: MenuItemComponent into the MenuItemComponent constructor (it's own constructor).

I falsely assumed that the dependency injector would create a different reference/instance for it and stop there, but turns out it was creating an infinite loop.

At this stage, I still haven't found a better solution on how to implement a Menu with children in angular 2 using components / sub-components, so anyone with a better solution is welcome to add an answer, but this answer addresses the error directly.