【问题标题】:Using mat-accordion and mat-expansion-panel in ngFor在 ngFor 中使用 mat-accordion 和 mat-expansion-panel
【发布时间】:2020-02-28 18:28:57
【问题描述】:

我正在尝试使用 ngFor 循环一些项目并为每个项目创建一个 mat-expansion-panel。

我想将每个item的逻辑封装到一个item组件中:

    <item></item>

初步尝试:

<mat-accordion>
  <div *ngFor="let item of items" >
    <item [item]="item"></item>
  </div>
</mat-accordion>

项目模板在哪里:

    <mat-expansion-panel>
      <mat-expansion-panel-header>
        Header Content
      </mat-expansion-panel-header>

      <div>
         Expandable content
      </div>
    </mat-expansion-panel>

这种方法的问题是我的组件在&lt;mat-accordion&gt;&lt;mat-expansion-panel&gt; 之间有一个额外的html 元素,这会弄乱手风琴的css。

有没有办法让我的组件提供标题和内容?

    <mat-accordion>
      <div *ngFor="let item of items" >
          <mat-expansion-panel>
            <mat-expansion-panel-header>
              <!-- put item component header here->
            </mat-expansion-panel-header>

          <div>
            <!-- put item component content here->
          </div>
        </mat-expansion-panel>
      </div>
    </mat-accordion>

我已经阅读了 ng-content,但我认为这与我想要的相反,我不想将自定义内容推送到我的组件中,我想从我的组件中提取元素并让它们呈现在父母。

我确实意识到我可以创建 2 个组件,即 item-header 和 item-content。但是,我真的很想将该登录信息保留在一个组件中。

【问题讨论】:

  • 将 *ngFor 放在
  • @JMP 不会为每个项目创建一个手风琴吗?
  • @JMP ngFor onaccordion 创建了多个手风琴元素,这是不正确的,应该只有一个。
  • 从模板中取出 并循环播放?最后的猜测!

标签: angular angular-material


【解决方案1】:

我遇到了同样的问题。关于这个主题的Pull Request is opened,但从未合并。 通过在下面添加这段代码,我们可以稍微改进一下布局(边界半径)。为简单起见,我们能做的最好的事情是在第一个和最后一个面板的顶部和底部恢复 border-radius

但是上一个面板的底部不展开,下一个面板的顶部不展开就更难了……

主要组件.html:

<mat-accordion class="custom-accordion">
  <item *ngFor="let item of items" [item]="item"></item>
</mat-accordion>

item.component.ts:

@Component({
  selector: 'app-item',
  template: `
    <mat-expansion-panel>
      <mat-expansion-panel-header>
        Header Content
      </mat-expansion-panel-header>
      <div>
        Expandable content
      </div>
    </mat-expansion-panel>
  `,
  host: {
    'class': 'expansion-panel-wrapper',
    '[class.expanded]': 'expansionPanel && expansionPanel.expanded',
  }
})
export class ItemComponent {
  @ViewChild(MatExpansionPanel, { static: false }) expansionPanel;
  ...
}

在styles.scss 中:

.custom-accordion.mat-accordion {
  .expansion-panel-wrapper:first-of-type .mat-expansion-panel {
    border-top-right-radius: 4px;
    border-top-left-radius: 4px;
  }

  & > :not(.expanded) .mat-expansion-panel {
    border-radius: 0;
  }

  & > .expansion-panel-wrapper:last-of-type > .mat-expansion-panel {
    border-bottom-right-radius: 4px;
    border-bottom-left-radius: 4px;
  }
}

【讨论】:

  • 很好 - 我完全错过了我的答案中的非常轻微的样式错误。被评为更好的答案。
  • 不要以为他们会合并那个 PR。更多信息也在这里:github.com/angular/components/issues/…。提到手风琴和扩展面板之间的紧密耦合讨论。猜猜它要么破解 css,要么制作 2 个组件,一个用于标题,一个用于内容。
  • 我稍微改了一下css,改了部分:&amp; &gt; .expansion-panel-wrapper:first-of-type &gt; .mat-expansion-panel {border-top-right-radius: 4px; border-top-left-radius: 4px;} &amp; &gt; .expansion-panel-wrapper &gt; .mat-expansion-panel:not(.mat-expanded) { border-radius: 0;} 现在我们不需要使用@ViewChildhost.class-expanded
【解决方案2】:

你快到了。您不需要任何包装元素 - 您可以直接在组件上使用 *ngFor:

<mat-accordion>
    <item *ngFor="let item of items" [item]="item"></item>
</mat-accordion>

使用简单的工作代码示例进行堆栈闪电战: https://stackblitz.com/edit/angular-pvse7t

【讨论】:

  • 是的,认为您在下面发现了它,css 与额外的组件元素不正确。
【解决方案3】:

通过查看代码,我认为您的问题来自于此:

<mat-accordion>
  <div *ngFor="let item of items" > **//this right here creates a 'div' element for each loop**
    <item [item]="item"></item>
  </div>
</mat-accordion>

尝试用 ng-container 替换 div:

<mat-accordion>
  <ng-container *ngFor="let item of items" > **//ng-container is never rendered in the DOM**
    <item [item]="item"></item>
  </ng-container>
</mat-accordion>

【讨论】:

    【解决方案4】:

    来自https://stackoverflow.com/a/38716164/11928194,试试看

    <mat-accordion>
      <ng-container *ngFor="let item of items" >
        <mat-expansion-panel item  [item]="item"></mat-expansion-panel>
      </ng-container>
    </mat-accordion>
    

    使用 ItemComponent 选择器作为 '[item]'

    【讨论】:

    • 很确定你不能在另一个组件上应用属性选择器。错误“多个组件在此元素上匹配。确保只有一个组件的选择器可以匹配给定元素。”
    • 我的错。不应该发布未经测试的答案。
    【解决方案5】:

    为什么不直接将ngFor应用到扩展面板上呢?

    <mat-accordion>
      <mat-expansion-panel *ngFor="let item of items">
        <mat-expansion-panel-header>
          <mat-panel-title>
            Header Content
          </mat-panel-title>
        </mat-expansion-panel-header>
        <ng-template matExpansionPanelContent>
          Expandable Content
        </ng-template>
      </mat-expansion-panel>
    </mat-accordion>
    

    我试图分享来自 Stackblitz 的链接,但不幸的是,我们似乎在分享时遇到了错误,所以我将分享我的意思的屏幕截图:

    编辑:看来 Stackblitz 现在决定合作了。这是链接:https://stackblitz.com/edit/angular-ae7cfr

    【讨论】:

    • 与其他 cmets 一起再次检查问题。问题是由于额外的 html 元素,这会弄乱面板的 css 样式。
    • @lostintranslation,我希望您重新考虑,以防您投反对票,即使此答案对您没有帮助。原因是我的答案实际上并没有引入新元素,实际上与其他答案不同。在您的问题中,您 ngFor 是一个包装 div。 Sidson Aidson 和 Kaustubh Badrike ng 用于包装 ng 容器。 TotallyNewb ngFor 具有扩展面板的组件(本质上与 ngFor 包装 ng-container 相同)。直接挖掘 ngFor 扩展面板,您可以将其用作以列表作为输入的组件。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-12-26
    • 2018-07-04
    • 2019-10-26
    • 2019-07-21
    • 1970-01-01
    • 2019-03-09
    • 1970-01-01
    相关资源
    最近更新 更多