Skip to content

Commit

Permalink
fix(core): Fixes URL-based template loading for header-cell, `foote…
Browse files Browse the repository at this point in the history
…r-cell`, `filter`.

Fixes issues #4744, #5717, #5115, #5196, #5712, #5260, #5196, #4851, #4514, #5601

For URL-based templates we need to be sure that content arrived before `$compile` and `$elm.append` call.
  • Loading branch information
falsyvalues authored and mportuga committed Oct 31, 2017
1 parent 85c3c90 commit f0b2fa7
Show file tree
Hide file tree
Showing 8 changed files with 183 additions and 22 deletions.
15 changes: 12 additions & 3 deletions src/js/core/directives/ui-grid-filter.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,19 @@
pre: function ($scope, $elm, $attrs, controllers) {
$scope.col.updateFilters = function( filterable ){
$elm.children().remove();
if ( filterable ){
if ( filterable ) {
var template = $scope.col.filterHeaderTemplate;

$elm.append($compile(template)($scope));
if (template === undefined && $scope.col.providedFilterHeaderTemplate !== '') {
if ($scope.col.filterHeaderTemplatePromise) {
$scope.col.filterHeaderTemplatePromise.then(function () {
template = $scope.col.filterHeaderTemplate;
$elm.append($compile(template)($scope));
});
}
}
else {
$elm.append($compile(template)($scope));
}
}
};

Expand Down
14 changes: 12 additions & 2 deletions src/js/core/directives/ui-grid-footer-cell.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,18 @@
compile: function compile(tElement, tAttrs, transclude) {
return {
pre: function ($scope, $elm, $attrs, uiGridCtrl) {
var cellFooter = $compile($scope.col.footerCellTemplate)($scope);
$elm.append(cellFooter);
var template = $scope.col.footerCellTemplate;
if (template === undefined && $scope.col.providedFooterCellTemplate !== '') {
if ($scope.col.footerCellTemplatePromise) {
$scope.col.footerCellTemplatePromise.then(function () {
template = $scope.col.footerCellTemplate;
$elm.append($compile(template)($scope));
});
}
}
else {
$elm.append($compile(template)($scope));
}
},
post: function ($scope, $elm, $attrs, uiGridCtrl) {
//$elm.addClass($scope.col.getColClass(false));
Expand Down
14 changes: 12 additions & 2 deletions src/js/core/directives/ui-grid-header-cell.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,18 @@
compile: function() {
return {
pre: function ($scope, $elm, $attrs) {
var cellHeader = $compile($scope.col.headerCellTemplate)($scope);
$elm.append(cellHeader);
var template = $scope.col.headerCellTemplate;
if (template === undefined && $scope.col.providedHeaderCellTemplate !== '') {
if ($scope.col.headerCellTemplatePromise) {
$scope.col.headerCellTemplatePromise.then(function () {
template = $scope.col.headerCellTemplate;
$elm.append($compile(template)($scope));
});
}
}
else {
$elm.append($compile(template)($scope));
}
},

post: function ($scope, $elm, $attrs, controllers) {
Expand Down
22 changes: 11 additions & 11 deletions src/js/core/services/gridClassFactory.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,9 @@
} else {
col[providedType] = colDef[templateType];
}
templateGetPromises.push(gridUtil.getTemplate(col[providedType])
.then(

var templatePromise = gridUtil.getTemplate(col[providedType])
.then(
function (template) {
if ( angular.isFunction(template) ) { template = template(); }
var tooltipCall = ( tooltipType === 'cellTooltip' ) ? 'col.cellTooltip(row,col)' : 'col.headerTooltip(col)';
Expand All @@ -119,9 +119,11 @@
},
function (res) {
throw new Error("Couldn't fetch/use colDef." + templateType + " '" + colDef[templateType] + "'");
}).catch(angular.noop)
);
}).catch(angular.noop);

templateGetPromises.push(templatePromise);

return templatePromise;
};


Expand All @@ -134,8 +136,7 @@
* must contain a div that can receive focus.
*
*/
processTemplate( 'cellTemplate', 'providedCellTemplate', 'ui-grid/uiGridCell', 'cellFilter', 'cellTooltip' );
col.cellTemplatePromise = templateGetPromises[0];
col.cellTemplatePromise = processTemplate( 'cellTemplate', 'providedCellTemplate', 'ui-grid/uiGridCell', 'cellFilter', 'cellTooltip' );

/**
* @ngdoc property
Expand All @@ -145,7 +146,7 @@
* is ui-grid/uiGridHeaderCell
*
*/
processTemplate( 'headerCellTemplate', 'providedHeaderCellTemplate', 'ui-grid/uiGridHeaderCell', 'headerCellFilter', 'headerTooltip' );
col.headerCellTemplatePromise = processTemplate( 'headerCellTemplate', 'providedHeaderCellTemplate', 'ui-grid/uiGridHeaderCell', 'headerCellFilter', 'headerTooltip' );

/**
* @ngdoc property
Expand All @@ -155,7 +156,7 @@
* is ui-grid/uiGridFooterCell
*
*/
processTemplate( 'footerCellTemplate', 'providedFooterCellTemplate', 'ui-grid/uiGridFooterCell', 'footerCellFilter' );
col.footerCellTemplatePromise = processTemplate( 'footerCellTemplate', 'providedFooterCellTemplate', 'ui-grid/uiGridFooterCell', 'footerCellFilter' );

/**
* @ngdoc property
Expand All @@ -164,14 +165,13 @@
* @description a custom template for the filter input. The default is ui-grid/ui-grid-filter
*
*/
processTemplate( 'filterHeaderTemplate', 'providedFilterHeaderTemplate', 'ui-grid/ui-grid-filter' );
col.filterHeaderTemplatePromise = processTemplate( 'filterHeaderTemplate', 'providedFilterHeaderTemplate', 'ui-grid/ui-grid-filter' );

// Create a promise for the compiled element function
col.compiledElementFnDefer = $q.defer();

return $q.all(templateGetPromises);
},


rowTemplateAssigner: function rowTemplateAssigner(row) {
var grid = this;
Expand Down
64 changes: 64 additions & 0 deletions test/unit/core/directives/ui-grid-filter.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
describe('uiGridFilter', function () {
var grid, recompile, $compile, $scope, $document, $httpBackend;

var data = [
{ 'name': 'Ethel Price', 'gender': 'female', 'company': 'Enersol' },
{ 'name': 'Claudine Neal', 'gender': 'female', 'company': 'Sealoud' },
{ 'name': 'Beryl Rice', 'gender': 'female', 'company': 'Velity' },
{ 'name': 'Wilder Gonzales', 'gender': 'male', 'company': 'Geekko' }
];

var columnDefs = [
{ name: 'name' },
{ name: 'gender' },
{ name: 'company' }
];

beforeEach(module('ui.grid'));

beforeEach(inject(function (_$compile_, $rootScope, _$document_, _$httpBackend_) {
$compile = _$compile_;
$scope = $rootScope;
$document = _$document_;
$httpBackend = _$httpBackend_;

$scope.gridOpts = {
columnDefs: columnDefs,
data: data
};

recompile = function () {
grid = angular.element('<div style="width: 500px; height: 300px" ui-grid="gridOpts"></div>');

$compile(grid)($scope);
$document[0].body.appendChild(grid[0]);

$scope.$digest();
};

recompile();
}));

afterEach(function() {
grid.remove();
});

describe('should handle a URL-based template defined in filterHeaderTemplate', function () {
it('should handle', function () {
var el, url = 'http://www.a-really-fake-url.com/filterHeaderTemplate.html';

$scope.gridOpts.enableFiltering = true;
$scope.gridOpts.columnDefs[0].filterHeaderTemplate = url;

$httpBackend.expectGET(url).respond('<div class="filterHeaderTemplate">filterHeaderTemplate content</div>');
recompile();

el = $(grid).find('.filterHeaderTemplate');
expect(el.text()).toEqual('');

$httpBackend.flush();
el = $(grid).find('.filterHeaderTemplate');
expect(el.text()).toEqual('filterHeaderTemplate content');
});
});
});
23 changes: 21 additions & 2 deletions test/unit/core/directives/ui-grid-footer-cell.spec.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
describe('uiGridFooterCell', function () {
var grid, data, columnDefs, $scope, $compile, $document, recompile, uiGridConstants;
var grid, data, columnDefs, $scope, $compile, $document, recompile, uiGridConstants, $httpBackend;

data = [
{ "name": "Bob", "age": 35 },
Expand All @@ -24,11 +24,12 @@ describe('uiGridFooterCell', function () {

beforeEach(module('ui.grid'));

beforeEach(inject(function (_$compile_, $rootScope, _$document_, _uiGridConstants_) {
beforeEach(inject(function (_$compile_, $rootScope, _$document_, _uiGridConstants_, _$httpBackend_) {
$scope = $rootScope;
$compile = _$compile_;
$document = _$document_;
uiGridConstants = _uiGridConstants_;
$httpBackend = _$httpBackend_;

$scope.gridOpts = {
showColumnFooter: true,
Expand Down Expand Up @@ -86,4 +87,22 @@ describe('uiGridFooterCell', function () {
expect(header.scope().grid.appScope.extScope).toBe('test');
});
});

describe('should handle a URL-based template defined in headerCellTemplate', function () {
it('should handle', function () {
var el, url = 'http://www.a-really-fake-url.com/footerCellTemplate.html';

$scope.gridOpts.columnDefs[0].footerCellTemplate = url;

$httpBackend.expectGET(url).respond('<div class="footerCellTemplate">footerCellTemplate content</div>');
recompile();

el = $(grid).find('.footerCellTemplate');
expect(el.text()).toEqual('');

$httpBackend.flush();
el = $(grid).find('.footerCellTemplate');
expect(el.text()).toEqual('footerCellTemplate content');
});
});
});
22 changes: 20 additions & 2 deletions test/unit/core/directives/ui-grid-header-cell.spec.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
describe('uiGridHeaderCell', function () {
var grid, $scope, $compile, $document, $timeout, $window, recompile, $animate, uiGridConstants, gridUtil, columnDefs;
var grid, $scope, $compile, $document, $timeout, $window, recompile, $animate, uiGridConstants, gridUtil, columnDefs, $httpBackend;

var downEvent, upEvent, clickEvent;

Expand All @@ -25,7 +25,7 @@ describe('uiGridHeaderCell', function () {

beforeEach(module('ui.grid'));

beforeEach(inject(function (_$compile_, $rootScope, _$document_, _$timeout_, _$window_, _$animate_, _uiGridConstants_, _gridUtil_) {
beforeEach(inject(function (_$compile_, $rootScope, _$document_, _$timeout_, _$window_, _$animate_, _uiGridConstants_, _gridUtil_, _$httpBackend_) {
$scope = $rootScope;
$compile = _$compile_;
$document = _$document_;
Expand All @@ -34,6 +34,7 @@ describe('uiGridHeaderCell', function () {
$animate = _$animate_;
uiGridConstants = _uiGridConstants_;
gridUtil = _gridUtil_;
$httpBackend = _$httpBackend_;

// Decide whether to use mouse or touch events based on which capabilities the browser has
if (gridUtil.isTouchEnabled()) {
Expand Down Expand Up @@ -199,4 +200,21 @@ describe('uiGridHeaderCell', function () {
});
});

describe('should handle a URL-based template defined in headerCellTemplate', function () {
it('should handle', function () {
var el, url = 'http://www.a-really-fake-url.com/headerCellTemplate.html';

$scope.gridOpts.columnDefs[0].headerCellTemplate = url;

$httpBackend.expectGET(url).respond('<div class="headerCellTemplate">headerCellTemplate content</div>');
recompile();

el = $(grid).find('.headerCellTemplate');
expect(el.text()).toEqual('');

$httpBackend.flush();
el = $(grid).find('.headerCellTemplate');
expect(el.text()).toEqual('headerCellTemplate content');
});
});
});
31 changes: 31 additions & 0 deletions test/unit/core/services/GridClassFactory.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,37 @@ describe('gridClassFactory', function() {
expect(testSetup.col.footerCellTemplate).toEqual('<div>a sample footer template with no custom_filters</div>');
});

it('column builder respectively creates promise like content resolver for each template in column', function() {
testSetup.$templateCache.put('ui-grid/uiGridHeaderCell', '<div>a sample header cell template</div>');
testSetup.$templateCache.put('ui-grid/uiGridCell', '<div>a sample cell template</div>');
testSetup.$templateCache.put('ui-grid/uiGridFooterCell', '<div>a sample footer cell template</div>');
testSetup.$templateCache.put('ui-grid/ui-grid-filter', '<div>a sample filter template</div>');

gridClassFactory.defaultColumnBuilder( testSetup.colDef, testSetup.col, testSetup.gridOptions );

expect(testSetup.col.providedHeaderCellTemplate).toEqual('ui-grid/uiGridHeaderCell');
expect(testSetup.col.providedCellTemplate).toEqual('ui-grid/uiGridCell');
expect(testSetup.col.providedFooterCellTemplate).toEqual('ui-grid/uiGridFooterCell');
expect(testSetup.col.providedFilterHeaderTemplate).toEqual('ui-grid/ui-grid-filter');

testSetup.$rootScope.$digest();

expect(testSetup.col.headerCellTemplate).toEqual('<div>a sample header cell template</div>');
expect(testSetup.col.cellTemplate).toEqual('<div>a sample cell template</div>');
expect(testSetup.col.footerCellTemplate).toEqual('<div>a sample footer cell template</div>');
expect(testSetup.col.filterHeaderTemplate).toEqual('<div>a sample filter template</div>');

expect(testSetup.col.headerCellTemplatePromise).toBeDefined();
expect(testSetup.col.cellTemplatePromise).toBeDefined();
expect(testSetup.col.footerCellTemplatePromise).toBeDefined();
expect(testSetup.col.filterHeaderTemplatePromise).toBeDefined();

expect('then' in testSetup.col.headerCellTemplatePromise).toBe(true);
expect('then' in testSetup.col.cellTemplatePromise).toBe(true);
expect('then' in testSetup.col.footerCellTemplatePromise).toBe(true);
expect('then' in testSetup.col.filterHeaderTemplatePromise).toBe(true);
});

it('column builder with no filters and template has placeholders', function() {
testSetup.$templateCache.put('ui-grid/uiGridHeaderCell', '<div>a sample header template with CUSTOM_FILTERS</div>');
testSetup.$templateCache.put('ui-grid/uiGridCell', '<div>a sample cell template with CUSTOM_FILTERS</div>');
Expand Down

0 comments on commit f0b2fa7

Please sign in to comment.