Skip to content

Commit

Permalink
Merge pull request Addepar#39 from li-qiang/refactor-grouped-row-chil…
Browse files Browse the repository at this point in the history
…dren-loading

Can lazily load grouping-row and its children
  • Loading branch information
li-qiang committed Jun 26, 2015
2 parents 6b87e75 + 2f0ed8c commit 0124875
Show file tree
Hide file tree
Showing 4 changed files with 157 additions and 18 deletions.
37 changes: 21 additions & 16 deletions addon/controllers/grouped-row-array.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export default RowArrayController.extend({

init: function() {
this._super();
this.set('_childrenRows', Ember.Map.create());
this.set('_expandedGroupRowToChildrenMap', Ember.Map.create());
this.set('_controllersMap', Ember.Map.create());
},

Expand All @@ -17,31 +17,36 @@ export default RowArrayController.extend({
var controller = controllersMap.get(object);
if (!controller) {
controller = this.get('itemController').create({
target: this,
parentController: this.get('parentController') || this,
content: object,
expandLevel: expandLevel,
parentContent: target.parent
target: this,
parentController: this.get('parentController') || this,
content: object,
expandLevel: expandLevel,
parentContent: target.parent
});
controllersMap.set(object, controller);
}
return controller;
},

expandChildren: function(row) {
var childrenRow = row.get('children');
row.addObserver('children.length', this, 'lengthDidChange');
row.set('isExpanded', true);
var childrenRow = row.get('children') || [];
if (this.arrayLength(childrenRow) > 0) {
var childrenRows = this.get('_childrenRows');
var childrenRows = this.get('_expandedGroupRowToChildrenMap');
childrenRows.set(row.get('content'), childrenRow);
this.toggleProperty('_resetLength');
this.toggleProperty('_forceContentLengthRecalc');
var expandLevelAfterExpand = this.maxExpandedDepthAfterExpand(row);
if (expandLevelAfterExpand > this.get('_expandedDepth')) {
this.set('_expandedDepth', expandLevelAfterExpand);
}
}
},

lengthDidChange: function() {
this.toggleProperty('_forceContentLengthRecalc');
},

maxExpandedDepthAfterExpand: function maxExpandedDepthAfterExpand(row) {
var childrenRow = row.get('children') || [];
var expandedChildrenLevel = row.get('expandLevel') + 1;
Expand All @@ -62,9 +67,9 @@ export default RowArrayController.extend({
row.set('isExpanded', false);
var childrenRow = row.get('children') || [];
if (this.arrayLength(childrenRow) > 0) {
var childrenRows = this.get('_childrenRows');
var childrenRows = this.get('_expandedGroupRowToChildrenMap');
childrenRows.delete(row.get('content'));
this.toggleProperty('_resetLength');
this.toggleProperty('_forceContentLengthRecalc');
this.set('_expandedDepth', this.maxExpandedDepthAfterCollapse());
}
},
Expand All @@ -80,7 +85,7 @@ export default RowArrayController.extend({
var childrenLength = value.get('children.length');
return prev + childrenLength;
}, 0) + this.get('content.length');
}).property('content.[]', '_resetLength'),
}).property('content.[]', '_forceContentLengthRecalc'),

traverseExpandedControllers: function traverseExpandedControllers(visit, init) {
var controllersMap = this.get('_controllersMap');
Expand Down Expand Up @@ -114,7 +119,7 @@ export default RowArrayController.extend({
var theLevel;
var theParent;
var visitCount = 0;
var childrenRows = this.get('_childrenRows');
var childrenRows = this.get('_expandedGroupRowToChildrenMap');
this.depthFirstTraverse(root, function(child, parent, level) {
if (visitCount === idx) {
theObject = child;
Expand Down Expand Up @@ -147,7 +152,7 @@ export default RowArrayController.extend({
var theLevel = 0;
var theParent = null;

var childrenRows = this.get('_childrenRows');
var childrenRows = this.get('_expandedGroupRowToChildrenMap');

while (childrenRows.has(theObject)) {
var children = childrenRows.get(theObject);
Expand Down Expand Up @@ -197,9 +202,9 @@ export default RowArrayController.extend({
return 0;
},

_resetLength: false,
_forceContentLengthRecalc: false,

_childrenRows: null,
_expandedGroupRowToChildrenMap: null,

//map between row content and row controller
_controllersMap: null,
Expand Down
32 changes: 32 additions & 0 deletions addon/models/grouping-row-proxy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import Ember from 'ember';
import LazyGroupRowArray from './lazy-group-row-array';

export default Ember.ObjectProxy.extend({

loadChildren: Ember.K,

groupingMetadata: null,

groupingLevel: 0,

groupingName: Ember.computed(function () {
return Ember.get(this.get('groupingMetadata').objectAt(this.get('groupingLevel')), 'id');
}).property('groupingMetadata', 'groupingLevel'),

selfQuery: Ember.computed(function () {
var query = {};
var groupingName = this.get('groupingName');
query[groupingName] = this.get('content.id');
return Ember.setProperties(query, this.get('parentQuery') || {});
}).property('content'),

children: Ember.computed(function () {
var lazyArray = LazyGroupRowArray.create({
loadChildren: this.loadChildren,
groupingLevel: this.get('groupingLevel') + 1,
groupingMetadata: this.get('groupingMetadata'),
parentQuery: this.get('selfQuery')
});
return lazyArray;
}).property()
});
102 changes: 102 additions & 0 deletions addon/models/lazy-group-row-array.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import Ember from 'ember';
import GroupingRowProxy from './grouping-row-proxy';

export default Ember.ArrayProxy.extend({
loadChildren: Ember.K,
groupingLevel: 0,
groupingMetadata: null,
parentQuery: {},

init: function () {
this.set('content', Ember.A());
this._super();
this.addLoadingPlaceHolder();
},

loadOneChunk: function(chunkIndex) {
return this.loadChildren(chunkIndex, this.get('parentQuery') || {});
},
wrapLoadedContent: function (row) {
if (this.get('isGroupingRow')) {
var groupingMetadata = this.get('groupingMetadata');
return GroupingRowProxy.create({
groupingMetadata: groupingMetadata,
groupingLevel: this.get('groupingLevel'),
content: row,
loadChildren: this.loadChildren,
parentQuery: this.get('parentQuery')
});
} else {
return row;
}
},

/*---------------Override ArrayProxy -----------------------*/
objectAtContent: function (index) {
var object = this._super(index);
if (object.get('isLoading') && !this.get('_hasInProgressLoading')) {
this.triggerLoading(index);
}
return object;
},

/*---------------Private methods -----------------------*/
isGroupingRow: Ember.computed(function() {
return this.get('groupingLevel') < this.get('groupingMetadata.length');
}).property('groupingMetadata.[]', 'groupingLevel'),

triggerLoading: function (index) {
this.set('_hasInProgressLoading', true);
var chunkIndex = this.chunkIndex(index);
var self = this;
this.loadOneChunk(chunkIndex).then(function (result) {
self.onOneChunkLoaded(result);
self.set('_hasInProgressLoading', false);
});
},

chunkIndex: function (index) {
var chunkSize = this.get('chunkSize');
if (!chunkSize) {
return 0;
}
return Math.floor(index / chunkSize);
},

onOneChunkLoaded: function (result) {
this.setProperties(result.meta);
var chunk = result.content;
if (chunk.get('length') > 0) {
this.updatePlaceHolderWithContent(this.wrapLoadedContent(chunk.get('firstObject')));
var self = this;
var chunkObjects = chunk.slice(1).map(function (x) {
return Ember.ObjectProxy.create({"isLoaded": true, "isError": false, "content": self.wrapLoadedContent(x)});
});
this.pushObjects(chunkObjects);
if (this.get('length') < this.get('totalCount')) {
this.addLoadingPlaceHolder();
}
} else {
this.removeObject(this.get('lastObject'));
}
},

addLoadingPlaceHolder: function () {
this.pushObject(Ember.ObjectProxy.create({"isLoading": true, "isLoaded": false}));
},

updatePlaceHolderWithContent: function (content) {
var lastObject = this.get('lastObject');
lastObject.setProperties({
'content': content,
'isLoading': false,
'isLoaded': true
});
},

totalCount: null,

chunkSize: null,

_hasInProgressLoading: false
});
4 changes: 2 additions & 2 deletions addon/views/grouped-row-indicator.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ export default Ember.View.extend({
row: Ember.computed.alias('parentView.row'),

isShown: Ember.computed(function(){
return this.get('hasChildren') || this.get('row.hasLoadedChildren') === false;
}).property('hasChildren', 'row.hasLoadedChildren'),
return this.get('hasChildren');
}).property('hasChildren'),

expandLevel: 0,

Expand Down

0 comments on commit 0124875

Please sign in to comment.