Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does AngularJS have a bug when processing a custom directive for an HTML Void Element

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.

like image 921
Andrew Philips Avatar asked Sep 14 '14 03:09

Andrew Philips


2 Answers

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.

like image 136
Andrew Philips Avatar answered Sep 21 '22 05:09

Andrew Philips


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.

like image 29
a better oliver Avatar answered Sep 19 '22 05:09

a better oliver