diff --git a/misc/demo/grid-directive.html b/misc/demo/grid-directive.html index dac49a0733..5331e2e3d7 100644 --- a/misc/demo/grid-directive.html +++ b/misc/demo/grid-directive.html @@ -35,7 +35,7 @@

Grid

-
+
diff --git a/src/js/core/directives/ui-grid-row.js b/src/js/core/directives/ui-grid-row.js index c513668a18..3efd036b98 100644 --- a/src/js/core/directives/ui-grid-row.js +++ b/src/js/core/directives/ui-grid-row.js @@ -23,10 +23,25 @@ $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 + function compileTemplate() { + var compiledElementFn = $scope.row.compiledElementFn; + + compiledElementFn($scope, function (clonedElement, scope) { + $elm.empty().append(clonedElement); }); + } + + // 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) { + newFunc($scope, function (clonedElement, scope) { + $elm.empty().append(clonedElement); + }); + } }); }, post: function($scope, $elm, $attrs, controllers) { diff --git a/src/js/core/services/gridClassFactory.js b/src/js/core/services/gridClassFactory.js index 887e6577ef..a48227cddd 100644 --- a/src/js/core/services/gridClassFactory.js +++ b/src/js/core/services/gridClassFactory.js @@ -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) diff --git a/test/unit/core/directives/ui-grid-row.spec.js b/test/unit/core/directives/ui-grid-row.spec.js new file mode 100644 index 0000000000..e0eba78515 --- /dev/null +++ b/test/unit/core/directives/ui-grid-row.spec.js @@ -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('
'); + + $compile(grid)($scope); + + $scope.$digest(); + }; + + recompile(); + })); + + describe('with different row templates', function () { + beforeEach(inject(function($templateCache) { + $templateCache.put('customRowTemplate', '
The name is: {{ row.entity.name }}
'); + + $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'); + }); + }); + }); +}); \ No newline at end of file