我正在使用角度材料设计组件,并希望创建一个自定义的网格列表组件。该组件将根据其大小调整网格列表列的数量。组件模板如下所示:
<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个<mat-grid-list>
的{{1}},并且结果DOM将包含这些元素。但是您看不到图块或它们的内容。
向网格列表中添加更多图块并使用固定的<mat-grid-tile>
不会影响网格列表的rowHeight
属性(据我所知,网格列表会计算出其高度取决于瓷砖的数量和色散/行跨度)。这使您认为网格列表没有“看到” height
子级。查看source code of the grid-list并在<mat-grid-tile>
上设置一个断点,确认了这一点,在此方法中_layoutTiles()
为空。
我的猜测是,角度this._tiles
-注释(here)在第一个代码段中找不到平铺子对象,因为它仅适用于DOM的第一层,而我们只有第一层ContentChildren
。
期望的结果很明确,我希望能够使用自定义的网格列表组件,为其添加一些子代并使用其功能。但是出于某种原因,angular不想让我成功,或者我仍然有很多东西要学习。
我正在使用angular 6.1,并使用official docs安装了材料组件。
答案 0 :(得分:1)
mat-grid-list在其自己的实现中使用内容投影,因此它需要能够查询其投影内容。尝试添加另一级别的内容投影将使这不可能,因为mat-grid-tile并不是实际上由列表而是由组件投影的。
答案很简短:这行不通。
可能有一种方法可以实现您的目标,但内容投影却不是。如果您能澄清您的意图,我可能会提供帮助。您仍然需要使用模板。
这是简单的情况:在mat-grid-list周围编写包装器,该包装器接受数据数组作为输入,您可以使用ngFor进行迭代以创建图块
@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周围提供了可重用的包装,为您摘要了一下。但是,如果网格内容比字符串复杂(可能)或在每次使用时都需要自定义模板,那么这样做就不好了。在这种情况下,您需要使用模板和指令的更为精细的方法:
@Directive({
selector: 'gridTemplate'
})
export class GridTemplate {
@Input() key: string;
constructor(private elementRef: ElementRef, public template: TemplateRef<any>) {}
}
此指令将标识您的自定义模板,然后在网格列表中,您可以使用这些模板来填充图块
@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>
然后您对组件的用法如下:
@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添加任何可重用的逻辑,但仍保持向网格提供自定义模板的灵活性。缺点是您必须采取额外的步骤来构造数据以利用这种方法。