allow rendering of html inside angular's square brakets - javascript

suppose I have this bit of html and javascript:
$scope.test = "hello<br/>world";
<div>{{ test }}</div>
angular will obviously render it as:
<div>hello<br/>world</div>
and that is exactly how it is supposed to work but, what if I would like it to actually render it as html markup rather than text?
I know this can lead to security problems, but I would just like to know out of curiousity.
Thanks in advance.

You can use the ng-bind-html directive in AngularJS.
<div ng-controller="ngBindHtmlCtrl">
<p ng-bind-html="trustedHtml"></p>
</div>
where
$scope.myHTML = "I am an <code>HTML</code>string with links!"
will be rendered accordingly.
For the security concerns involved in this, before you pass the HTML content to your scope variable myHTML, sanitize it with:
$scope.trustedHtml = $sce.trustAsHtml($scope.html);
and then use $scope.trustedHtml in your ng-bind-html directive as listed above.

You can create a filter as suggested here:
HTML :
<div ng-controller="MyCtrl">
<div ng-bind-html="my_html | to_trusted"></div>
</div>
This is how your javascript would appear:
var myApp = angular.module('myApp',[]);
angular.module('myApp')
.filter('to_trusted', ['$sce', function($sce){
return function(text) {
return $sce.trustAsHtml(text);
};
}]);
function MyCtrl($scope) {
$scope.my_html = '<div>hello<br/>world</div>';
}

Related

angularjs click event, after appending content [duplicate]

