从 Angular 2 理解 *ngFor

Posted

技术标签:

【中文标题】从 Angular 2 理解 *ngFor【英文标题】:Understanding *ngFor from Angular 2 【发布时间】:2019-02-03 01:06:00 【问题描述】:

我正在尝试在我的 Angular 项目中使用嵌套的 *ngFor 来呈现动态菜单。我正在尝试这样的事情:

<li class="treeview" *ngFor="let pm of parentMenu">

    <a href="#">
      <i class="fa fa-edit"></i> <span>pm.MenuTitle</span>
      <span class="pull-right-container">
        <i class="fa fa-angle-left pull-right"></i>
      </span>
    </a>
    <ul class="treeview-menu" *ngFor="let cm of childMenu">
      <li *ngIf="cm.ParentMenuId == pm.Id">cm.MenuTitle</li>
    </ul>
  </li>

我只得到 childMenu 的第一个元素,我的理解是 *ngFor 的工作类似于 C# 中的 foreach,但显然情况并非如此。有人可以帮我修复代码并理解它吗?

【问题讨论】:

*ngIf works similar to foreach 我猜你的意思是*ngFor,它确实像forEach 一样工作。 *ngIfif 一样工作(这里没有惊喜) 是的,抱歉,会更新问题。 内部 *ngFor 会生成几个 li 元素,但 *ngIf 只会挑选出一个。还是其中几个条件为真? 那么它是如何工作的,第一次从外循环迭代,然后从内循环进行所有迭代,然后从外循环进行第二次迭代,再从内循环进行所有迭代,等等? 是的,就像一个外部和一个内部 for 循环 【参考方案1】:

试试这个代码

 <ul class="treeview-menu" *ngFor="let cm of pm.childMenu">
      <li *ngIf="cm.ParentMenuId == pm.Id">cm.MenuTitle</li>
    </ul>

【讨论】:

pm 没有 childMenu 属性。我正在读取两个不同的数组,parentMenu 和 childMenu。 为什么你有两个数组?【参考方案2】:

您可以通过使用模板、容器或组件的递归调用来实现递归菜单。您可以采用不同的方法。

Angular2 Navigation Menu with Recursive Templates

Recursion in Angular Components

Angular *ngFor recursive list tree template

【讨论】:

【参考方案3】:

我不知道您的 .ts 文件的内容,但您的代码在这里可以正常工作:

https://stackblitz.com/edit/angular-sduuwm

请注意,我已经像这样定义了我的数组:

  parentMenu = [
    
      Id: 1,
      MenuTitle: "One",
    ,
    
      Id: 2,
      MenuTitle: "Two",
    ,
    
      Id: 3,
      MenuTitle: "Three",
    
  ];

  childMenu = [
     
      ParentMenuId: 1,
      MenuTitle: "One quarter"
    ,
    
      ParentMenuId: 1,
      MenuTitle: "One half"
    ,
    
      ParentMenuId: 2,
      MenuTitle: "Two half"
    ,
    
      ParentMenuId: 3,
      MenuTitle: "Three half"
    
  ];

但是,也就是说,如果我是你,我宁愿这样定义我的数组:

  parentMenu = [
    
      Id: 1,
      MenuTitle: "One",
      childMenu: [
         MenuTitle: "One quarter" ,
         MenuTitle: "One half" ,
      ]
    ,
    
      Id: 2,
      MenuTitle: "Two",
      childMenu: [
         MenuTitle: "Two half" ,
      ]
    ,
    
      Id: 3,
      MenuTitle: "Three",
      childMenu: [
         MenuTitle: "Three half" ,
      ]
    
  ];

并像这样编写 html

<a href="#">
  <i class="fa fa-edit"></i> <span>pm.MenuTitle</span>
  <span class="pull-right-container">
    <i class="fa fa-angle-left pull-right"></i>
  </span>
</a>
<ul class="treeview-menu" *ngFor="let cm of pm.childMenu">
  <li>cm.MenuTitle</li>
</ul>

而且您的代码中不需要*ngIf 测试。

【讨论】:

对不起,我必须投反对票。如果你有父母,孩子有一个 uniq 对象。如果你有一个 uniq 对象,你必须使用 *ngFor="let child of pm .children" 无法理解您的评论,伙计,请更全面地证明您的反对意见。我同意替代解决方案不适用于他的 HTML,但它确实向他展示了解决问题的替代解决方案。 我最好不要使用 *ngIf 来只显示一个元素。您可以使用 let i=index 并显示 parentMenu[i].MenuTitle(仅使用最后一个 *ngFor)或仅将两个数组转换为一个。无论如何我只是删除了downvote(但我觉得答案不正确)【参考方案4】:
<ul>    
          <ng-template #recursiveMenu let-parentMenu>
             <li class="treeview" *ngFor="let pm of parentMenu">
               <a href="#">
                 <i class="fa fa-edit"></i> <span>pm.MenuTitle</span>
                 <span class="pull-right-container">
                   <i class="fa fa-angle-left pull-right"></i>
                  </span>
               </a>
               <ul class="treeview-menu">
                 <ng-container *ngTemplateOutlet="recursiveMenu; context: 
                   $implicit: pm.childMenu">
                 </ng-container>
               </ul>
             </li>
          </ng-template>
          <ng-container *ngTemplateOutlet="recursiveMenu; context: 
            $implicit: parentMenu">
          </ng-container>
</ul>

【讨论】:

能否给你的代码添加一点解释。【参考方案5】:

你是正确的,ngFor 的行为类似于 foreach 或 for 循环。

我怀疑你的问题是你绑定的对象。

基本上使用您的代码,组件上应该有一个名为 parentItem 的属性,它是一个具有嵌套属性的数组,包括 childMenu

parentMenu = 
    'Parent1':['menuTitle':'Menu 1', 'childItem':[
      'menuTitle':'sub item 1']
      ,
     'menuTitle':'A cool menu', 'childItem':[
       'menuTitle':'sub item 1',
     'menuTitle': 'sub item 2']
     ]
  

然后你的 HTML 应该像这样工作:

<li class="treeview" *ngFor="let pm of parentMenu.Parent1">

    <a href="#">
      <i class="fa fa-edit"></i> <span>pm.menuTitle</span>
      <span class="pull-right-container">
        <i class="fa fa-angle-left pull-right"></i>
      </span>
    </a>
    <ul class="treeview-menu" *ngFor="let cm of pm.childItem">
      <li>cm.menuTitle</li>
    </ul>
  </li>

对于reference in action a working stackblitz from your code:

【讨论】:

即使根据您的建议重构了代码,我仍然只得到子菜单的第一个元素。渲染长度时,它显示 2 但只有第一个元素被渲染。我现在完全糊涂了。它应该可以工作。 我的 html 模板似乎有问题。在删除所有引导类并只放置纯 html 后,一切都正确呈现。 我不得不把内部 *ngFor 放在 而不是 中,如下所示: cm.MenuTitle

以上是关于从 Angular 2 理解 *ngFor的主要内容,如果未能解决你的问题,请参考以下文章

Angular 新手,非响应式动态表

从订阅者 Angular 获取数据的问题

为什么Angular 9必须预先编译自身代码?

ngAfterContentChecked() 无法理解 + 角度 2

视频分享Angular 4.0从入门到实战 打造股票管理网站

angular组件间共享数据的四种方式