Angular custom directives are failing in w3 validation - angularjs

When I use custom directives of angular, the html page fails in w3 validation. Help me to overcome this issue.
Eg:
<div>
<share-news news-title="{{...}}" news-content="{{...}}"></share-news>
</div>
When I use the above code,
I am getting the error like
Element share-news not allowed as child of element div in this context. (Suppressing further errors from this subtree.)

While the initial source of the page body (before angular processes an ng-app element) may not adhere to the W3C standards, if you use "replace: true" in directives, custom elements are replaced by a template HTML, which can be valid. So, in this case, you can think about an angular element as just a placeholder that is replaced with the terminal HTML output.

Related

Can component be used on element as an attribute in AngularJS 1.6?

AngularJS 1.6 documentation for directives states:
$compile can match directives based on element names (E), attributes (A), class names (C), and comments (M).
(...)
The following demonstrates the various ways a directive (myDir in this case) that matches all 4 types can be referenced from within a template.
<my-dir></my-dir>
<span my-dir="exp"></span>
<!-- directive: my-dir exp -->
<span class="my-dir: exp;"></span>
Can you use components in the same way, adding them to HTML element by attribute? Because documentation for components always shows examples of comonents being used as elements.
To clarify, instead of having to write it like below and cluttering my markup with non-standard elements:
<component-name></component-name>
I'd like to be able to do something like that in my HTML:
<h1 component-name=""></h1>
The entire web is moving towards components. I wouldn't be concerned about "non-standard elements." At any rate, components are restricted to elements only. They cannot be used for Attributes. This is the primary use case for directives vs. components.
Components are provided specifically for creating HTML and augmenting it with view based behavior. Directives are now primarily for decorating HTML.

ng-if only first directive working with self-closing tag

I am new to angular, so this may not be the best way to do this. I will probably redo most of what I've already done as I learn more.
I am using url routing with ngRoute an it works fine. In one of the pages, I then have a number of ng-include templates- again, everything is good.
In one of the ng-include templates, I am using two directives to display templates.
<provider-search providers="practiceData.providers" states="ref.states" specialties="ref.specialties" status="updateSearchStatus" ng-show="searchStatus == 1"/>
<search-list status="updateSearchStatus" addp="addProvider" providers="searchResults" ng-if="searchStatus == 2" />
Each of the directives uses isolated scope and a controller. The problem is only the first directive is working. If I switch the order, then the second directive (now if first position) works. In short, only the directive listed first works.
Any help is appreciated.
You not closing the tag.
<provider-search providers="practiceData.providers" states="ref.states" specialties="ref.specialties" status="updateSearchStatus" ng-show="searchStatus == 1">
</provider-search>
<search-list status="updateSearchStatus" addp="addProvider" providers="searchResults" ng-if="searchStatus == 2">
</search-list>
Why it is not working?
self-closing or void elements as the html spec defines them are very special to the browser parser. you can't make your own, so for your custom elements you have to stick to non-void elements (<foo></foo>).
Read more from here self closing tag issue

How can I hide a component in AngularJS yet still get an external library to bind to it?

In my code I have something similar to
<div ng-if="variableThatEvaluatesToFalse">
<input id="location">
</div>
What I'm trying to do is hide a component and then show it in response to user input. However, upon my page loading I want Google Maps to attach to my input. Google Maps relies on document.getElementById('location') which is null presumably because AngularJS is 'hiding' it. I can I get document.getElementById('location') to return my input field even if it is initially hidden by the ngIf directive?
The ngIf directive prevents elements from being included in the DOM at all. What you would need in this case is ngHide, which would keep the element in the DOM.
See: https://docs.angularjs.org/api/ng/directive/ngHide

Hide Angular brackets until javascript loaded

