angular directive leaking child contents out - html

I have a custom tag <my-tag> created with an Angular directive, and replace it with a simple <div> in the directive definition code:
.directive('myTag',function(){
return {
restrict: 'E',
template: '<div>contents in template</div>',
replace: true
}
})
Things get strange when I put this tag inside a <p> tag and have some block element in it (for later transcluding maybe):
<p>
<my-tag><div>leak</div></my-tag>
</p>
the rendered html is something like this:
<p><div>contents in template</div></p>
<div>leak</div>
rather than been replaced as a whole, the <div>leak</div> is leaked out. Firstly I thought this might be some inline/block element issue, since the <p> tag is only allowed to have phrasing content in it. But when I switched it to <pre>, <h1>, <span>(they all have the same restrictions in the content model), I don't have the problem anymore:
<span>
<my-tag><div>leak</div></my-tag>
</span>
rendered html (as expected):
<span><div>contents in template</div></span>
This could be a big problem when tries to transclude the contents - they are completely unavailable in the directive.
Here is a plunker for the live demo:
http://plnkr.co/edit/hOByDb
Frankly I'm not sure whether this is a browser issue or a Angular issue, or maybe is just an intended behavior?
Edit:
I think this is rather a common HTML issue than an Angular issue, but it's more likely to happen in an Angular project, since we tend to have many custom directives/tags there.

According to W3C docs ( HTML4 & HTML5), block level elements are not valid children of <p>. This is cause of your problem
The P element represents a paragraph. It cannot contain block-level elements (including P itself).
Reference docs

Related

Terminology - The types of elements in HTML

A while ago there was a term that I remembered that described two categories of elements. I forgot the term and I want to know what that term was. The information I can remember is that the first category of elements get their values from within HTML like <p> or <a> or <ul> but there is another category of elements which get their values from "outside" of HTML like <img> or <input type="textbox">. I want to know the terminology for these types.
Edit - I've went through Zomry, Difster and BoltClock's answers and didn't get anything. So I remembered some extra piece of information and decided to add it. The two categories are Lazy Opposites of each other. For example if one is called xyz, then the other is called non-xyz.
Probably you mean replaced elements (and non-replaced, respectively)?
However, the distinction between them is not so unambigous. For example, form controls were traditionally considered replaced elements, but the HTML spec currently explicitly lists them as non-replaced (introducing the "widget" term instead).
The HTML specification mentions for tags like <img> and <input> the following: Tag omission in text/html: No end tag.
Tags with an end tag are defined as: Tag omission in text/html: Neither tag is omissible.
So as far as I can find, the HTML spec does define a technical name for this, apart from void versus normal elements, so what Watilin pointed out in the comments should be fine: standalone vs containers.
As an added side-note: HTML has a lot more HTML content categories. You can find a complete overview at the HTML spec here: https://html.spec.whatwg.org/multipage/indices.html#element-content-categories
Also interesting to read to visualize that a bit better: https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Content_categories
Elements whose contents are defined by text and/or other elements between their start and end tags don't have a special category. Even the HTML spec just calls them normal elements for the most part in section 8.1.2.
Elements whose primary values are defined by attributes and that cannot have content between their tags are called void elements. img and input are indeed two examples of void elements. Note that void elements are not to be confused with empty elements; see the following questions for more details on that:
Are void elements and empty elements the same?
HTML "void elements" so called because without content?
<input type="text" id="someField" name="someField">
With an input selector, you can get a value from it like so (with jQuery):
$("#someField).val();
Where as with a paragraph or a div, you don't get a value, you get the text or html.
<div id="someDiv">Blah, blah, blah</div> You can get that with jQuery as follows:
$("#someDiv").html();
Do you see the difference?

Why the <content> tag must be defined with a starting and ending tag?

I used these two syntaxes in Firefox/Chrome to define a WebComponent.
Open tag
<content></content>
Closed tag
<content/>
and both work as expected.
What are the (technical) reasons for defining <content> in the first way?
MDN Content element indicates that a starting and ending tag is mandatory, but doesn't specify why.
You actually must use the <content></content> form. In a normal HTML (non-XML) document (which is what you want to be making here), with the standard way that HTML parsing works in all browser engines, the <content/> tag is not a content end tag—instead it’s just a content start tag with an extra / inside it that just gets ignored by HTML parsers.
In your case, that means when an HTML parser doesn’t see any </content> end tag for that content-start-tag-with-extra-/-at-the end, the parser never actually closes that content element, so that *all nodes that follow that content element become child content of it.
To see what I mean, look at the DOM view of what the <content/> looks like to an HTML parser.
MDN Content element indicates that the empty tag form is mandatory, but doesn't specify why.
I'm not sure what you mean by “empty tag form”. That MDN page says:
Tag omission: None, both the starting and ending tag are mandatory.
That means the content element must have an end tag.

Is there a way to safely hide HTML tags in AngularJS?

I'm recently starting to explore AngularJS, and of course, i know it is ran at the client side, and since SPA (Single Page Applications) are becoming more and more common, i have a question regarding how to safely hide HTML elements.
Let me give a simple example:
Employee
<div ng-show="canSeeSalary">
{{salary}}
</div>
Now, of course, at runtime the div tag related to the salary won't be displayed, however by seeing the HTML source code, or using a developer tool like the one we have in Chrome, it would be possible to see the tag and probably its value.
I know tags like these should be filtered at the the server-side, of course, but since it has come to the client side, the div will be there.
My question is exactly, if there is any way i could hide these divs from the HTML source code, without needing to mix AngularJS with JSTL, for example.
Thanks in advance.
Try ng-if directive:
<div ng-if="canSeeSalary">
{{salary}}
</div>
Corresponding div element will be removed from the DOM. From the official documentation:
The ngIf directive removes or recreates a portion of the DOM tree
based on an {expression}. If the expression assigned to ngIf evaluates
to a false value then the element is removed from the DOM, otherwise a
clone of the element is reinserted into the DOM.
Use
Employee
<div ng-if="canSeeSalary">
{{salary}}
</div>
ng-if completely removes and recreates the element in the DOM rather than changing its visibility via the display css property
I would recommend using ngCloak rather than ngIf.
The ngCloak directive is used to prevent the Angular html template from being briefly displayed by the browser in its raw (uncompiled) form while your application is loading. Use this directive to avoid the undesirable flicker effect caused by the html template display.
example:
<div ng-cloak> {{::test}} </div>
ngCloak # Official Angular Docs

HTML validation :document type does not allow element

It has been an hour since I started finding a solution but so far no luck. I am sure that it is just a matter of some missing tag or something but despite my efforts unable to find the issue. The page is located at:
http://contestlancer.com/greenFields/?page_id=47
and I am getting 114 validation errors all same as title of the thread on all <p> and <h2> tags in the document.
Here is the validation results link: CLick here
And here is a JS fiddle containing HTML Code:
http://jsfiddle.net/fz6m6/
<p> elements may not contain <div> elements (or indeed any block-level element).
The problem was (at least) that you had p elements that lacked a closing tag </p>, which is not allowed in XHTML, and the page declares an XHTML doctype.

CKEditor 4 and nonstandard HTML element

Here is a nonstandard HTML element that I defined (AngularJS makes this easy):
<exercise id="Sample Exercise" language="Scala" lectureId="5437">
This is the text of the lecture
</exercise>
If I use this element in an HTML document, each time I switch from CKEditor's rendered mode to source mode a new empty paragraph is added between each of the block elements in the document:
<p> </p>
The 2nd time I switch, I get two insertions:
<p> </p>
<p> </p>
The 3rd time I switch, I get three insertions between each block-level element, etc:
<p> </p>
<p> </p>
<p> </p>
Can anyone suggest a workaround?
It seemed easier to avoid custom elements and so I used HTML5 data attributes.
<div class="exercise" data-id="Challenge #42" data-language="Scala" data-lectureid="5437">
<p>Create a program that outputs the meaning of life, the universe, and everything.</p></div>
This worked out. Maybe greater integration between CKEditor and AngularJS will evolve over time.
Pekka's question is very good - why do you need to load a custom element into CKEditor? Neither browsers (which do one part of WYSIWYG editing) not CKEditor (which does another part) know how to handle this element, what it means, how to render it and how editing features should work around it. For example, if I understood your question, you wrote about <exercise> that it is a block element. How do CKEditor and browsers know that it is a block element? :|
Second thing you should understand is that CKEditor is not a WYSIWYG website builder, but a "documents" editor. Its content has to have a meaning for it and that tag won't have it.
Anyway, if you must go this way, there are some things you can do.
Here are two answers that can give you an idea what you can do: CKEditor strips <i> Tag.
If you'll decide not to protect source of your <exercise> tags, but to render them, then you should also know about the CKEDITOR.dtd object, which I described briefly here: ckeditor how to allow for .insertHtml("<customTag myAttr='value'"></customTag>").