Angular - mat-grid-list 不显示 <ng-content> 传递的子项 [英] Angular - mat-grid-list not displaying children passed by <ng-content>

查看:22
本文介绍了Angular - mat-grid-list 不显示 <ng-content> 传递的子项的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用有角度的材料设计组件,并且想要创建一个自定义的网格列表组件.该组件将根据其大小调整网格列表列的数量.组件模板如下所示:

I'm using angular material design components and want to create a custom grid-list component. The component would adapt the number of grid-list-columns based on its size. The components template would look like this:

<mat-grid-list [cols]="adaptiveCols">
    <ng-content></ng-content>
</mat-grid-list>

组件将像这样使用:

<my-grid>
    <mat-grid-tile>tile_content</mat-grid-tile>
    <mat-grid-tile>tile_content</mat-grid-tile>
    <mat-grid-tile>tile_content</mat-grid-tile>
</my-grid>

所以你会认为这会显示一个 ,其中包含 3 个 ,以及结果DOM 将包含这些元素.但是您看不到图块及其内容.

So you would think this would display a <mat-grid-list> with 3 <mat-grid-tile>s in them, and the resulting DOM will contain those elements. But you don't see the tiles nor their content.

向网格列表添加更多图块并使用固定的 rowHeight 不会影响网格列表的 height 属性(从我可以找出的网格列表根据瓷砖的数量和列/行跨度计算其高度).这让您认为网格列表不会看到"<mat-grid-tile>-children.查看源代码网格列表并在 _layoutTiles() 上设置断点证实了这一点,在此方法中 this._tiles 为空.
我的猜测是有角度的 ContentChildren-注释(here) 没有在第一个代码片段中找到 tile-children 因为它只适用于 DOM 的第一级,而第一级我们只有 .

Adding more tiles to the grid-list and using a fixed rowHeight doesn't affect the height-attribute of the grid-list (from what I could figure out the grid-list calculates its height based on the number and col-/rowspan of tiles). That makes you think the grid-list doesn't "see" the <mat-grid-tile>-children. Looking at the source code of the grid-list and setting a breakpoint on _layoutTiles() confirmed this, in this method this._tiles is empty.
My guess is the angular ContentChildren-annotation (here) doesn't find the tile-children in the first code snippet because it only works on the first level of DOM, and that first level we only have the <ng-content>.

想要的结果很明确,我希望能够使用自定义的网格列表组件,给它一些子项并使用它的功能.但是出于某种原因,angular 不想让我成功,否则我还有东西要学.

The desired result is clear, I want to be able to use a custom grid-list component, give it some children and use its features. But for some reason, angular doesn't want me to succeed, or I still have the stuff to learn.

我使用的是 angular 6.1,并使用官方文档安装了材料组件.

I'm using angular 6.1 and installed the material-components using the official docs.

推荐答案

mat-grid-list 在它自己的实现中使用内容投影,因此它需要能够查询它的投影内容.尝试添加另一个级别的内容投影使这成为不可能,因为 mat-grid-tile 实际上不是由列表投影的,而是由您的组件投影的.

mat-grid-list uses content projection in it's own implementation and so it needs to be able to query it's projected content. Trying to add another level of content projection makes this not possible since the mat-grid-tile's are not actually being projected by the the list, but by your component.

这么简短的回答:这行不通.

So short answer: this isn't gona work.

可能有一种方法可以实现您的目标,但内容投影不是方法.如果您稍微澄清一下您的意图,我也许可以提供帮助.不过,您可能需要使用模板.

There is likely a way to achieve your goal but content projection isn't the way. If you clarify your intentions a bit, I may be able to help. You likley need to use templates though.

这是一个简单的例子:围绕 mat-grid-list 编写一个包装器,它接受一个数据数组作为输入,你可以用 ngFor 迭代来创建图块

Here's the simple case: write a wrapper around mat-grid-list that accepts an array of data as input that you can iterate over with ngFor to create the tiles

@Component({
  selector: 'my-grid',
  templateUrl: './my-grid.html'
})
export class MyGrid {
  @Input() data: string[];
}


<mat-grid-list>
  <mat-grid-tile *ngFor="let d of data">{{d}}</mat-grid-tile>
</mat-grid-list>

这为 mat-grid-list 提供了一个可重用的包装器,为您抽象了它的一部分.但是,如果您的网格内容比字符串(可能)更复杂,或者每次使用都需要自定义模板,这就不好了.在这种情况下,您需要一种更精细的方法,使用模板和指令:

This provides a reusable wrapper around mat-grid-list that abstracts a bit of it away for you. however, this is no good if your grid content is more complex than a string (likely) or requires custom templates on every usage. In this case, you need a somewhat more refined approach, using templates and directives:

@Directive({
  selector: 'gridTemplate'
})
export class GridTemplate {
   @Input() key: string;
   constructor(private elementRef: ElementRef, public template: TemplateRef<any>) {}
}

此指令将标识您的自定义模板,然后在您的网格列表中,您可以使用这些模板来填充图块

This directive will identify your custom templates then, in your grid list, you can use these templates to populate the tiles

@Component({
  selector: 'my-grid',
  templateUrl: './my-grid.html'
})
export class MyGrid implements AfterContentInit {
  //structure the data so it can be assigned to a template by key
  @Input() data: {templateKey:string, data: any}[];

  //use content children to find projected templates
  @ContentChildren(GridTemplate)
  gridTemplates: QueryList<GridTemplate>;

  gridTemplateMap: {[key:string]: TemplateRef<any>} = {};

  ngAfterContentInit() { 
    //store queried templates in map for use in template
    this.gridTemplates.forEach(t => this.gridTemplateMap[t.key] = t.template);
  }
}


<ng-template #defaultGridTemp let-d="data">{{d}}</ng-template>
<mat-grid-list>
  <mat-grid-tile *ngFor="let d of data">
    <!-- here we use the template map to place the correct templates or use a default -->
    <!-- we also feed the data property as context into the template -->
    <ng-container [ngTemplateOutlet]="(gridTemplateMap[d.templateKey] || defaultGridTemp)" 
                  [ngTemplateOutletContext]="{ data: d.data }" ></ng-container>
  </mat-grid-tile>
</mat-grid-list>

那么你对组件的使用是这样的:

Then your usage of your component is like this:

@Component({...})
export class MyComponent {
   data = [
    { templateKey:'MyKey1', data: {message: 'Projected Message', number: 1} },
    { templateKey:'MyKey2', data: {whatever: 'Message', youWant: 'to place'} }
   ];
}


<my-grid [data]="data">
  <ng-template gridTemplate key="MyKey1" let-d="data">
     <div>{{d.message}}</div>
     <div>{{d.number}}</div>
     <div>Any other arbitrary content</div>
  </ng-template>
  <ng-template gridTemplate key="MyKey2" let-d="data">
     <div>{{d.whatever}}</div>
     <div>{{d.youWant}}</div>
     <div>Any other arbitrary content</div>
  </ng-template>
</my-grid>

通过这种方法,您可以将任何可重用的逻辑添加到您想要在网格组件中的 mat-grid-list 中,但仍然保持为您的网格提供自定义模板的灵活性.缺点是您必须采取额外的步骤来构建数据以利用这种方法.

with this approach, you can add whatever reusable logic to mat-grid-list you want inside your grid component but still maintain the flexibility of providing custom templates to your grid. The drawback is that you have to take the extra steps to structure your data to take advantage of this approach.

这篇关于Angular - mat-grid-list 不显示 &lt;ng-content&gt; 传递的子项的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