I have a few bits of HTML like
<p class="noresults">{{numberOfContacts}} Results Are Available</p>
Is it possible for me to hide {{numberOfContacts}} until Angular has loaded? So it would just say Results Are Available
I've seem some solutions such as hiding the entire body until Angular has loaded, but I'd rather not do that if possible.
Yes, use ng-cloak. Simply add class="ng-cloak" or ng-cloak to an element like this
Using directive <div ng-cloak></div>
Using class <div class="ng-cloak"></div>
It's simply a set of CSS rules with display: none !important and as Angular has rendered your DOM it removes the ng-cloak so an element is visible.
use <span ng-bind="numberOfContacts" /> instead of {{numberOfContacts}}
Sometimes, even if I used the ng-cloak, I could still see the braces for a few seconds. Adding the following style resolved my issue:
[ng-cloak]
{
display: none !important;
}
Please see this link link for more explanation.
Hope it helps :D
This is typically only an issue when working with complex content on really slow devices. In those instances, there can be a brief moment when the browser displays the HTML in the document while AngularJS is parsing the HTML, getting ready, and processing the directives. In this interval of time, any inline template expressions you have defined will be visible to the user. Most devices nowadays have pretty good browsers which are quick enough to prevent this from being an issue. There are two ways to solve the problem.
Avoid using inline template expressions and stick with ng-bind directive.
(Best) Use the ng-cloak directive which will hide the content until Angular has finished processing it. Basically, the ng-cloak directive uses CSS to hide the elements and angular removes the CSS class when the content has been processed, ensuring that the user never sees the {{ and }} characters of a template expression.
One strategy to consider is using the ng-cloak directly to the body element, which will ensure that the user will see an empty browser while AngularJS loads. However, you can be more specific by applying it to parts of the document where there are inline expressions.
I have seen issues with ng-cloak not working when added to an element. In the past, I have worked around this issue by simply adding ng-cloak class to element.
You can use ng-bind instead of expression like
<span ng-bind="data"></span>

AngularJS element directives not displaying when using self-closing tags

I have in my html file directives
<add />
<back />
and the directives are on the form
.directive('add', ['$window', ...
and
.directive('back', ['$window',
This works fine.
If i change the directives to camel case:
.directive('addPlayer', ['$window', ...
<add_player />
<back />
and
<add:player />
<back />
display fine whereas
<add-player /> regular dash
<back />
displays only <add-player> and everything after is not displayed.
Any ideas why?
EDIT:
I've kind of gotten the same behaviour here
http://plnkr.co/edit/cpP4c2TyZwv5Y4BrNUBb?p=preview
To lay your question to rest, I am quoting the official statement from the AngularJS team: (sic)
self-closing or void elements as the html spec defines them are very special to the browser parser. you can't make your own, so for your custom elements you have to stick to non-void elements (<foo></foo>).
this can't be changed in angular.
- IgorMinar
source: https://github.com/angular/angular.js/issues/1953#issuecomment-13135021
Follow the rest of the conversation on AngularJS issue's page where they discuss the possibility of using XHTML for delivering content with self-closing tags that is acceptable to the browser. However do note that it is not fully supported by AngularJS.
HTML spec does not allow self-closing tags on non-void elements.
HTML syntax rules [W3C]
Elements have a start tag to indicate where they begin. Non-void elements have an end tag to indicate where they end.
Start tags consist of the following parts, in exactly the following order:
A "<" character.
The element’s tag name.
Optionally, one or more attributes, each of which must be preceded by one or more space characters.
Optionally, one or more space characters.
Optionally, a "/" character, which may be present only if the element is a void element.
A ">" character.
There is a limited number of void elements in HTML5 spec. Here is the complete list:
area, base, br, col, command, embed, hr, img, input, keygen, link, meta, param, source, track, wbr.
What's really going on
The browser's parser has to listen to the spec. Since using the slash in a non-void element tag is invalid, the parser ignores the ending />, and <back /> means <back>. Therefore you are never closing the first element which prevents the others to work.
On Plunker you have:
<body>
<back></back>
Self closing <back />
Self closing <back />
</body>
which parses into
<body>
<back></back>
Self closing <back>
Self closing <back>
</back>
</back>
</body>
You then specify template: '<button>back</button>' on your directive which replaces back (and it's children) with the specified HTML resulting in:
<body>
<back>
<button>back</button>
</back>
Self closing <back>
<button>back</button>
</back>
</body>
What should I do then?
Use <back></back> for all and it will work fine. Alternatively you could use element attributes: <div back="attr"></div>.
See the following discussions for more details:
Q: Are self-closing tags valid in HTML5?
AngularJS - Custom directives with self-closing tags capture tag siblings.
AngularJS - Self-closing directives not always rendering.
I've run into the same problem recently and managed to fix it by not using self-closing tags. Try <add-player></add-player> instead of the self-closing version.
I don't know why self-closing tags don't work with dashes in the directive's tag name. Did a quick research back in the day and didn't find anything on the HTML/XHTML side. Perhaps a bug/limitation in Angular?
Angular v15.1.0 now has added support to self-closing tags on custom elements.
Check it out: https://github.com/angular/angular/blob/main/CHANGELOG.md

Resources