Skip to content

Commit fd9214b

Browse files
committed
fix(pfTableView): ng-include inside ng-repeat hurts performance
1 parent d0bbacf commit fd9214b

File tree

5 files changed

+55
-27
lines changed

5 files changed

+55
-27
lines changed

Diff for: src/table/tableview/examples/table-view-basic.js

+4-2
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@
2020
* <ul style='list-style-type: none'>
2121
* <li>.header - (string) Text label for a column header
2222
* <li>.itemField - (string) Item field to associate with a particular column.
23-
* <li>.htmlTemplate - (string) (optional) id/name of an embedded ng/html template. Ex: htmlTemplate="name_template.html". The template will be used to render each cell of the column.
23+
* <li>.templateFn - (function) (optional) Template function used to render each cell of the column. Pro: more performant than `htmlTemplate`. Con: doesn't support AngularJS directives in the template, therefore it doesn't support things like ng-click. Example: <pre>templateFn: value => `<span class="text-danger">${value}</span>`</pre>
24+
* <li>.htmlTemplate - (string) (optional) id/name of an embedded ng/html template. Pro: supports AngularJS directives in the template. Con: poor performance on large tables. Ex: htmlTemplate="name_template.html". The template will be used to render each cell of the column.
2425
* Use <code>handleColAction(key, value)</code> in the template to call the <code>colActionFn</code> callback function you specify. 'key' is the item attribute name; which should equal the itemFld of a column.
2526
* 'value' is the item[key] value.
2627
* <pre>
@@ -31,6 +32,7 @@
3132
* <li>.colActionFn - (function) (optional) Callback function used for the column. 'value' is passed as a paramenter to the
3233
* callback function.
3334
* </ul>
35+
* <p><strong>Tip:</strong> For templating, use `tempateFn` unless you really need to use AngularJS directives. `templateFn` performs better than `htmlTemplate`.</p>
3436
* @param {array} actionButtons List of action buttons in each row
3537
* <ul style='list-style-type: none'>
3638
* <li>.name - (String) The name of the action, displayed on the button
@@ -108,7 +110,7 @@
108110
{ header: "Status", itemField: "status", htmlTemplate: "status_template.html" },
109111
{ header: "Name", itemField: "name", htmlTemplate: "name_template.html", colActionFn: onNameClick },
110112
{ header: "Address", itemField: "address"},
111-
{ header: "City", itemField: "city" },
113+
{ header: "City", itemField: "city", templateFn: function(value) { return '<span class="text-success">' + value + '</span>' } },
112114
{ header: "State", itemField: "state"}
113115
];
114116

Diff for: src/table/tableview/examples/table-view-with-toolbar.js

+31-6
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@
2828
* <ul style='list-style-type: none'>
2929
* <li>.header - (string) Text label for a column header
3030
* <li>.itemField - (string) Item field to associate with a particular column.
31-
* <li>.htmlTemplate - (string) (optional) id/name of an embedded ng/html template. Ex: htmlTemplate="name_template.html". The template will be used to render each cell of the column.
31+
* <li>.templateFn - (function) (optional) Template function used to render each cell of the column. Pro: more performant than `htmlTemplate`. Con: doesn't support AngularJS directives in the template, therefore it doesn't support things like ng-click. Example: <pre>templateFn: value => `<span class="text-danger">${value}</span>`</pre>
32+
* <li>.htmlTemplate - (string) (optional) id/name of an embedded ng/html template. Pro: supports AngularJS directives in the template. Con: poor performance on large tables. Ex: htmlTemplate="name_template.html". The template will be used to render each cell of the column.
3233
* Use <code>handleColAction(key, value)</code> in the template to call the <code>colActionFn</code> callback function you specify. 'key' is the item attribute name; which should equal the itemFld of a column.
3334
* 'value' is the item[key] value.
3435
* <pre>
@@ -39,6 +40,7 @@
3940
* <li>.colActionFn - (function) (optional) Callback function used for the column. 'value' is passed as a paramenter to the
4041
* callback function.
4142
* </ul>
43+
* <p><strong>Tip:</strong> For templating, use `tempateFn` unless you really need to use AngularJS directives. `templateFn` performs better than `htmlTemplate`.</p>
4244
* @param {array} actionButtons List of action buttons in each row
4345
* <ul style='list-style-type: none'>
4446
* <li>.name - (String) The name of the action, displayed on the button
@@ -154,11 +156,34 @@
154156
$scope.actionsText = "";
155157
156158
$scope.columns = [
157-
{ header: "Status", itemField: "status", htmlTemplate: "status_template.html" },
158-
{ header: "Name", itemField: "name", htmlTemplate: "name_template.html", colActionFn: onNameClick },
159-
{ header: "Age", itemField: "age"},
160-
{ header: "Address", itemField: "address", htmlTemplate: "address_template.html" },
161-
{ header: "BirthMonth", itemField: "birthMonth"}
159+
{
160+
header: "Status",
161+
itemField: "status",
162+
htmlTemplate: "status_template.html"
163+
},
164+
{
165+
header: "Name",
166+
itemField: "name",
167+
htmlTemplate: "name_template.html",
168+
colActionFn: onNameClick
169+
},
170+
{
171+
header: "Age",
172+
itemField: "age",
173+
templateFn: function(value) {
174+
var className = value > 30 ? 'text-success' : 'text-warning';
175+
return '<span class="' + className + '">' + value + '</span>';
176+
}
177+
},
178+
{
179+
header: "Address",
180+
itemField: "address",
181+
htmlTemplate: "address_template.html"
182+
},
183+
{
184+
header: "BirthMonth",
185+
itemField: "birthMonth"
186+
}
162187
];
163188
164189
// dtOptions paginationType, displayLength, and dom:"p" are no longer being