I am working with angularjs 1.2.0-rc.3. I'd like to include html code into a template dynamically. For that I use in the controller :
html = "<div>hello</div>";
$scope.unicTabContent = $sce.trustAsHtml(html);
In the template I got :
<div id="unicTab" ng-bind-html="unicTabContent"></div>
It works fine for regular html code. But when I try to put angular template it is not interpreted, it is just included in the page. For example I'd like to include :
<div ng-controller="formCtrl">
<div ng-repeat="item in content" ng-init="init()">
</div>
</div>
Thanks a lot
This solution doesn't use hardcoded templates, and you can compile Angular expressions embedded within an API response.
Step 1.
Install this directive: https://github.com/incuna/angular-bind-html-compile
Step 2. Include the directive in the module.
angular.module("app", ["angular-bind-html-compile"])
Step 3. Use the directive in the template:
<div bind-html-compile="letterTemplate.content"></div>
Result:
Controller Object
$scope.letter = { user: { name: "John"}}
JSON Response
{ "letterTemplate":[
{ content: "<span>Dear {{letter.user.name}},</span>" }
]}
HTML Output =
<div bind-html-compile="letterTemplate.content">
<span>Dear John,</span>
</div>
For reference sake, here's the relevant directive:
(function () {
'use strict';
var module = angular.module('angular-bind-html-compile', []);
module.directive('bindHtmlCompile', ['$compile', function ($compile) {
return {
restrict: 'A',
link: function (scope, element, attrs) {
scope.$watch(function () {
return scope.$eval(attrs.bindHtmlCompile);
}, function (value) {
element.html(value);
$compile(element.contents())(scope);
});
}
};
}]);
}());
This is what I've made, no idea if it's the angular wayTM, but it works and is super simple;
.directive('dynamic', function($compile) {
return {
restrict: 'A',
replace: true,
link: function (scope, element, attrs) {
scope.$watch(attrs.dynamic, function(html) {
$compile(element.html(html).contents())(scope);
});
}
};
});
So;
<div id="unicTab" dynamic="unicTabContent"></div>
Edit: I found the angular way, and it's super simple.
$templateCache.put('unicTabContent', $sce.trustAsHtml(html));
<div id="unicTab" ng-include="'unicTabContent'"></div>
Don't need to make your own directives or anything.
But it's a bind-once sort of deal, it wont see changes made to your html like the custom directive does.
As Vinod Louis says in his comment, the best way to do that was to use templates. I had to define a template outside of the regular code, for example I added that code inside of my index.html :
<script type="text/ng-template" id="unic_tab_template.html">
<div ng-switch on="page">
<div ng-switch-when="home"><p>{{home}}</p></div>
<div ng-switch-when="form">
<div ng-controller="formCtrl">
<div ng-repeat="item in content">{{item.name}}:{{item.value}}</div>
</div>
</div>
<div ng-switch-default>an error accured</div>
</div>
</script>
This template is conditional, so depending on the value of $scope.page, it switches between the 3 templates (the third being an error handler). To use it I had :
<div id="unicTab" ng-controller="unicTabCtrl">
<div ng-include="'unic_tab_template.html'"></div>
</div>
That way my page changes depending on the $scope inside of my unicTabCtrl controller.
To conclude the idea of inserting angularsjs template seams to be difficult to realize ($compile seams to be the solution, but I wasn't able to make it work). But instead you may use conditional templating.
I was trying to do the same thing and came across this module.
http://ngmodules.org/modules/ng-html-compile
I just included it and then I was able to use "ng-html-compile" instead of "ng-bind-html"
My solution to similar problem in my current app without using template (not elegant, but working):
directive('ngBindHtmlCompile', ['$compile', function ($compile) {
return {
restrict: 'A',
compile: function compile(tElement, tAttributes, transcludeFn) {
return function postLink(scope, element, attributes) {
scope.$watch(function() {
return scope.$eval(attributes.ngBindHtml);
}, function(newValue, oldValue) {
$compile(element.children())(scope);
});
};
}
};
}]);
It requires ngBindHtml on the same element and compiles the element content after it changes with ngBindHtml.
<div id="unicTab" ng-bind-html="unicTabContent" ng-bind-html-compile></div>
ng-html-compile looks similar but at first glance it won't be recalculated when the template content is changing. But I haven't tried it.
One way is use a directive for purpose of inserting custom templates that include angular expresssions
<div id="unicTab" unic-tab-content></div>
app.directive("unicTabContent",function(){
return {
restrict:"A",
template:'{{unicTabContent}}'
}
})
The code below is much simpler using Angular's built-in $interpolate and $sce objects. First inject the $interpolate and $sce Angular objects into your directive as you do anything custom you need in your directive.
amqApp.directive('myDir', ['$interpolate', '$sce', function ($interpolate,$sce ) {...}
Then create all your scoped variables found in your imported html expressions...
$scope.custom = 'Hello World';
Next use $interpolate to process your custom HTML and its expressions...then make sure you use the $sce object to trust it as HTML before binding...
var html = $interpolate('<b>{{custom}}</b>')($scope);
$scope.data = $sce.trustAsHtml(html);
Finally, in your view, just make sure use an element with the "ng-bind" or "ng-bind-html" on it in your view display. I found the $sce piece wont display the HTML as HTML (sees it as text) if you don't bind it in your html template like this...
<span ng-bind-html="data"></span>
You should see in bold...
Hello World
I used this trick to import in text/HTML with custom angular {{expressions}} from a web.config.
A lot simplified solution of #clement-roblot based on built-in templates.
Controller:
app.controller('TestCtrl', [
'$scope',
'$templateCache',
function ($scope, $templateCache) {
$templateCache.put('test.html', '2 + 2 = {{ 2 + 2 }}');
}
]);
View:
<div ng-include="'test.html'"></div>

ng-controller within an include that is within another controller potential scope issue

I am using node and angularjs. I have a frame like page inside an ejs that is passed content to load into the includes dynamically.
<div ng-app="thisApp">
<div ng-controller='MainCtrl'>
{{ firstMessage }}
<div id='contentFromNode' ng-include='<%= pageContent %>'></div>
</div>
</div>
<script>
var thisApp = angular.module('thisApp', []);
thisApp.controller('MainCtrl', [ '$scope', function($scope) {
$scope.firstMessage = "Main Controller Working Fine";
}])
</script>
and then the passed content might be just an html page containing something like this:
<div ng-controller='NestedCtrl' id='content-type-container'>
{{ nestedMessage }}
</div>
<script>
thisApp.controller('NestedCtrl', [function(){
var nested = this;
nested.nestedMessage = "Nested Won't Work";
}])
</script>
So I have tried $scope within the NestCtrl instead of referencing this, I have tried moving the script tag above and below (ideally this get separated eventually anyway). I have tried aliasing the controllers, however my problem is the in registration of the controller itself as I get that great Error: [$controller:ctrlreg] error. The page is loading the content fine? Any ideas what I am doing wrong here?
Seems JQlite doesn't support this. You have to include jquery or lazy load the script. Refer
AngularJS: How to make angular load script inside ng-include?

$compile unusual Behaviour

Angular version:1.3
I am trying to compile the html and generate the interpolated html. the ng-if code is getting commented out
html
<div ng-if="true">true</div>
I am using the above html as htmlTemplateDom
Controller
var htmlCompiledDom = $compile(htmlTemplateDom)($scope);
var div = angular.element("div#emailContent").append(htmlCompiledDom);
console.log(div.html());
Console
<!-- ng-if:true -->
So the problem is ng-if is getting commented out.
Someone help !!!!
I don't see any problems on $compile.
This example works just as expected, check if you're doing something different.
HTML:
<div ng-app="app" ng-controller="controller">
<div id="compile">
</div>
</div>
Javascript:
angular.module('app', [])
.controller('controller', function ($scope, $compile) {
var template = '<div ng-if="true">true</div>';
var content = $compile(template)($scope);
angular.element('div#compile').append(content);
});
If you want to execute it, take a look at this fiddle.

Jquery append() not working with angularjs

We are working with jquery 1.9.1 and angular 1.2.13. We are using a wysiwyg editor that works great, we save the html into the database and load the html back using jquery append function and works fine. Now we are trying to append the same html into a div tag (the wysiwyg editor also uses a div) and the append function it's not working. We check in the console, and the string we are trying to append is there, also jquery grabs the element (also checked in the console log) but the append function it's not working.
PD: I apologize for my english
The html
<div data-ng-controller="PreviewCtrl">
<div class="container">
<div id="resumenPreview"></div>
</div>
</div>
The controller
angular.module('module').controller('PreviewCtrl', ['$scope', '$routeParams', '$location', '$http', 'selectedElement',
function ($scope, $routeParams, $location, $http, selectedElement) {
$scope.id = $routeParams.id;
$scope.mensaje = $scope.id;
$scope.imagen = null;
$scope.dataImagen = null;
//is not working either
$('#resumenPreview').append("hola");
$scope.pageLoad = function () {
var x = selectedElement.data.Resumen;
//This is properly displayed in the console
console.log(x);
//This too, is displayed in the console log
console.log($('#resumenPreview'));
// Why this isn't working? I'am clueless
$('#resumenPreview').append(x);
};
$scope.pageLoad();
}]);
My guess would be there are multiple divs with id="resumenPreview". But this is clearly the wrong way to handle such things in angular. There shouldn't be dom-manipulation in the controller - directives should take care of dom-related stuff. Put the html-string into the scope and let angular handle the injection into the dom:
instead of $('#resumenPreview').append(x); do $scope.resumenPreview = x;
and in the template do this:
<div class="container">
<div ng-bind-html="resumenPreview"></div>
</div>
Solve it with angularjs for the ng-bind-html to work it's necessary to include
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.3/angular-sanitize.js"></script>
and to add 'ngSanitize' as a dependency in the app module configuration. And then just do what #Johannes Reuter posted.
Thanks everybody, Greetings.

Template inside of a directive

I have a strange situation where I need to put a template inside of a template in my directive. The reason for this is that AngularJS will not read ng-repeat code inside of attributes.
In an ideal world, this is what my code would look like:
<div ng-repeat="phone in phones">
<button popover="<div ng-repeat='friend in phone.friends'>{{friend.name}}</div>"></button>
</div>
Unfortunately this does not work because of the quotes around the popover attribute. This has led me down a pretty deep rabbit hole where I'm trying to put a template inside of a template like in this plunker:
http://plnkr.co/edit/ZA1uA1UOlU3cCH2mbE0X?p=preview
HTML:
<div my-popover></div>
Javascript:
angularApp.directive('myPopover', function( $compile) {
var getTemplate = function()
{
var scope = {title: "other title"};
var template = "<div> test template. title: {{title}}</div> ";
return $compile(template)(scope);
}
return {
restrict: 'A',
template: '<button class="btn btn-default" popover="{{content}}" popover-title="title">template</button>',
link: function(scope) {
scope.content = getTemplate();
}
};
})
Unfortunately this does not work because AngularJs complains about a circular reference. Please help! (this has been taking me all day)
I'm not sure I understand exactly what you are trying to achieve, but from the look of it you might want check out the transclude option for directives.
From the docs:
use transclude: true when you want to create a directive that wraps
arbitrary content.
If you use transclude, you can store the popover content inside the button, and "forward" that content to where you want it using the ng-transclude directive.
Your code would then look something like this:
<button>
<div ng-repeat='friend in phone.friends'>{{friend.name}}</div>
</button>
You can see some examples in action in the guide to directives.

Categories

Resources