Permalink
Comparing changes
Open a pull request
- 3 commits
- 5 files changed
- 0 commit comments
- 1 contributor
Commits on Dec 22, 2014
The uiGridRow directive will now watch the row's compiledElementFn property. If it changes the grid will recompile the element and swap it out. This appears to function pretty darn quickly during vertical scrolling. Also added unit tests to cover swapping templates using rows processors.
Bindings were being attached to the uiGridRow scope but never removed because the scope was not being destroyed even though child elements were being added. This was fixed by creating new scopes for uiGridRow when compiled/re-compiled. Also, added an element-based `$destroy` handler for ui-grid-cell. It already had one for the $scope.
Unified
Split
Showing
with
177 additions
and 8 deletions.
- +1 −1 misc/demo/grid-directive.html
- +1 −1 src/js/core/directives/ui-grid-cell.js
- +33 −5 src/js/core/directives/ui-grid-row.js
- +45 −1 src/js/core/services/gridClassFactory.js
- +97 −0 test/unit/core/directives/ui-grid-row.spec.js
| @@ -35,7 +35,7 @@ | ||
|
|
||
| <!-- <div class="row main"> --> | ||
| <h2>Grid</h2> | ||
| <div ui-grid="gridOptions" class="grid" ui-grid-pinning ui-grid-resize-columns></div> | ||
| <div ui-grid="gridOptions" class="grid" ui-grid-resize-columns></div> | ||
| <!-- <div class="placeholder"> --> | ||
| <!-- </div> --> | ||
|
|
||
| @@ -87,8 +87,8 @@ angular.module('ui.grid').directive('uiGridCell', ['$compile', '$parse', 'gridUt | ||
| rowWatchDereg(); | ||
| }; | ||
|
|
||
|
|
||
| $scope.$on( '$destroy', deregisterFunction ); | ||
| $elm.on( '$destroy', deregisterFunction ); | ||
| } | ||
| }; | ||
| } | ||
| @@ -23,18 +23,46 @@ | ||
| $scope.grid = uiGridCtrl.grid; | ||
| $scope.colContainer = containerCtrl.colContainer; | ||
|
|
||
| grid.getRowTemplateFn.then(function (templateFn) { | ||
| templateFn($scope, function(clonedElement, scope) { | ||
| $elm.replaceWith(clonedElement); | ||
| // Function for attaching the template to this scope | ||
| var clonedElement, cloneScope; | ||
| function compileTemplate() { | ||
| var compiledElementFn = $scope.row.compiledElementFn; | ||
|
|
||
| // Create a new scope for the contents of this row, so we can destroy it later if need be | ||
| var newScope = $scope.$new(); | ||
|
|
||
| compiledElementFn(newScope, function (newElm, scope) { | ||
| // If we already have a cloned element, we need to remove it and destroy its scope | ||
| if (clonedElement) { | ||
| clonedElement.remove(); | ||
| cloneScope.$destroy(); | ||
| } | ||
|
|
||
| // Empty the row and append the new element | ||
| $elm.empty().append(newElm); | ||
|
|
||
| // Save the new cloned element and scope | ||
| clonedElement = newElm; | ||
| cloneScope = newScope; | ||
| }); | ||
| } | ||
|
|
||
| // Initially attach the compiled template to this scope | ||
| compileTemplate(); | ||
|
|
||
| // If the row's compiled element function changes, we need to replace this element's contents with the new compiled template | ||
| $scope.$watch('row.compiledElementFn', function (newFunc, oldFunc) { | ||
| if (newFunc !== oldFunc) { | ||
| compileTemplate(); | ||
| } | ||
| }); | ||
| }, | ||
| post: function($scope, $elm, $attrs, controllers) { | ||
| var uiGridCtrl = controllers[0]; | ||
| var containerCtrl = controllers[1]; | ||
|
|
||
| //add optional reference to externalScopes function to scope | ||
| //so it can be retrieved in lower elements | ||
| // Sdd optional reference to externalScopes function to scope | ||
| // so it can be retrieved in lower elements | ||
| $scope.getExternalScopes = uiGridCtrl.getExternalScopes; | ||
| } | ||
| }; | ||
| @@ -43,6 +43,9 @@ | ||
|
|
||
| grid.registerColumnBuilder(service.defaultColumnBuilder); | ||
|
|
||
| // Row builder for custom row templates | ||
| grid.registerRowBuilder(service.rowTemplateAssigner); | ||
|
|
||
| // Reset all rows to visible initially | ||
| grid.registerRowsProcessor(function allRowsVisible(rows) { | ||
| rows.forEach(function (row) { | ||
| @@ -179,8 +182,49 @@ | ||
| col.compiledElementFnDefer = $q.defer(); | ||
|
|
||
| return $q.all(templateGetPromises); | ||
| } | ||
| }, | ||
|
|
||
| rowTemplateAssigner: function rowTemplateAssigner(row) { | ||
| var grid = this; | ||
|
|
||
| // Row has no template assigned to it | ||
| if (!row.rowTemplate) { | ||
| // Use the default row template from the grid | ||
| row.rowTemplate = grid.options.rowTemplate; | ||
|
|
||
| // Use the grid's function for fetching the compiled row template function | ||
| row.getRowTemplateFn = grid.getRowTemplateFn; | ||
|
|
||
| // Get the compiled row template function... | ||
| grid.getRowTemplateFn.then(function (rowTemplateFn) { | ||
| // And assign it to the row | ||
| row.compiledElementFn = rowTemplateFn; | ||
| }); | ||
| } | ||
| // Row has its own template assigned | ||
| else { | ||
| // Create a promise for the compiled row template function | ||
| var perRowTemplateFnPromise = $q.defer(); | ||
| row.getRowTemplateFn = perRowTemplateFnPromise.promise; | ||
|
|
||
| // Get the row template | ||
| gridUtil.getTemplate(row.rowTemplate) | ||
| .then(function (template) { | ||
| // Compile the template | ||
| var rowTemplateFn = $compile(template); | ||
|
|
||
| // Assign the compiled template function to this row | ||
| row.compiledElementFn = rowTemplateFn; | ||
|
|
||
| // Resolve the compiled template function promise | ||
| perRowTemplateFnPromise.resolve(rowTemplateFn); | ||
| }, | ||
| function (res) { | ||
| // Todo handle response error here? | ||
| throw new Error("Couldn't fetch/use row template '" + row.rowTemplate + "'"); | ||
| }); | ||
| } | ||
| } | ||
| }; | ||
|
|
||
| //class definitions (moved to separate factories) | ||
| @@ -0,0 +1,97 @@ | ||
| ddescribe('uiGridRow', function () { | ||
| var grid, data, columnDefs, $scope, $compile, $document, recompile, uiGridConstants, GridRow, gridUtil; | ||
|
|
||
| data = [ | ||
| { "name": "Bob", "age": 35 }, | ||
| { "name": "Bill", "age": 25 }, | ||
| { "name": "Sam", "age": 17 }, | ||
| { "name": "Jane", "age": 19 } | ||
| ]; | ||
|
|
||
| columnDefs = [ | ||
| { name: 'name' }, | ||
| { name: 'age' } | ||
| ]; | ||
|
|
||
| beforeEach(module('ui.grid')); | ||
|
|
||
| beforeEach(inject(function (_$compile_, $rootScope, _$document_, _uiGridConstants_, _GridRow_, _gridUtil_) { | ||
| $scope = $rootScope; | ||
| $compile = _$compile_; | ||
| $document = _$document_; | ||
| uiGridConstants = _uiGridConstants_; | ||
| GridRow = _GridRow_; | ||
| gridUtil = _gridUtil_; | ||
|
|
||
| $scope.gridOpts = { | ||
| columnDefs: columnDefs, | ||
| data: data, | ||
| onRegisterApi: function( gridApi ){ $scope.gridApi = gridApi; } | ||
| }; | ||
|
|
||
| $scope.extScope = 'test'; | ||
|
|
||
| recompile = function () { | ||
| grid = angular.element('<div style="width: 500px; height: 300px" ui-grid="gridOpts"></div>'); | ||
|
|
||
| $compile(grid)($scope); | ||
|
|
||
| $scope.$digest(); | ||
| }; | ||
|
|
||
| recompile(); | ||
| })); | ||
|
|
||
| describe('with different row templates', function () { | ||
| beforeEach(inject(function($templateCache) { | ||
| $templateCache.put('customRowTemplate', '<div><div>The name is: {{ row.entity.name }}</div></div>'); | ||
|
|
||
| $scope.gridApi.grid.registerRowsProcessor(function alterTemplates(rows, cols) { | ||
| var grid = this; | ||
|
|
||
| rows.forEach(function (row) { | ||
| if (row.entity.name === 'Sam') { | ||
| row.rowTemplate = 'customRowTemplate'; | ||
| gridUtil.getTemplate(row.rowTemplate) | ||
| .then(function (template) { | ||
| row.compiledElementFn = $compile(template); | ||
| }); | ||
| } | ||
| }); | ||
|
|
||
| return rows; | ||
| }); | ||
|
|
||
| $scope.gridApi.grid.refresh(); | ||
| $scope.$digest(); | ||
| })); | ||
|
|
||
| it('should allow rows to compile with different templates', function() { | ||
| // The third row in the template should have a different template | ||
| var thirdRow = $(grid).find('.ui-grid-row:nth-child(3)'); | ||
|
|
||
| expect(thirdRow.text()).toEqual('The name is: Sam'); | ||
| }); | ||
|
|
||
| it('should change templates properly after a sort', function () { | ||
| var refreshed = false; | ||
| runs(function () { | ||
| $scope.gridApi.grid.sortColumn($scope.gridApi.grid.columns[0], uiGridConstants.ASC) | ||
| .then(function () { | ||
| $scope.gridApi.grid.refresh(); | ||
| refreshed = true; | ||
| }); | ||
|
|
||
| $scope.$digest(); | ||
| }); | ||
|
|
||
| waitsFor(function () { return refreshed; }, 10000); | ||
|
|
||
| runs(function () { | ||
| var fourthRow = $(grid).find('.ui-grid-row:nth-child(4)'); | ||
|
|
||
| expect(fourthRow.text()).toEqual('The name is: Sam'); | ||
| }); | ||
| }); | ||
| }); | ||
| }); |