-
Notifications
You must be signed in to change notification settings - Fork 27.5k
Directive fails to insert/replace html when template root element is table row (tr) #1459
Comments
Workaround: Instead of replacing a non-standard element with a <div ng-app="tables">
<table>
<tr row key="x" value="y"></tr>
<tr row key="1" value="2"></tr>
<tr row key="longer" value="very long!"></tr>
</table>
</div> angular.module('tables',[])
.directive('row', function() {
return {
restrict: 'A',
replace: false,
scope: { key: '@', value: '@' },
template: '<td>{{key}}</td><td>{{value}}</td>'
}
}); Edit: Further testing shows that this still breaks ng-transclude: <div ng-app="tables">
<table>
<tr row key="Label 1"><input type="text"></input></tr>
<tr row key="Label 2">Text</tr>
</table>
</div> angular.module('tables',[])
.directive('row', function() {
return {
transclude: true,
scope: { key: '@' },
template: '<td>{{key}}</td><td> <span ng-transclude></span>{{value}}</td>'
}
}); It appears that the browser is again moving the element content outside of the element before angular has a chance to apply the template. I'm not sure that it's even possible for angular to make this work. Avoiding |
I'll write this one off to the browser modifying the markup (moving nodes out of the table) before it ever gets to angular. I rewrote the page & directive using |
I have the same problem trying to transclude td into a tr. Please see http://jsbin.com/otogih/9. |
And how about using this solution to ensure transclusion of content which otherwise would be removed by the browser --- if that's the case: < directive-that-transcludes-content > Angular would have to try to detect if it is transcluding a script element and then extract the html template from the script and insert it in each element. Note: I think the id attribute in the script tag is not required |
Working solution here: http://jsbin.com/otogih/18/edit It uses a scriptTransclude directive. |
Re-opening, as I think this is still an issue. Here's very simple example of the problem http://jsfiddle.net/A2FPR/2/ |
Here is a simpler example comparing the scriptTransclude directive and the regular ng-transclude. It is not directly applicable to the example Vojta has shared but has similarities. |
I have also run into this problem trying to replace a element with in a directive with the following template:
I have a potential fix for the problem. In the file "src/ng/compile.js" line 660 it does this:
That is the exception that is thrown, the jqLite calls is failing because it is wrapping the td/tr with in a div the jqLite node creator thinks it's bad HTML. This is the fix I made to make work:
|
Is this planned to be fixed at some point ? |
vote +1 |
+1 The work around I've gone with for this problem is naive, but workable for my situation: A linking function to swap out the tag name...
And then some monkey business in the template that looks like this (ws-lister is creating a table that ends up with a
|
+1 |
I have encountered the same issue in 1.15. As suggested, I had to replace the "replace: true" approach by using an attribute tag instead. This worked.
|
Yep, running into this problem right now. I've tried both writing the directive as an element as well as an attribute. |
I just managed to fix this for I will continue work on this tomorrow and hopefully have a working pull request ready that covers all those tags. |
Any idea if/when pelme's PR will be merged? |
Stumbled about this today too, d'oh! Took me a while to understand that it wasn't my fault but instead a limitation of angular. |
Looking forward to an update on this... |
+1 |
I got around this by doing |
+1 |
Just a note that this also seems to affect templates whose root element is |
So to put it plainly, at present it is impossible to write directives using HTML tables without resorting to "hacks"? |
Yes, that's correct |
If the first element in a template is a <tr>, <th>, <td>, or <tbody> tag, the HTML compiler will ensure that the template is wrapped in a <table> element so that the table content is not discarded. Closes angular#2848 Closes angular#1459 Closes angular#3647 Closes angular#3241
+1 |
I'm still seeing this issue using 1.3. Am I doing anything wrong? |
@timjacobi -- the issue is that the browser's HTML parser will take non-table-content nodes out of your table before angular ever sees them, so we aren't able to put them back for you. To work around this, you can use attribute directives. |
Cheers. I'm trying to only use tag names like in Polymer. Surrounding the |
I don't think polymer will do any better in this case, the HTML parser just pukes on non-table content within tables unless |
Here is my solution to this problem: |
so... you're adding transcludes and never using them? :P anyways, it works in that case because the |
oh hang on, I missed the |
not to mention all of the known unfixable bugs with replace directives |
Thanks, I will look for better solution. |
I mean, it works fine, you just have to be careful with it =) |
I've been struggling with this issue today, so I found and modified an existing plunkr (http://plnkr.co/edit/n2aUcuz2yCoPe2RUE5Gx?p=preview) to give me a simple example of using attribute directives to get around this, but I'm still seeing the table row contents being replaced by a span. Did I misunderstand or incorrectly implement the workaround you suggested? |
You're misunderstanding. So, here's the deal. The HTML parser (in the browser) has this really stupid "adoption agency algorithm", which will reparent elements during parsing when it decides they don't belong. So what happens is, if you have a So, to work around this, you have two options.
|
Hey, I am also running into this problem (I think?). I am using the ng-multi-transclude plugin, which basically let's me have multiple transcludes instead of just one. When using the plugin, the content inside the table is not transcluded at all, unless I change that |
It seems to still be broken with 1.4.7. Check out this plunkr: http://plnkr.co/edit/vgDJadfnwZo7OgCSEVuj?p=preview This code:
... leads to the following DOM:
Note how the cells land outside table, and there's only one of them for each table row (template had 4, DOM has 2). |
As has been pointed out in this thread several times now, HTML does not work the way you're wanting it to here, and there is no way for Angular to make this work for you. When the browser parses For technical details on this, see https://html.spec.whatwg.org/#parsing-main-intable Sorry, but this is not feasible :( You can work around this by defining your own custom |
@caitp many thanks for this information - saved me a lot of time finding a workaround. |
For anyone still looking, I managed to replace the TR itself with no problem. Template:
<script type="text/ng-template" id="comment.html" class="collapse">
<td>{{commentData.content}}</td><td>test</td>
</script>
HTML:
<tr comment-item ng-repeat="comment in comments"
data-index="{{$index}}" data-comment-data="comment">
</tr>
Directive:
app.directive('commentItem', function($timeout, $http, $document) {
return {
restrict: 'A',
scope: {
index: '@'
}, templateUrl: 'comment.html',
link: function postLink(scope) { |
Why shouldn't this work the way "we expect HTML to work"? This is why Angular sucks. Long live React. |
That is pretty inappropriate, @abacaj. Please refer to code-of-conduct |
Don't think it's inappropriate. What's inappropriate is having to build out a workaround because of Angular not because of the browser. Clearly - this is something Angular failed to resolve. |
If you love so much react, we accept it, just let us work with angular and solve our issues!
|
@abacaj I have provided the solution and investigated why it happens. There's nothing angular can do to make it work, it's the browser that expects TR within TABLE opening and closing elements that is the issue. If it finds anything like myRow, which is a custom Angular element, it will just discard it. So, this is not why Angular sucks, sorry. Read @caitp 's post, it explains exactly what is going on.
There is no way to make this work, due to way the the browser behaves. It's not possible to resolve this. |
@otterslide I found it cumbersome that we couldn't use the 'E' restriction. But I suppose it works. |
In an attempt to automate some common table layouts I created a directive that emits the
<tr> ...</tr>
, including the table cells.When this directive is applied, angular throws an exception indicating that the template does not have a single root element (it does).
When
replace
is set tofalse
, this issue does not occur -- but the resulting markup will be invalid.I suspect that the problem is partially due to the browser "cleaning up" the table HTML and moving unrelated or unknown tags outside of the table -- while preventing table tags from being inserted/replaced at the desired location.
Example
Url: http://jsfiddle.net/phaas/sL9gM/
Stack Trace
The text was updated successfully, but these errors were encountered: