Skip to content

Commit f0b2fa7

Browse files
falsyvaluesmportuga
authored andcommitted
fix(core): Fixes URL-based template loading for header-cell, footer-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.
1 parent 85c3c90 commit f0b2fa7

8 files changed

+183
-22
lines changed

src/js/core/directives/ui-grid-filter.js

+12-3
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,19 @@
99
pre: function ($scope, $elm, $attrs, controllers) {
1010
$scope.col.updateFilters = function( filterable ){
1111
$elm.children().remove();
12-
if ( filterable ){
12+
if ( filterable ) {
1313
var template = $scope.col.filterHeaderTemplate;
14-
15-
$elm.append($compile(template)($scope));
14+
if (template === undefined && $scope.col.providedFilterHeaderTemplate !== '') {
15+
if ($scope.col.filterHeaderTemplatePromise) {
16+
$scope.col.filterHeaderTemplatePromise.then(function () {
17+
template = $scope.col.filterHeaderTemplate;
18+
$elm.append($compile(template)($scope));
19+
});
20+
}
21+
}
22+
else {
23+
$elm.append($compile(template)($scope));
24+
}
1625
}
1726
};
1827

src/js/core/directives/ui-grid-footer-cell.js

+12-2
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,18 @@
1515
compile: function compile(tElement, tAttrs, transclude) {
1616
return {
1717
pre: function ($scope, $elm, $attrs, uiGridCtrl) {
18-
var cellFooter = $compile($scope.col.footerCellTemplate)($scope);
19-
$elm.append(cellFooter);
18+
var template = $scope.col.footerCellTemplate;
19+
if (template === undefined && $scope.col.providedFooterCellTemplate !== '') {
20+
if ($scope.col.footerCellTemplatePromise) {
21+
$scope.col.footerCellTemplatePromise.then(function () {
22+
template = $scope.col.footerCellTemplate;
23+
$elm.append($compile(template)($scope));
24+
});
25+
}
26+
}
27+
else {
28+
$elm.append($compile(template)($scope));
29+
}
2030
},
2131
post: function ($scope, $elm, $attrs, uiGridCtrl) {
2232
//$elm.addClass($scope.col.getColClass(false));

src/js/core/directives/ui-grid-header-cell.js

+12-2
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,18 @@
1919
compile: function() {
2020
return {
2121
pre: function ($scope, $elm, $attrs) {
22-
var cellHeader = $compile($scope.col.headerCellTemplate)($scope);
23-
$elm.append(cellHeader);
22+
var template = $scope.col.headerCellTemplate;
23+
if (template === undefined && $scope.col.providedHeaderCellTemplate !== '') {
24+
if ($scope.col.headerCellTemplatePromise) {
25+
$scope.col.headerCellTemplatePromise.then(function () {
26+
template = $scope.col.headerCellTemplate;
27+
$elm.append($compile(template)($scope));
28+
});
29+
}
30+
}
31+
else {
32+
$elm.append($compile(template)($scope));
33+
}
2434
},
2535

2636
post: function ($scope, $elm, $attrs, controllers) {

src/js/core/services/gridClassFactory.js

+11-11
Original file line numberDiff line numberDiff line change
@@ -97,9 +97,9 @@
9797
} else {
9898
col[providedType] = colDef[templateType];
9999
}
100-
101-
templateGetPromises.push(gridUtil.getTemplate(col[providedType])
102-
.then(
100+
101+
var templatePromise = gridUtil.getTemplate(col[providedType])
102+
.then(
103103
function (template) {
104104
if ( angular.isFunction(template) ) { template = template(); }
105105
var tooltipCall = ( tooltipType === 'cellTooltip' ) ? 'col.cellTooltip(row,col)' : 'col.headerTooltip(col)';
@@ -119,9 +119,11 @@
119119
},
120120
function (res) {
121121
throw new Error("Couldn't fetch/use colDef." + templateType + " '" + colDef[templateType] + "'");
122-
}).catch(angular.noop)
123-
);
122+
}).catch(angular.noop);
123+
124+
templateGetPromises.push(templatePromise);
124125

126+
return templatePromise;
125127
};
126128

127129

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

140141
/**
141142
* @ngdoc property
@@ -145,7 +146,7 @@
145146
* is ui-grid/uiGridHeaderCell
146147
*
147148
*/
148-
processTemplate( 'headerCellTemplate', 'providedHeaderCellTemplate', 'ui-grid/uiGridHeaderCell', 'headerCellFilter', 'headerTooltip' );
149+
col.headerCellTemplatePromise = processTemplate( 'headerCellTemplate', 'providedHeaderCellTemplate', 'ui-grid/uiGridHeaderCell', 'headerCellFilter', 'headerTooltip' );
149150

150151
/**
151152
* @ngdoc property
@@ -155,7 +156,7 @@
155156
* is ui-grid/uiGridFooterCell
156157
*
157158
*/
158-
processTemplate( 'footerCellTemplate', 'providedFooterCellTemplate', 'ui-grid/uiGridFooterCell', 'footerCellFilter' );
159+
col.footerCellTemplatePromise = processTemplate( 'footerCellTemplate', 'providedFooterCellTemplate', 'ui-grid/uiGridFooterCell', 'footerCellFilter' );
159160

160161
/**
161162
* @ngdoc property
@@ -164,14 +165,13 @@
164165
* @description a custom template for the filter input. The default is ui-grid/ui-grid-filter
165166
*
166167
*/
167-
processTemplate( 'filterHeaderTemplate', 'providedFilterHeaderTemplate', 'ui-grid/ui-grid-filter' );
168+
col.filterHeaderTemplatePromise = processTemplate( 'filterHeaderTemplate', 'providedFilterHeaderTemplate', 'ui-grid/ui-grid-filter' );
168169

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

172173
return $q.all(templateGetPromises);
173174
},
174-
175175

176176
rowTemplateAssigner: function rowTemplateAssigner(row) {
177177
var grid = this;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
describe('uiGridFilter', function () {
2+
var grid, recompile, $compile, $scope, $document, $httpBackend;
3+
4+
var data = [
5+
{ 'name': 'Ethel Price', 'gender': 'female', 'company': 'Enersol' },
6+
{ 'name': 'Claudine Neal', 'gender': 'female', 'company': 'Sealoud' },
7+
{ 'name': 'Beryl Rice', 'gender': 'female', 'company': 'Velity' },
8+
{ 'name': 'Wilder Gonzales', 'gender': 'male', 'company': 'Geekko' }
9+
];
10+
11+
var columnDefs = [
12+
{ name: 'name' },
13+
{ name: 'gender' },
14+
{ name: 'company' }
15+
];
16+
17+
beforeEach(module('ui.grid'));
18+
19+
beforeEach(inject(function (_$compile_, $rootScope, _$document_, _$httpBackend_) {
20+
$compile = _$compile_;
21+
$scope = $rootScope;
22+
$document = _$document_;
23+
$httpBackend = _$httpBackend_;
24+
25+
$scope.gridOpts = {
26+
columnDefs: columnDefs,
27+
data: data
28+
};
29+
30+
recompile = function () {
31+
grid = angular.element('<div style="width: 500px; height: 300px" ui-grid="gridOpts"></div>');
32+
33+
$compile(grid)($scope);
34+
$document[0].body.appendChild(grid[0]);
35+
36+
$scope.$digest();
37+
};
38+
39+
recompile();
40+
}));
41+
42+
afterEach(function() {
43+
grid.remove();
44+
});
45+
46+
describe('should handle a URL-based template defined in filterHeaderTemplate', function () {
47+
it('should handle', function () {
48+
var el, url = 'http://www.a-really-fake-url.com/filterHeaderTemplate.html';
49+
50+
$scope.gridOpts.enableFiltering = true;
51+
$scope.gridOpts.columnDefs[0].filterHeaderTemplate = url;
52+
53+
$httpBackend.expectGET(url).respond('<div class="filterHeaderTemplate">filterHeaderTemplate content</div>');
54+
recompile();
55+
56+
el = $(grid).find('.filterHeaderTemplate');
57+
expect(el.text()).toEqual('');
58+
59+
$httpBackend.flush();
60+
el = $(grid).find('.filterHeaderTemplate');
61+
expect(el.text()).toEqual('filterHeaderTemplate content');
62+
});
63+
});
64+
});

test/unit/core/directives/ui-grid-footer-cell.spec.js

+21-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
describe('uiGridFooterCell', function () {
2-
var grid, data, columnDefs, $scope, $compile, $document, recompile, uiGridConstants;
2+
var grid, data, columnDefs, $scope, $compile, $document, recompile, uiGridConstants, $httpBackend;
33

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

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

27-
beforeEach(inject(function (_$compile_, $rootScope, _$document_, _uiGridConstants_) {
27+
beforeEach(inject(function (_$compile_, $rootScope, _$document_, _uiGridConstants_, _$httpBackend_) {
2828
$scope = $rootScope;
2929
$compile = _$compile_;
3030
$document = _$document_;
3131
uiGridConstants = _uiGridConstants_;
32+
$httpBackend = _$httpBackend_;
3233

3334
$scope.gridOpts = {
3435
showColumnFooter: true,
@@ -86,4 +87,22 @@ describe('uiGridFooterCell', function () {
8687
expect(header.scope().grid.appScope.extScope).toBe('test');
8788
});
8889
});
90+
91+
describe('should handle a URL-based template defined in headerCellTemplate', function () {
92+
it('should handle', function () {
93+
var el, url = 'http://www.a-really-fake-url.com/footerCellTemplate.html';
94+
95+
$scope.gridOpts.columnDefs[0].footerCellTemplate = url;
96+
97+
$httpBackend.expectGET(url).respond('<div class="footerCellTemplate">footerCellTemplate content</div>');
98+
recompile();
99+
100+
el = $(grid).find('.footerCellTemplate');
101+
expect(el.text()).toEqual('');
102+
103+
$httpBackend.flush();
104+
el = $(grid).find('.footerCellTemplate');
105+
expect(el.text()).toEqual('footerCellTemplate content');
106+
});
107+
});
89108
});

test/unit/core/directives/ui-grid-header-cell.spec.js

+20-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
describe('uiGridHeaderCell', function () {
2-
var grid, $scope, $compile, $document, $timeout, $window, recompile, $animate, uiGridConstants, gridUtil, columnDefs;
2+
var grid, $scope, $compile, $document, $timeout, $window, recompile, $animate, uiGridConstants, gridUtil, columnDefs, $httpBackend;
33

44
var downEvent, upEvent, clickEvent;
55

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

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

28-
beforeEach(inject(function (_$compile_, $rootScope, _$document_, _$timeout_, _$window_, _$animate_, _uiGridConstants_, _gridUtil_) {
28+
beforeEach(inject(function (_$compile_, $rootScope, _$document_, _$timeout_, _$window_, _$animate_, _uiGridConstants_, _gridUtil_, _$httpBackend_) {
2929
$scope = $rootScope;
3030
$compile = _$compile_;
3131
$document = _$document_;
@@ -34,6 +34,7 @@ describe('uiGridHeaderCell', function () {
3434
$animate = _$animate_;
3535
uiGridConstants = _uiGridConstants_;
3636
gridUtil = _gridUtil_;
37+
$httpBackend = _$httpBackend_;
3738

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

203+
describe('should handle a URL-based template defined in headerCellTemplate', function () {
204+
it('should handle', function () {
205+
var el, url = 'http://www.a-really-fake-url.com/headerCellTemplate.html';
206+
207+
$scope.gridOpts.columnDefs[0].headerCellTemplate = url;
208+
209+
$httpBackend.expectGET(url).respond('<div class="headerCellTemplate">headerCellTemplate content</div>');
210+
recompile();
211+
212+
el = $(grid).find('.headerCellTemplate');
213+
expect(el.text()).toEqual('');
214+
215+
$httpBackend.flush();
216+
el = $(grid).find('.headerCellTemplate');
217+
expect(el.text()).toEqual('headerCellTemplate content');
218+
});
219+
});
202220
});

test/unit/core/services/GridClassFactory.spec.js

+31
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,37 @@ describe('gridClassFactory', function() {
5050
expect(testSetup.col.footerCellTemplate).toEqual('<div>a sample footer template with no custom_filters</div>');
5151
});
5252

53+
it('column builder respectively creates promise like content resolver for each template in column', function() {
54+
testSetup.$templateCache.put('ui-grid/uiGridHeaderCell', '<div>a sample header cell template</div>');
55+
testSetup.$templateCache.put('ui-grid/uiGridCell', '<div>a sample cell template</div>');
56+
testSetup.$templateCache.put('ui-grid/uiGridFooterCell', '<div>a sample footer cell template</div>');
57+
testSetup.$templateCache.put('ui-grid/ui-grid-filter', '<div>a sample filter template</div>');
58+
59+
gridClassFactory.defaultColumnBuilder( testSetup.colDef, testSetup.col, testSetup.gridOptions );
60+
61+
expect(testSetup.col.providedHeaderCellTemplate).toEqual('ui-grid/uiGridHeaderCell');
62+
expect(testSetup.col.providedCellTemplate).toEqual('ui-grid/uiGridCell');
63+
expect(testSetup.col.providedFooterCellTemplate).toEqual('ui-grid/uiGridFooterCell');
64+
expect(testSetup.col.providedFilterHeaderTemplate).toEqual('ui-grid/ui-grid-filter');
65+
66+
testSetup.$rootScope.$digest();
67+
68+
expect(testSetup.col.headerCellTemplate).toEqual('<div>a sample header cell template</div>');
69+
expect(testSetup.col.cellTemplate).toEqual('<div>a sample cell template</div>');
70+
expect(testSetup.col.footerCellTemplate).toEqual('<div>a sample footer cell template</div>');
71+
expect(testSetup.col.filterHeaderTemplate).toEqual('<div>a sample filter template</div>');
72+
73+
expect(testSetup.col.headerCellTemplatePromise).toBeDefined();
74+
expect(testSetup.col.cellTemplatePromise).toBeDefined();
75+
expect(testSetup.col.footerCellTemplatePromise).toBeDefined();
76+
expect(testSetup.col.filterHeaderTemplatePromise).toBeDefined();
77+
78+
expect('then' in testSetup.col.headerCellTemplatePromise).toBe(true);
79+
expect('then' in testSetup.col.cellTemplatePromise).toBe(true);
80+
expect('then' in testSetup.col.footerCellTemplatePromise).toBe(true);
81+
expect('then' in testSetup.col.filterHeaderTemplatePromise).toBe(true);
82+
});
83+
5384
it('column builder with no filters and template has placeholders', function() {
5485
testSetup.$templateCache.put('ui-grid/uiGridHeaderCell', '<div>a sample header template with CUSTOM_FILTERS</div>');
5586
testSetup.$templateCache.put('ui-grid/uiGridCell', '<div>a sample cell template with CUSTOM_FILTERS</div>');

0 commit comments

Comments
 (0)