Skip to content
This repository was archived by the owner on Sep 5, 2024. It is now read-only.

Commit 5d9142e

Browse files
Scott HyndmanThomasBurleson
authored andcommitted
fix(gridlist): Tile ordering improved
Fixes #2553, Fixes #2225, Closes #2568. * ng-repeated and static tiles can now be mixed * Ordering should work properly once and for all. There's no more state maintenance in the grid controller. Whenever the grid re-renders, the DOM is queried to determine the tiles involved
1 parent 95d1dd9 commit 5d9142e

1 file changed

Lines changed: 54 additions & 70 deletions

File tree

src/components/gridList/gridList.js

Lines changed: 54 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -155,45 +155,46 @@ function GridListDirective($interpolate, $mdConstant, $mdGridLayout, $mdMedia) {
155155
* Invokes the layout engine, and uses its results to lay out our
156156
* tile elements.
157157
*
158-
* @param {boolean} tilesAdded Whether tiles have been added since the last
159-
* layout. This is to avoid situations where tiles are replaced with
160-
* properties identical to their removed counterparts.
158+
* @param {boolean} tilesInvalidated Whether tiles have been
159+
* added/removed/moved since the last layout. This is to avoid situations
160+
* where tiles are replaced with properties identical to their removed
161+
* counterparts.
161162
*/
162-
function layoutDelegate(tilesAdded) {
163+
function layoutDelegate(tilesInvalidated) {
164+
var tiles = getTileElements();
163165
var props = {
164-
tileSpans: getTileSpans(),
166+
tileSpans: getTileSpans(tiles),
165167
colCount: getColumnCount(),
166168
rowMode: getRowMode(),
167169
rowHeight: getRowHeight(),
168170
gutter: getGutter()
169171
};
170172

171-
if (!tilesAdded && angular.equals(props, lastLayoutProps)) {
173+
if (!tilesInvalidated && angular.equals(props, lastLayoutProps)) {
172174
return;
173175
}
174176

175-
var tiles = getTileElements(),
176-
performance =
177-
$mdGridLayout(props.colCount, props.tileSpans, tiles)
178-
.map(function(tilePositions, rowCount) {
177+
var performance =
178+
$mdGridLayout(props.colCount, props.tileSpans, tiles)
179+
.map(function(tilePositions, rowCount) {
180+
return {
181+
grid: {
182+
element: element,
183+
style: getGridStyle(props.colCount, rowCount,
184+
props.gutter, props.rowMode, props.rowHeight)
185+
},
186+
tiles: tilePositions.map(function(ps, i) {
179187
return {
180-
grid: {
181-
element: element,
182-
style: getGridStyle(props.colCount, rowCount,
183-
props.gutter, props.rowMode, props.rowHeight)
184-
},
185-
tiles: tilePositions.map(function(ps, i) {
186-
return {
187-
element: angular.element(tiles[i]),
188-
style: getTileStyle(ps.position, ps.spans,
189-
props.colCount, props.rowCount,
190-
props.gutter, props.rowMode, props.rowHeight)
191-
}
192-
})
188+
element: angular.element(tiles[i]),
189+
style: getTileStyle(ps.position, ps.spans,
190+
props.colCount, props.rowCount,
191+
props.gutter, props.rowMode, props.rowHeight)
193192
}
194193
})
195-
.reflow()
196-
.performance();
194+
}
195+
})
196+
.reflow()
197+
.performance();
197198

198199
// Report layout
199200
scope.mdOnLayout({
@@ -345,20 +346,23 @@ function GridListDirective($interpolate, $mdConstant, $mdGridLayout, $mdMedia) {
345346
}
346347

347348
function getTileElements() {
348-
return ctrl.tiles.map(function(tile) { return tile.element });
349+
return [].filter.call(element.children(), function(ele) {
350+
return ele.tagName == 'MD-GRID-TILE';
351+
});
349352
}
350353

351354
/**
352355
* Gets an array of objects containing the rowspan and colspan for each tile.
353356
* @returns {Array<{row: number, col: number}>}
354357
*/
355-
function getTileSpans() {
356-
return ctrl.tiles.map(function(tile) {
358+
function getTileSpans(tileElements) {
359+
return [].map.call(tileElements, function(ele) {
360+
var ctrl = angular.element(ele).controller('mdGridTile');
357361
return {
358362
row: parseInt(
359-
$mdMedia.getResponsiveAttribute(tile.attrs, 'md-rowspan'), 10) || 1,
363+
$mdMedia.getResponsiveAttribute(ctrl.$attrs, 'md-rowspan'), 10) || 1,
360364
col: parseInt(
361-
$mdMedia.getResponsiveAttribute(tile.attrs, 'md-colspan'), 10) || 1
365+
$mdMedia.getResponsiveAttribute(ctrl.$attrs, 'md-colspan'), 10) || 1
362366
};
363367
});
364368
}
@@ -407,58 +411,33 @@ function GridListDirective($interpolate, $mdConstant, $mdGridLayout, $mdMedia) {
407411

408412
/* @ngInject */
409413
function GridListController($timeout) {
410-
this.invalidated = false;
411-
this.tilesAdded = false;
414+
this.layoutInvalidated = false;
415+
this.tilesInvalidated = false;
412416
this.$timeout_ = $timeout;
413-
this.tiles = [];
414417
this.layoutDelegate = angular.noop;
415418
}
416419

417420
GridListController.prototype = {
418-
addTile: function(tileElement, tileAttrs, idx) {
419-
var tile = { element: tileElement, attrs: tileAttrs };
420-
if (angular.isUndefined(idx)) {
421-
this.tiles.push(tile);
422-
} else {
423-
this.tiles.splice(idx, 0, tile);
424-
}
425-
this.tilesAdded = true;
426-
this.invalidateLayout();
427-
},
428-
429-
removeTile: function(tileElement, tileAttrs) {
430-
var idx = this._findTileIndex(tileAttrs);
431-
if (idx === -1) {
432-
return;
433-
}
434-
this.tiles.splice(idx, 1);
421+
invalidateTiles: function() {
422+
this.tilesInvalidated = true;
435423
this.invalidateLayout();
436424
},
437425

438426
invalidateLayout: function() {
439-
if (this.invalidated) {
427+
if (this.layoutInvalidated) {
440428
return;
441429
}
442-
this.invalidated = true;
430+
this.layoutInvalidated = true;
443431
this.$timeout_(angular.bind(this, this.layout));
444432
},
445433

446434
layout: function() {
447435
try {
448-
this.layoutDelegate(this.tilesAdded);
436+
this.layoutDelegate(this.tilesInvalidated);
449437
} finally {
450-
this.invalidated = false;
451-
this.tilesAdded = false;
438+
this.layoutInvalidated = false;
439+
this.tilesInvalidated = false;
452440
}
453-
},
454-
455-
_findTileIndex: function(tileAttrs) {
456-
for (var i = 0; i < this.tiles.length; i++) {
457-
if (this.tiles[i].attrs == tileAttrs) {
458-
return i;
459-
}
460-
}
461-
return -1;
462441
}
463442
};
464443

@@ -724,6 +703,10 @@ function GridTileDirective($mdMedia) {
724703
template: '<figure ng-transclude></figure>',
725704
transclude: true,
726705
scope: {},
706+
// Simple controller that exposes attributes to the grid directive
707+
controller: function($attrs) {
708+
this.$attrs = $attrs;
709+
},
727710
link: postLink
728711
};
729712

@@ -736,24 +719,25 @@ function GridTileDirective($mdMedia) {
736719
attrs, angular.bind(gridCtrl, gridCtrl.invalidateLayout));
737720

738721
// Tile registration/deregistration
739-
// TODO(shyndman): Kind of gross to access parent scope like this.
740-
// Consider other options.
741-
gridCtrl.addTile(element, attrs, scope.$parent.$index);
722+
gridCtrl.invalidateTiles();
742723
scope.$on('$destroy', function() {
743724
unwatchAttrs();
744-
gridCtrl.removeTile(element, attrs);
725+
gridCtrl.invalidateLayout();
745726
});
746727

747728
if (angular.isDefined(scope.$parent.$index)) {
748729
scope.$watch(function() { return scope.$parent.$index; },
749730
function indexChanged(newIdx, oldIdx) {
750-
gridCtrl.removeTile(element, attrs);
751-
gridCtrl.addTile(element, attrs, newIdx);
731+
if (newIdx === oldIdx) {
732+
return;
733+
}
734+
gridCtrl.invalidateTiles();
752735
});
753736
}
754737
}
755738
}
756739

740+
757741
function GridTileCaptionDirective() {
758742
return {
759743
template: '<figcaption ng-transclude></figcaption>',

0 commit comments

Comments
 (0)