Angular filter generating escaped HTML - javascript

This filter is operating on a field that's being loaded from a REST service. It's converting new line characters to <br/> tags and they're getting escaped.
angular.module('myMod').filter('convertBreaks', function($sce) {
return function(input) {
return $sce.trustAsHtml(input.replace(/[\n]/g, "<br/>"));
};
});
It's called like this:
<p>{{data.x.y.z | convertBreaks}}</p>
The <br/> tags are coming out escaped. Any suggestions why?
Update
Forgot to mention that this is being executed by a directive that uses the $compile service.

Try using ng-bind-html
<p ng-bind-html="data.x.y.z | convertBreaks"></p>
Angular has some built in security mechanisms that will cause those kinds of shenanigans.

Related

AngularJS and Sanitize - Sanitize HTML without ngBind Directive

Lets supose we need to sanitize an HTML string and we can't use ng-bind-html directive, for example:
<span data-toggle="tooltip" title="Edit {{customer.name}}">Text</span>
If we have special chars in customer.name this line would be printed as the html version like é and we want é instead.
I have tested with:
$sce.trustAsHtml(customer.name)
$sce.parseAsHtml(customer.name)
But nothing can "translate" this html. How can be this done?
A short explanation would be: how to sanitize html inside a directive (not in the body with ng-bind-html).
It doesn't have to be so complicated.
Instead, use setAttribute and textContent (V.S. innerHTML) on elements, and browsers themselves will take care of sanitizing for you.
// To set element attributes
$span.setAttribute("title", "Edit" + customer.name);
// To set element content
$span.textContent = customer.name;
For more details, see the post here. These are one time bindings of course, so if you need updates, just throw $watch in the midst.
From an oficial documentation:
ngBindHtml uses $sce.parseAsHtml(binding expression). Here's the actual code (slightly simplified):
var ngBindHtmlDirective = ['$sce', function($sce) {
return function(scope, element, attr) {
scope.$watch($sce.parseAsHtml(attr.ngBindHtml), function(value) {
element.html(value || '');
});
};
}];
so I think all you need is $sce.parseAsHtml (https://docs.angularjs.org/api/ng/service/$sce#parseAsHtml).
If you are not able to persuade angular to print HTML anyway, you can try to use
customer.name.replace(/é/g, String.fromCharCode(233));
You can find some basic codes here: http://www.javascripter.net/faq/accentedcharacters.htm
That should work, but it is not definitely the best solution. You should always use ng-bind-html.

Knockout.js: how to make a variable available to all viewmodels so it can be used in bindings without explicitly putting it in all viewmodels?

I am refactoring code base based on Knockout.js and have stumped into a problem.
The code uses templates as interpolated strings in typescript eg.
var template = `<div title='${Resources.string1}'> ${Resources.string1} </div>`
The problem is that the strings can contain a single quote which sometimes break the proper HTML parsing after it has been compiled to javascript.
var template = `<div title='I have a ' single quote'> I have a ' single quote</div>`
I want to expose the Resources object so that it is visible in all the view models without explicitly adding the resource object to every view model so that I can use it like this
<div data-bind="title: Resource.string1"> ${Resources.string1} </div>
Or is their anything global to which I can bind this resources object and access it from all view models inside my app.
You can refer to a global variable without any problem.
This one works, here is a demo fiddle.
var Resources = {
string1: "something here with ' quote"
}
window.Resources = Resources;
ko.applyBindings({});
<div data-bind="text: Resources.string1">
</div>
However, this feels like kind of a hack. I'd rather use some HTML encoding for the resources. See some possibilities here. I'd add a getResource function which would return the requested resource in a properly encoded form.

Include an HTML/CSS/JS file as code, not rendered

I have a page that I am using ng-include to pull in a file as rendered HTML. I would like to include that same file as code, next to it.
Is there a way to do this in Angular, or jQuery? I want to be able to include HTML, CSS and potentially JS files as code that would be run through a code-renderer, like Prism or something similar.
This is similar to jsfiddle or codepen, in that you can see the code and rendered view in the same window, but I do not need them to be connected (ie. edit the code to see the rendered result.) I just want to pull both views from the same file.
I am currently using an Angular directive to loop through a JSON file and push out blocks of HTML according to what is listed in the JSON. My directive is:
app.directive('patterns', function() {
return {
restrict: 'E',
require: ['^ngType', 'ngTemplate'],
scope: {
ngType: '#',
ngTemplate: '#'
},
templateUrl: 'patterns.html',
controller: function($scope, $http, $sanitize) {
var theType = $scope.ngType;
$http.get('indexes/json/' + theType + '.json')
.then(function(result) {
$scope.patterns = result.data;
});
},
controllerAs: 'patterns',
link: function(scope, iElement, iAttrs, ctrl) {
scope.getType(iAttrs.ngType);
}
}
});
And I want to add something that also uses pattern.anchor (based off an "anchor" key I have in my JSON) to grab a particular file and output only the code. I can currently use pattern.anchor with ng-include to output rendered HTML, but not only code.
Yes, with angular you can use ngSanitize or the $sanitize service.
There's a simple example available here: http://codepen.io/tipsoftheday/pen/jthks
angular.module('expressionsEscaping', ['ngSanitize'])
.controller('ExpressionsEscapingCtrl', function ($scope, $sanitize) {
$scope.msg = 'Hello, <b>World</b>!';
$scope.safeMsg = $sanitize($scope.msg);
});
and a more complex example available in the Angular documentation here: https://docs.angularjs.org/api/ngSanitize/service/$sanitize.
Ampersand-Delineated Character Entity
In the code, replace all angle brackets < and > with a character entity code < and >. The entity codes get rendered as angle brackets but don't get processed as such. Unfortunately, this doesn't preserve the formatting of your file (read on to see how to do that), since all whitespace gets compressed to a single non-breaking space.
<strong> The strong tag is shown rather
than rendered, but all whitespace characters
still get compressed into a single space.
However, this <br /> break tag gets rendered rather
than shown. </strong>
HTML provides a block-level element called pre. Anything inside the pre tag is considered pre-rendered and the browser displays it as-is. Whitespace in this block does not get condensed. This will preserve the formatting of your code.
<pre>
<strong> In this block, if I add extra spaces, they are shown.
If I move to a newline, that is shown as well.
HTML tags still need to have<br />their angle brackets replaced
in order to be shown rather than rendered.</strong>
</pre>
If you are using JavaScript/AJAX to include the file, you can first do a string replace function to replace the angle brackets with the character entity codes. If you are doing server-side includes, you can do something similar with your server-side language of choice.
If you want to do all of this automatically, Mike Feltman suggested a method using Angular.

AngularJs Web Components using special characters

as Web Components, I mean AngularJs's directives here.
I am trying to use special characters as a tag's name, especially asiatic ones (korean even more specifically).
Here's a plunker so you'll get a better grasp on what I try to achieve.
// library
(function (angular) {
angular.module('molecules', [])
.directive('헐', function () { return {
template: 'ㅎㅓㄹ'
}});
})(window.angular);
// main module
(function (angular) {
angular.module('lab', ['molecules']);
})(window.angular);
<div ng-controller="monitor1">
<헐></헐>
</div>
It seems to have to do with how the browser is interpreting the DOM. If you append an alphabet character to the foreign character (in the directive and the start and end tags), it works as expected i.e.
<a헐></a헐>
Note - check out the DOM while you are at it (I was checking in IE11) - notice that the tag is closed with . With <헐> notice that the IE has taken it upon itself to make some modifications. There is also the console error HTML1407: Invalid tag name. First character should match [a-zA-Z].

How to know if $interpolate fails in AngularJS 1.2?

I'm trying to use the $interpolate service in AngularJS 1.2.16. However, I don't know how to check if Angular has properly interpolated all the vars in my string or not.
I noticed in AngularJS 1.3 they have added a new parameter AllOrNothing, which will cause the interpolate function to return an undefined if any embedded expressions fail to evaluate fully.
Any ideas how I can perform a similar check in 1.2? I would be okay looking for any embedded expressions, but Angular will strip them from the string if they are not specified in the context, so I can't even look for non-evaluated tokens in the returned string.
Use a unit test:
var exp = $interpolate('Hello {{name | uppercase}}!');
expect(exp({name:'Angular'}).toEqual('Hello ANGULAR!');
References
AngularJS Source: interpolateSpec.js

Categories

Resources