Diff for: src/table/tableview/table-view.component.js

+5-16
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ angular.module('patternfly.table').component('pfTableView', {
1212
emptyStateActionButtons: '=?'
1313
},
1414
templateUrl: 'table/tableview/table-view.html',
15-
controller: function (DTOptionsBuilder, DTColumnDefBuilder, $element, pfUtils, $log, $filter, $timeout) {
15+
controller: function (DTOptionsBuilder, DTColumnDefBuilder, $element, pfUtils, $log, $filter, $timeout, $sce) {
1616
'use strict';
1717
var ctrl = this, prevDtOptions, prevItems;
1818

@@ -396,21 +396,6 @@ angular.module('patternfly.table').component('pfTableView', {
396396
}
397397
};
398398

399-
ctrl.hasHTMLTemplate = function (key) {
400-
var htmlTemplate = this.getHTMLTemplate(key);
401-
return htmlTemplate.length > 0;
402-
};
403-
404-
ctrl.getHTMLTemplate = function (key) {
405-
var retVal = '';
406-
var tableCol = $filter('filter')(ctrl.columns, {itemField: key});
407-
408-
if (tableCol && tableCol.length === 1 && tableCol[0].hasOwnProperty('htmlTemplate')) {
409-
retVal = tableCol[0].htmlTemplate;
410-
}
411-
return retVal;
412-
};
413-
414399
ctrl.handleColAction = function (key, value) {
415400
var tableCol = $filter('filter')(ctrl.columns, {itemField: key});
416401

@@ -489,5 +474,9 @@ angular.module('patternfly.table').component('pfTableView', {
489474
ctrl.dropdownClass = 'dropup';
490475
}
491476
}
477+
478+
ctrl.trustAsHtml = function (html) {
479+
return $sce.trustAsHtml(html);
480+
};
492481
}
493482
});

Diff for: src/table/tableview/table-view.html

+3-2
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,9 @@
1818
</td>
1919

2020
<td ng-repeat="col in $ctrl.columns" ng-init="key = col.itemField; value = item[key]">
21-
<span ng-if="!$ctrl.hasHTMLTemplate(key)">{{value}}</span>
22-
<span ng-if="$ctrl.hasHTMLTemplate(key)" ng-include="$ctrl.getHTMLTemplate(key)"></span>
21+
<span ng-if="!col.htmlTemplate && !col.templateFn">{{value}}</span>
22+
<span ng-if="col.htmlTemplate" ng-include="col.htmlTemplate"></span>
23+
<span ng-if="col.templateFn" ng-bind-html="$ctrl.trustAsHtml(col.templateFn(value))"></span>
2324
</td>
2425

2526
<td ng-if="$ctrl.actionButtons && $ctrl.actionButtons.length > 0" class="table-view-pf-actions" ng-repeat="actionButton in $ctrl.actionButtons">

Diff for: test/table/tableview/table-view.spec.js

+12-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ describe('Component: pfTableView', function () {
3333
{itemField: 'uuid', header: 'ID'},
3434
{itemField: 'name', header: 'Name', htmlTemplate: "name_template.html", colActionFn: onNameClick},
3535
{itemField: 'size', header: 'Size'},
36-
{itemField: 'capacity', header: 'Capacity'}
36+
{itemField: 'capacity', header: 'Capacity', templateFn: function(value) { return '<span class="custom-template2">' + value + '</span>' }}
3737
];
3838

3939
$scope.items = [
@@ -148,6 +148,17 @@ describe('Component: pfTableView', function () {
148148
expect($scope.result).toBe('You clicked on One');
149149
});
150150

151+
it('should use a template function if one is configured', function () {
152+
basicSetup();
153+
var customSpans = element.find('.custom-template2');
154+
expect(customSpans.length).toBe(5);
155+
customSpans.each(function(i) {
156+
var result = $(this).parent().html();
157+
var expected = '<span class="custom-template2">' + $scope.items[i].capacity + '</span>';
158+
expect(result).toBe(expected);
159+
});
160+
});
161+
151162
it('should not show pagination controls by default', function () {
152163
basicSetup();
153164
expect(element.find('pf-pagination').length).toBe(0);

0 commit comments

Comments
 (0)