ngSanitize does not allow allow id attribute - angularjs

I am using ngBindHtml to display some HTML from an (internal) CMS:
<span ng-bind-html="cmsHtml"></span>
The HTML contains a link with an id attribute:
"<a id='fsgPdfLink' href='http://blah/download.pdf' target='_blank'>Click here to download the PDF</a>"
However, I notice that the id attribute is removed by angular before writing the link to the page, so what gets rendered is just:
<a href='http://blah/download.pdf' target='_blank'>Click here to download the PDF</a>
Looking at the source for the ngSanitize module, it seems that for some reason the id attribute is not on the list of valid attributes:
https://github.com/angular/angular.js/blob/master/src/ngSanitize/sanitize.js#L206
What's the reason for not allowing the id attribute? Is it a security risk?
I'd really like to continue to use ngBindHtml if possible. Is there an API where I can add safe tags to the sanitizer's list? Or do I have to edit the source myself to add this tag?

To partially answer my own question, there doesn't seem to be an API to change the built-in whitelist, as described in this open issue:
https://github.com/angular/angular.js/issues/5900

Related

Are html tags inside directive attribute valid in AngularJS

I was doing code review and found custom directive with html tags inside attribute:
<form-field help="Use <b>foo</b> option to blah blah"></form-field>
I find it very unusual, and thought that it will not work in older browsers. But when I and author of this code checked - it turned out that it works in every version of IE we had (10+) and in Chrome/FF without any troubles.
Moreover I checked it in W3C validator (validator.w3.org) and it looks like HTML allows to have unescaped tags inside attributes. This SO answers Can data-* attribute contain HTML tags? confirms that too.
So my question is: Can this make troubles when used with AngularJS? Will this behavior change in Angular 2.0? And finally is this accepted usage of attributes?
I personally would like something like this:
<form-field>
<help>
Use <b>foo</b> option to blah blah
</help>
</form-fild>
Yes, you can do that with ng-bind-html directive. Take a look at this: https://docs.angularjs.org/api/ng/directive/ngBindHtml

Angular render markup that is nested

I get JSON like this
{
"lots of":"keys"
"description" : {
"key":"Some sample key",
"value":"This is the markup™"
}
}
from server and I ultimately iterate the description objects and populate table rows with two columns: one for the key and one for the value.
I have tried putting on my <td> tag ng-bind-html as well as injecting $sce into my controller and using trustAsHtml but so far the string always displays as it is in the JSON. Not every value will be HTML but I can easily detect based on the key if HTML is a possibility. It seemed when I put in the directive on the td it did not display anything if no HTML was present. I am interested in using something that can allow HTML in the value but not require it so I can display either
HTML fragment
<tr ng-repeat="(key, val) in record.description">
<td>{{key}}:</td>
<td>{{val}}</td>
</tr>
I created a quick fiddle here:
https://jsfiddle.net/frishi/mvw97s3q/6/
I used angular-sanitize, which I am not sure you mentioned injecting in your module dependency list. Either way, the example works simply by using ng-bind-html
Relevant docs page: https://docs.angularjs.org/api/ng/directive/ngBindHtml
It works by using the directive ng-bind-html on the element you want to display the HTML string in. You use it like so:
<p ng-bind-html="data.firstName"></p>
assuming that data.firstName = "<strong>FeeFee</strong>" or something like that.
I would also like to add that Angular does not allow this natively because of legitimate security concerns. That and the fact that allowing arbitrary HTML to be rendered might not always produce desirable results. Your page layout could quite possibly break because of some HTML you allowed to be passed through.
Angular was designed with security in mind, and will prevent you from displaying HTML from raw strings whenever possible - to prevent various injection attacks.
Here is workarround for your problem: AngularJS: Insert HTML from a string. Generally you should use ng-bind-html insted of ng-bind (this is used by curly braces).

VisualForce page with AngularJS tag

I've got an interesting question.
I have a VisualForce page with some Angular JS.
The problem is with the ng-repeat-end tag.
The HTML looks like this:
<span ng-repeat-end ng-if="$last" class="a nav__links__link" data-nav="control">You are here: {{breadcrumb.label}}</span>
VisualForce won't save with this error:
Attribute name "ng-repeat-end" associated with an element type "span" must be followed by the ' = ' character.
So I change the offending tag to this:
<span ng-repeat-end="" ng-if="$last" class="a nav__links__link" data-nav="control">You are here: {{breadcrumb.label}}</span>
Which makes VisualForce happy but Angular JS mad with this error:
Unterminated attribute, found 'ng-repeat-start' but no matching 'ng-repeat-end' found.
How can I satisfy both VisualForce's parser and AngularJS?
At the end of the day Visualforce needs a valid XML document. Try searching for "Angular + XHTML" I guess? I've found https://groups.google.com/forum/#!topic/angular/8iorDWKsMyI for example.
Will ng-repeat-end="ng-repeat-end" work? I remember that a trick with attr. name as attr. value is what's a perfectly fine workaround to convert for example <input type="checkbox" checked /> into valid XHTML.
SF themselves didn't include an example similar to what you're trying to do and I'm not familiar with AngularJS... It might be that they promote it but only for hybrid apps (where you could have local HTML file without the restrictions) or apps where you'd build your DOM from javascript, without having any skeleton in VF other than <script>s and <body>.
Last but not least - check what you can salvage from:
the "Mobile Pack": (looks like it's only VF sample in that directory),
http://www.oyecode.com/2013/06/getting-started-with-angularjs-on.html
Maybe contact the developers? All examples I can find seem to just "repeat" by creating a <table>, no <span>s...

ng-click as a class in AngularJS

I'm trying to work out why this doesn't work:
<a class="ng-click: loadSomeDatas();">Click here to load some datas</a>
But this does:
<a ng-click="loadSomeDatas()">Click here to load some datas</a>
Why are you using classes?
Well ng-* attributes don't play nice on some of the clients I have to support, thus rather than shimming them I'd rather just use good ol' safe classes.
This looks like a documentation error. According to the source code, it can only be used as an attribute. The link function does not use restrict so the default is "attribute only".
Can you try using "data-ng-click"? Angular will still work with data- appended before it's attribute names and this should be valid syntax in older browsers.
<a data-ng-click="loadSomeDatas()" href="#">Click here to load some datas</a>

how to compile results of filter before rendered in angularjs

I've got a web app where the user's can enter 'rich text' content (tinymce) and have possibly entered hyperlinks. In my angular app, I'm rendering this in a div with ng-bind-html-unsafe to preserve all formatting. I would like to attach an 'ng-click' to any an all a hrefs in that content. I created a filter that parses the content and adds the 'ng-click' text to the resulting html. I interrogated the DOM and see the ng-click="alert('test')" but there's something I'm missing where the output from the filter isn't being "wired up" (compiled).
The real answer is I needed to be doing this in a directive, not a filter. Roy's link https://stackoverflow.com/a/13405548/295797 provided the necessary guidance.
[answering own question to clear from 'unanswered' queue]

Resources