Skip to content

Commit 3e1cff0

Browse files
crisbetovivian-hu-zz
authored andcommitted
fix(grid-list): incorrectly laying out tiles for nested list (#13086)
Fixes the grid list picking up the tiles of other nested grid lists, causing them to not being laid out correctly. Fixes #13074.
1 parent 3c55caa commit 3e1cff0

File tree

5 files changed

+72
-10
lines changed

5 files changed

+72
-10
lines changed

src/lib/grid-list/grid-list-base.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import {InjectionToken} from '@angular/core';
10+
11+
/**
12+
* Injection token used to provide a grid list to a tile and to avoid circular imports.
13+
* @docs-private
14+
*/
15+
export const MAT_GRID_LIST = new InjectionToken<MatGridListBase>('MAT_GRID_LIST');
16+
17+
/**
18+
* Base interface for a `MatGridList`.
19+
* @docs-private
20+
*/
21+
export interface MatGridListBase {
22+
cols: number;
23+
gutterSize: string;
24+
rowHeight: number | string;
25+
}

src/lib/grid-list/grid-list.spec.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,18 @@ describe('MatGridList', () => {
139139
expect(getStyle(tiles[2], 'top')).toBe('101px');
140140
});
141141

142+
it('should lay out the tiles correctly for a nested grid list', () => {
143+
const fixture = createComponent(NestedGridList);
144+
fixture.detectChanges();
145+
146+
const innerTiles = fixture.debugElement.queryAll(
147+
By.css('mat-grid-tile mat-grid-list mat-grid-tile'));
148+
149+
expect(getStyle(innerTiles[0], 'top')).toBe('0px');
150+
expect(getStyle(innerTiles[1], 'top')).toBe('101px');
151+
expect(getStyle(innerTiles[2], 'top')).toBe('202px');
152+
});
153+
142154
it('should set the gutter size if passed', () => {
143155
const fixture = createComponent(GridListWithGutterSize);
144156
fixture.detectChanges();
@@ -635,3 +647,19 @@ class GridListWithRtl { }
635647
`
636648
})
637649
class GridListWithIndirectTileDescendants {}
650+
651+
652+
@Component({template: `
653+
<div style="width:200px">
654+
<mat-grid-list cols="2" rowHeight="100px">
655+
<mat-grid-tile></mat-grid-tile>
656+
<mat-grid-tile>
657+
<mat-grid-list cols="1" rowHeight="100px">
658+
<mat-grid-tile></mat-grid-tile>
659+
<mat-grid-tile></mat-grid-tile>
660+
<mat-grid-tile></mat-grid-tile>
661+
</mat-grid-list>
662+
</mat-grid-tile>
663+
</mat-grid-list>
664+
</div>`})
665+
class NestedGridList { }

src/lib/grid-list/grid-list.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import {TileCoordinator} from './tile-coordinator';
2323
import {TileStyler, FitTileStyler, RatioTileStyler, FixedTileStyler} from './tile-styler';
2424
import {Directionality} from '@angular/cdk/bidi';
2525
import {coerceNumberProperty} from '@angular/cdk/coercion';
26+
import {MAT_GRID_LIST, MatGridListBase} from './grid-list-base';
2627

2728

2829
// TODO(kara): Conditional (responsive) column count / row size.
@@ -40,10 +41,14 @@ const MAT_FIT_MODE = 'fit';
4041
host: {
4142
'class': 'mat-grid-list',
4243
},
44+
providers: [{
45+
provide: MAT_GRID_LIST,
46+
useExisting: MatGridList
47+
}],
4348
changeDetection: ChangeDetectionStrategy.OnPush,
4449
encapsulation: ViewEncapsulation.None,
4550
})
46-
export class MatGridList implements OnInit, AfterContentChecked {
51+
export class MatGridList implements MatGridListBase, OnInit, AfterContentChecked {
4752
/** Number of columns being rendered. */
4853
private _cols: number;
4954

@@ -139,16 +144,18 @@ export class MatGridList implements OnInit, AfterContentChecked {
139144
/** Computes and applies the size and position for all children grid tiles. */
140145
private _layoutTiles(): void {
141146
if (!this._tileCoordinator) {
142-
this._tileCoordinator = new TileCoordinator(this._tiles);
147+
this._tileCoordinator = new TileCoordinator();
143148
}
144149

150+
145151
const tracker = this._tileCoordinator;
152+
const tiles = this._tiles.filter(tile => !tile._gridList || tile._gridList === this);
146153
const direction = this._dir ? this._dir.value : 'ltr';
147154

148-
this._tileCoordinator.update(this.cols);
155+
this._tileCoordinator.update(this.cols, tiles);
149156
this._tileStyler.init(this.gutterSize, tracker, this.cols, direction);
150157

151-
this._tiles.forEach((tile, index) => {
158+
tiles.forEach((tile, index) => {
152159
const pos = tracker.positions[index];
153160
this._tileStyler.setStyle(tile, pos.row, pos.col);
154161
});

src/lib/grid-list/grid-tile.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,17 @@ import {
1111
ViewEncapsulation,
1212
ElementRef,
1313
Input,
14+
Optional,
1415
ContentChildren,
1516
QueryList,
1617
AfterContentInit,
1718
Directive,
1819
ChangeDetectionStrategy,
20+
Inject,
1921
} from '@angular/core';
2022
import {MatLine, MatLineSetter} from '@angular/material/core';
2123
import {coerceNumberProperty} from '@angular/cdk/coercion';
24+
import {MAT_GRID_LIST, MatGridListBase} from './grid-list-base';
2225

2326
@Component({
2427
moduleId: module.id,
@@ -36,7 +39,9 @@ export class MatGridTile {
3639
_rowspan: number = 1;
3740
_colspan: number = 1;
3841

39-
constructor(private _element: ElementRef<HTMLElement>) {}
42+
constructor(
43+
private _element: ElementRef<HTMLElement>,
44+
@Optional() @Inject(MAT_GRID_LIST) public _gridList?: MatGridListBase) {}
4045

4146
/** Amount of rows that the grid tile takes up. */
4247
@Input()

src/lib/grid-list/tile-coordinator.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import {QueryList} from '@angular/core';
109
import {MatGridTile} from './grid-tile';
1110

1211
/**
@@ -53,19 +52,17 @@ export class TileCoordinator {
5352
/** The computed (row, col) position of each tile (the output). */
5453
positions: TilePosition[];
5554

56-
constructor(private _tiles: QueryList<MatGridTile>) {}
57-
5855
/**
5956
* Updates the tile positions.
6057
* @param numColumns Amount of columns in the grid.
6158
*/
62-
update(numColumns: number) {
59+
update(numColumns: number, tiles: MatGridTile[]) {
6360
this.columnIndex = 0;
6461
this.rowIndex = 0;
6562

6663
this.tracker = new Array(numColumns);
6764
this.tracker.fill(0, 0, this.tracker.length);
68-
this.positions = this._tiles.map(tile => this._trackTile(tile));
65+
this.positions = tiles.map(tile => this._trackTile(tile));
6966
}
7067

7168
/** Calculates the row and col position of a tile. */

0 commit comments

Comments
 (0)