Skip to content
This repository has been archived by the owner on Apr 12, 2024. It is now read-only.

fix($compile): properly handle directive replace for table elements #3647

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 20 additions & 5 deletions src/ng/compile.js
Original file line number Diff line number Diff line change
Expand Up @@ -1157,7 +1157,8 @@ function $CompileProvider($provide) {
replaceDirective = originalReplaceDirective,
childTranscludeFn = transcludeFn,
linkFn,
directiveValue;
directiveValue,
directiveValueTrimmed;

// executes all directives on the current element
for(var i = 0, ii = directives.length; i < ii; i++) {
Expand Down Expand Up @@ -1250,11 +1251,25 @@ function $CompileProvider($provide) {

if (directive.replace) {
replaceDirective = directive;
$template = jqLite('<div>' +
trim(directiveValue) +
'</div>').contents();
compileNode = $template[0];

directiveValueTrimmed = trim(directiveValue);

// Special case for table elements that cannot be wrapped in a div
if (directiveValueTrimmed.indexOf('<tr') === 0) {
$template = jqLite('<table><tbody>' + directiveValueTrimmed + '</tbody></table>').children().contents();
}
else if (['<tbody', '<thead', '<tfoot'].indexOf(directiveValueTrimmed.substr(0, 6)) !== -1 ||
directiveValueTrimmed.substr(0, 8) == '<caption') {
$template = jqLite('<table>' + directiveValueTrimmed + '</table>').contents();
}
else if (['<td', '<th'].indexOf(directiveValueTrimmed.substr(0, 3)) !== -1) {
$template = jqLite('<table><tbody><tr>' + directiveValueTrimmed + '</tr></tbody></table>').children().children().contents();
}
else {
$template = jqLite('<div>' + directiveValueTrimmed + '</div>').contents();
}

compileNode = $template[0];
if ($template.length != 1 || compileNode.nodeType !== 1) {
throw $compileMinErr('tplrt',
"Template for directive '{0}' must have exactly one root element. {1}",
Expand Down
106 changes: 106 additions & 0 deletions test/ng/compileSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,16 @@ describe('$compile', function() {
expect(element).toBe(attr.$$element);
}
}));

directive('replaceTr', valueFn({
replace: true,
template: '<tr class="replaced"><td>Replace!</td></tr>',
compile: function(element, attr) {
attr.$set('compiled', 'COMPILED');
expect(element).toBe(attr.$$element);
}
}));

directive('replaceWithInterpolatedStyle', valueFn({
replace: true,
template: '<div style="width:{{1+1}}px">Replace with interpolated style!</div>',
Expand All @@ -512,8 +522,104 @@ describe('$compile', function() {
expect(element).toBe(attr.$$element);
}
}));

directive('replaceTd', valueFn({
replace: true,
template: '<td>Replace!</td>',
compile: function(element, attr) {
attr.$set('compiled', 'COMPILED');
expect(element).toBe(attr.$$element);
}
}));

directive('replaceTh', valueFn({
replace: true,
template: '<th>Replace!</th>',
compile: function(element, attr) {
attr.$set('compiled', 'COMPILED');
expect(element).toBe(attr.$$element);
}
}));

directive('replaceThead', valueFn({
replace: true,
template: '<thead><tr><td>Replace!</td></tr></thead>',
compile: function(element, attr) {
attr.$set('compiled', 'COMPILED');
expect(element).toBe(attr.$$element);
}
}));

directive('replaceTbody', valueFn({
replace: true,
template: '<tbody><tr><td>Replace!</td></tr></tbody>',
compile: function(element, attr) {
attr.$set('compiled', 'COMPILED');
expect(element).toBe(attr.$$element);
}
}));

directive('replaceTfoot', valueFn({
replace: true,
template: '<tfoot><tr><td>Replace!</td></tr></tfoot>',
compile: function(element, attr) {
attr.$set('compiled', 'COMPILED');
expect(element).toBe(attr.$$element);
}
}));

directive('replaceCaption', valueFn({
replace: true,
template: '<caption>Replace!</caption>',
compile: function(element, attr) {
attr.$set('compiled', 'COMPILED');
expect(element).toBe(attr.$$element);
}
}));

}));

it('should replace tr element with template', inject(function($compile, $rootScope) {
element = $compile('<table><tr replace-tr></tr></table>')($rootScope);
expect(element.text()).toEqual('Replace!');
expect(element.find('tr').attr('compiled')).toEqual('COMPILED');
}));

it('should replace td element with template', inject(function($compile, $rootScope) {
element = $compile('<table><tr><td replace-td></td></tr></table>')($rootScope);
expect(element.text()).toEqual('Replace!');
expect(element.find('td').attr('compiled')).toEqual('COMPILED');
}));

it('should replace th element with template', inject(function($compile, $rootScope) {
element = $compile('<table><tr><th replace-th></th></tr></table>')($rootScope);
expect(element.text()).toEqual('Replace!');
expect(element.find('th').attr('compiled')).toEqual('COMPILED');
}));

it('should replace thead element with template', inject(function($compile, $rootScope) {
element = $compile('<table><thead replace-thead></thead></table>')($rootScope);
expect(element.find('td').text()).toEqual('Replace!');
expect(element.find('thead').attr('compiled')).toEqual('COMPILED');
}));

it('should replace tbody element with template', inject(function($compile, $rootScope) {
element = $compile('<table><tbody replace-tbody></tbody></table>')($rootScope);
expect(element.find('td').text()).toEqual('Replace!');
expect(element.find('tbody').attr('compiled')).toEqual('COMPILED');
}));

it('should replace tfoot element with template', inject(function($compile, $rootScope) {
element = $compile('<table><tfoot replace-tfoot></tfoot></table>')($rootScope);
expect(element.find('td').text()).toEqual('Replace!');
expect(element.find('tfoot').attr('compiled')).toEqual('COMPILED');
}));

it('should replace caption element with template', inject(function($compile, $rootScope) {
element = $compile('<table><caption replace-caption></caption></table>')($rootScope);
expect(element.find('caption').text()).toEqual('Replace!');
expect(element.find('caption').attr('compiled')).toEqual('COMPILED');
}));

it('should replace element with template', inject(function($compile, $rootScope) {
element = $compile('<div><div replace>ignore</div><div>')($rootScope);
Expand Down