8

UPDATE

  1. First, this is not a bug in Angular (@PSL).
  2. I've left my original question below for historic purposes.
  3. This is not a bug in HTML spec. After clicking through on some links from commenters below (@zerflagL), I see that the HTML spec says that VOID ELEMENTS are not synonymous with SELF CLOSING ELEMENTS (here's an SO Q&A on the topic).
  4. OK, so crappy research on my part.
  5. Doubling down on this, however:

HTML should include self-closing tags (it appears it no longer does) and siblings should not magically become sub-DOM elements (innerHTML).

Thanks to @PSL, @shaunhusain and @zeroflagL for setting me straight.


I believe I may have found a bug in Angular's custom directive processing and would like confirmation to make sure I haven't misunderstood custom directive behavior. I'm new to AngularJS, so perhaps I've made a mistake.

It looks like when Angular processes a custom directive on a void element, an improper DOM change occurs and peer elements are pushed down to inner HTML. Here's some HTML:

<div ng-app="myApp">
    <div ng-app="mainController">
        <div>
            <voidtagtest></voidtagtest>
            <p>Example 1 - stays peer</p>
        </div>
        <div>
            <voidtagtest/>
            <p>Example 2 - becomes innerHTML</p>
            <p>this one, too.</p>
        </div>
    </div>
</div>

Here's some JavaScript for Angular:

angular.module('myApp', [])
    .controller('mainController', function ($scope) {
        $scope.message = 'a msg';
    })
    .directive('voidtagtest', function () {
        return {
            restrict: 'E'
        };
    });

The DOM after Angular processing (requires browser web inspection) is:

    ...
    <div>
        <voidtagtest>
            <p>Example 2 - becomes innerHTML</p>
            <p>this one, too.</p>
        </voidtagtest>
    </div>
    ...

Notice how the two Paragraph tags were pulled inside the voidtagtest element?

W3C definition of VOID ELEMENT, if you weren't aware of its syntax.

Here's a jFiddle implementing the entire beast.

Is this a bug or am I missing something? If it is a bug, please recommend how I can file a bug with the Angular team.

Thanks.

Community
  • 1
  • 1
Andrew Philips
  • 1,950
  • 18
  • 23
  • 3
    It is a well known behavior.. https://github.com/angular/angular.js/issues/1953 – PSL Sep 14 '14 at 03:29
  • I don't think you can force a custom empty element to be a void element (i.e. always empty). – BoltClock Sep 14 '14 at 04:02
  • @PSL, thanks for the pointer. That was helpful. I commented on that link. Although it's closed as not a bug, I believe that's a mistake (it is a bug) and have made that clear. – Andrew Philips Sep 14 '14 at 04:27
  • 1
    @BoltClock, actually, I'm not trying to force it to be **only** a void element (vs. start & end tags). Only asking that the void element not consume its siblings when processed. Apparently, this behavior is a known problem and the use of void elements in custom directives is recommended against. – Andrew Philips Sep 14 '14 at 04:29

2 Answers2

2

UPDATED

Not an AngularJS bug. See top of question for update to all of this.


OK, so thanks to @PSL (see comment on question), I'm made aware that this is a known behavior with Angular. I see no valid reason for this behavior to be tolerated. I think Angular should fix this and have left a comment in github telling them so. I leave this answer here in case anyone else is tripped up by this, although I refuse to mark it as accepted as I don't accept the premise that this is proper behavior. Hopefully, some future release will fix this problem and someone can add a proper answer here that can be accepted.

Andrew Philips
  • 1,950
  • 18
  • 23
  • 2
    Hi Andrew, glad you found some closure here although you still consider it an Angular issue. Based on reading the discussion linked above by PSL though it seems to be a problem with the HTML parsers in web browsers rather than a problem with angular itself. The thing is the browser is going to be interpreting/parsing the HTML before angular has a chance to pass over it to smooth things like this out. So I think they closed the bug since it can't be fixed in Angular or any other JS framework itself, rather it's a browser bug. – shaunhusain Sep 14 '14 at 05:47
  • 1
    @shaunhusain, thank you. That's the explanation that I needed (or apparently wasn't able to understand). I've created another jsFiddle (http://jsfiddle.net/codeedog/x6zd1vf4/) that demonstrates the problem with no js or angular. I stand corrected, but particularly annoyed (now with the browser). I worked on SGML & XML a couple of decades ago. Void Controls shouldn't behave the way the browsers have built them. Probably some poor implementation in an early browser that's been carried on down through everything. I'll update my comments on the thread at github, too. Blech. – Andrew Philips Sep 14 '14 at 06:26
  • you should update your answer since it is not accurate and passes blame to angular instead of browser – charlietfl Sep 14 '14 at 12:13
  • Updated Question to reflect not a bug in Angular nor HTML browsers. – Andrew Philips Sep 14 '14 at 17:49
1

Contrary to previous versions HTML 5 has a set of very strict rules for parsing the source and creating the DOM. Calling the behavior a bug would be wrong. 8.2.4 of the specs says

When a start tag token is emitted with its self-closing flag set, if the flag is not acknowledged when it is processed by the tree construction stage, that is a parse error.

For tags like input it explicitly states

Acknowledge the token's self-closing flag, if it is set.

For unknown tags (referred to as "any other") the parser is not supposed to acknowledge the flag. So the browser is right, Angular is innocent and we can't use custom self-closing tags. If that behavior is desirable is another story.

BTW: I like how a parser must handle the sarcasm tag ;)

An end tag whose tag name is "sarcasm": Take a deep breath, then act as described in the "any other end tag" entry below.

a better oliver
  • 26,330
  • 2
  • 58
  • 66
  • thanks for the pointer to the HTML spec. I couldn't find how "acknowledged" was handled anywhere in the spec, although perhaps I didn't dig deep enough. However, the SO Question (link in the update section of this question) pulled VOID ELEMENT, SELF CLOSING ELEMENT and acknowledged. – Andrew Philips Sep 14 '14 at 17:51