diff --git a/src/lib/grid-list/grid-list.spec.ts b/src/lib/grid-list/grid-list.spec.ts index 6f556b40bbcc..048d430d8545 100644 --- a/src/lib/grid-list/grid-list.spec.ts +++ b/src/lib/grid-list/grid-list.spec.ts @@ -64,13 +64,13 @@ describe('MdGridList', () => { it('should use a ratio row height if passed in', () => { let fixture = TestBed.createComponent(GirdListWithRowHeightRatio); - fixture.componentInstance.heightRatio = '4:1'; + fixture.componentInstance.rowHeight = '4:1'; fixture.detectChanges(); let tile = fixture.debugElement.query(By.directive(MdGridTile)); expect(getStyle(tile, 'padding-top')).toBe('100px'); - fixture.componentInstance.heightRatio = '2:1'; + fixture.componentInstance.rowHeight = '2:1'; fixture.detectChanges(); expect(getStyle(tile, 'padding-top')).toBe('200px'); @@ -257,7 +257,7 @@ describe('MdGridList', () => { it('should not use calc() that evaluates to 0', () => { const fixture = TestBed.createComponent(GirdListWithRowHeightRatio); - fixture.componentInstance.heightRatio = '4:1'; + fixture.componentInstance.rowHeight = '4:1'; fixture.detectChanges(); const firstTile = fixture.debugElement.query(By.directive(MdGridTile)).nativeElement; @@ -265,6 +265,28 @@ describe('MdGridList', () => { expect(firstTile.style.marginTop).toBe('0px'); expect(firstTile.style.left).toBe('0px'); }); + + it('should reset the old styles when switching to a new tile styler', () => { + const fixture = TestBed.createComponent(GirdListWithRowHeightRatio); + + fixture.componentInstance.rowHeight = '4:1'; + fixture.detectChanges(); + + const list = fixture.debugElement.query(By.directive(MdGridList)); + const tile = fixture.debugElement.query(By.directive(MdGridTile)); + + expect(getStyle(tile, 'padding-top')).toBe('100px'); + expect(getStyle(list, 'padding-bottom')).toBe('100px'); + + fixture.componentInstance.rowHeight = '400px'; + fixture.detectChanges(); + + expect(getStyle(tile, 'padding-top')).toBe('0px', 'Expected tile padding to be reset.'); + expect(getStyle(list, 'padding-bottom')).toBe('0px', 'Expected list padding to be reset.'); + expect(getStyle(tile, 'top')).toBe('0px'); + expect(getStyle(tile, 'height')).toBe('400px'); + }); + }); @@ -306,12 +328,12 @@ class GridListWithUnspecifiedRowHeight { } @Component({template: `
- +
`}) class GirdListWithRowHeightRatio { - heightRatio: string; + rowHeight: string; } @Component({template: ` diff --git a/src/lib/grid-list/grid-list.ts b/src/lib/grid-list/grid-list.ts index 20cc6befd653..5a5581995835 100644 --- a/src/lib/grid-list/grid-list.ts +++ b/src/lib/grid-list/grid-list.ts @@ -85,8 +85,12 @@ export class MdGridList implements OnInit, AfterContentChecked { /** Set internal representation of row height from the user-provided value. */ @Input() set rowHeight(value: string | number) { - this._rowHeight = coerceToString(value); - this._setTileStyler(); + const newValue = coerceToString(value); + + if (newValue !== this._rowHeight) { + this._rowHeight = newValue; + this._setTileStyler(this._rowHeight); + } } ngOnInit() { @@ -106,36 +110,40 @@ export class MdGridList implements OnInit, AfterContentChecked { private _checkCols() { if (!this.cols) { throw Error(`md-grid-list: must pass in number of columns. ` + - `Example: `); + `Example: `); } } /** Default to equal width:height if rowHeight property is missing */ private _checkRowHeight(): void { if (!this._rowHeight) { - this._tileStyler = new RatioTileStyler('1:1'); + this._setTileStyler('1:1'); } } /** Creates correct Tile Styler subtype based on rowHeight passed in by user */ - private _setTileStyler(): void { - if (this._rowHeight === MD_FIT_MODE) { + private _setTileStyler(rowHeight: string): void { + if (this._tileStyler) { + this._tileStyler.reset(this); + } + + if (rowHeight === MD_FIT_MODE) { this._tileStyler = new FitTileStyler(); - } else if (this._rowHeight && this._rowHeight.indexOf(':') > -1) { - this._tileStyler = new RatioTileStyler(this._rowHeight); + } else if (rowHeight && rowHeight.indexOf(':') > -1) { + this._tileStyler = new RatioTileStyler(rowHeight); } else { - this._tileStyler = new FixedTileStyler(this._rowHeight); + this._tileStyler = new FixedTileStyler(rowHeight); } } /** Computes and applies the size and position for all children grid tiles. */ private _layoutTiles(): void { - let tracker = new TileCoordinator(this.cols, this._tiles); - let direction = this._dir ? this._dir.value : 'ltr'; + const tracker = new TileCoordinator(this.cols, this._tiles); + const direction = this._dir ? this._dir.value : 'ltr'; this._tileStyler.init(this.gutterSize, tracker, this.cols, direction); this._tiles.forEach((tile, index) => { - let pos = tracker.positions[index]; + const pos = tracker.positions[index]; this._tileStyler.setStyle(tile, pos.row, pos.col); }); @@ -143,7 +151,7 @@ export class MdGridList implements OnInit, AfterContentChecked { } /** Sets style on the main grid-list element, given the style name and value. */ - _setListStyle(style: [string, string] | null): void { + _setListStyle(style: [string, string | null] | null): void { if (style) { this._renderer.setStyle(this._element.nativeElement, style[0], style[1]); } diff --git a/src/lib/grid-list/grid-tile.ts b/src/lib/grid-list/grid-tile.ts index 24a9dc21c78d..d2f57a9ef46a 100644 --- a/src/lib/grid-list/grid-tile.ts +++ b/src/lib/grid-list/grid-tile.ts @@ -52,7 +52,7 @@ export class MdGridTile { * Sets the style of the grid-tile element. Needs to be set manually to avoid * "Changed after checked" errors that would occur with HostBinding. */ - _setStyle(property: string, value: string): void { + _setStyle(property: string, value: any): void { this._renderer.setStyle(this._element.nativeElement, property, value); } } diff --git a/src/lib/grid-list/tile-styler.ts b/src/lib/grid-list/tile-styler.ts index 6c781e3c7e67..36a897e1d583 100644 --- a/src/lib/grid-list/tile-styler.ts +++ b/src/lib/grid-list/tile-styler.ts @@ -6,6 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ +import {MdGridList} from './grid-list'; import {MdGridTile} from './grid-tile'; import {TileCoordinator} from './tile-coordinator'; @@ -139,6 +140,13 @@ export abstract class TileStyler { * @docs-private */ getComputedHeight(): [string, string] | null { return null; } + + /** + * Called when the tile styler is swapped out with a different one. To be used for cleanup. + * @param list Grid list that the styler was attached to. + * @docs-private + */ + abstract reset(list: MdGridList); } @@ -166,6 +174,15 @@ export class FixedTileStyler extends TileStyler { 'height', calc(`${this.getTileSpan(this.fixedRowHeight)} + ${this.getGutterSpan()}`) ]; } + + reset(list: MdGridList) { + list._setListStyle(['height', null]); + + list._tiles.forEach(tile => { + tile._setStyle('top', null); + tile._setStyle('height', null); + }); + } } @@ -203,8 +220,17 @@ export class RatioTileStyler extends TileStyler { ]; } + reset(list: MdGridList) { + list._setListStyle(['padding-bottom', null]); + + list._tiles.forEach(tile => { + tile._setStyle('margin-top', null); + tile._setStyle('padding-top', null); + }); + } + private _parseRatio(value: string): void { - let ratioParts = value.split(':'); + const ratioParts = value.split(':'); if (ratioParts.length !== 2) { throw Error(`md-grid-list: invalid ratio given for row-height: "${value}"`); @@ -237,6 +263,12 @@ export class FitTileStyler extends TileStyler { tile._setStyle('height', calc(this.getTileSize(baseTileHeight, tile.rowspan))); } + reset(list: MdGridList) { + list._tiles.forEach(tile => { + tile._setStyle('top', null); + tile._setStyle('height', null); + }); + } }