创建由JSON驱动的动态多级菜单

时间:2017-03-16 15:56:14

标签: angular typescript

问题

我正在尝试在Angular中创建由JSON驱动的动态多级主导航(菜单)。

在AngularJS中,我会定义一个模板并递归地使用它来根据需要动态创建额外级别的菜单。

在Angular中,我无法找到一种动态创建这些菜单级别的方法。

目前我已将其硬编码为允许两个级别,但如果将来需要添加更多级别,则必须对每个级别进行硬编码才能正常工作。

我正在寻找一种基于菜单返回的JSON动态执行此操作的方法。

JSON

menu = [
  {
    title: "Menu Item 1",
        url: "/",
        target: "_blank"
    },
    {
    title: "Menu Item 2",
        active: true,
        navigationItems: [
            {
              title: "Sub-Menu Item 1",
              url: "/"
            },
            {
              title: "Sub-Menu Item 2",
              url: "/",
              navigationItems: [
                  {
                      title: "This Level Not Supported Without Hard-Coding"
                  }
              ]
            }
        ]
    }
]

标记

<div>
    <ul role="menubar">
        <li *ngFor="let link of menu; let i = index;">

            <a 
              [attr.href]="link.href ? link.href : null"
              [attr.target]="link.target ? link.target : null"
              aria-role="menuitem"
              [attr.ariaExpanded]="link.navigationItems && openElements[i] ? true : null"
              [attr.ariaHasPopup]="link.navigationItems ? true : null"
              (click)="link.navigationItems ? openElements[i] = !openElements[i] : null"
              [class]="openElements[i] ? 'open' : null"
            >
              {{link.title}}
            </a>

            <ul *ngIf="link.navigationItems" role="menu">
                <li *ngFor="let link of link.navigationItems">
                    <a [attr.href]="link.url"
                        [innerHTML]="link.title"
                        [attr.target]="link.target ? link.target : null"
                        role="menuitem"
                    >
                    </a>
                </li>
            </ul>

        </li>
    </ul>
</div>

工作实例

https://plnkr.co/edit/lpLxHlKtwCJUukoruxq2?p=preview

解决方案

我需要一种方法来确保可以根据从附加到组件的数据服务返回的JSON的结构将任意数量的级别添加到此菜单,而不需要在每个标记中使用硬编码级别水平。

1 个答案:

答案 0 :(得分:6)

设置自定义递归组件

NavItem.d.ts

export interface NavItem {
  title: string;
  active: boolean;
  target: string;
  url: string;
  navigationItems: NavItem[];
}

NavItem.component.ts

import { Component, Input } from '@angular/core';
import { NavItem } from 'NavItem.d.ts';

@Component({
  selector: 'nav-item',
  template: 'NavItem.component.html'
})
export class NavItemComponent {

    @Input() private navItems: NavItem[];

    constructor() {
    }
}

NavItem.component.html

<ul role="menubar">
  <li *ngFor="let item of navItems">
    <a ...>{{ item.title }}</a>
    <nav-item *ngIf="item.navigationItems" [navItems]="item.navigationItems"></nav-item>
  </li>
</ul>

用法:在可访问navItems

的现有模板内
<nav-item [navItems]="navItems"></nav-item>