I have html template like this:
$scope.template = '<span class="pointer"><i class="icon-refresh pointer" ng-click="refresh()"></i></span>';
I want to bind this template using ng-bind-html, I tried to use it and also I used ng-bind-html-unsafe, but unfortunately It bind the html string as it is with no click action.
<span ng-bind-html="template"></span>
<span ng-bind-html-unsafe="template"></span>
I read about similar problem and it said that ng-click is loaded after ng-bind, so can anybody introduce to me how to solve this problem?
Perhaps you need to compile the template inside the controller?
angular.controller('ABCDCtrl', function($scope, $compile){
var templateHTML = '<span class="pointer"><i class="icon-refresh pointer" ng-click="refresh()"></i></span>';
$scope.template = $compile(templateHTML)($scope);
});
You could try ng-include and put your template in to a static file instead.
Putting HTML content in scope variables kind of goes against some angular philosophy guidelines, I believe.
If you were to later change the template, would you want it to rebind itself and be processed again?
Related
I have a special template problem... I have a array of products, every products have a property "button_code", this property is a result in plain text of HTML laravel template with some angular code inside.
Actually im using a ng-bind-html="product.button_code" inside a and use this template inside a ng-repeat, the html code is correctly inserted in every repeat iteration, but the code is plain text, and I need to "wake up" the ng-controllers ng-clicks etc inside this html
I try with this:
var targets = $('.buy-button-container').toArray();
for (var target in targets) {
console.log($(targets[target]));
$compile($(targets[target]))($scope);
}
$scope.$apply();
But this make the code inside the container (all html code inserted in the ng-bind-html) dissapear of the DOM.
How i can do this?
PD: and yes, im forced to use these template in these product.button_code because special things...)
Thanks
EDIT: This is a piece of code i want to bind:
<button class="buy-link btn btn-default" data-toggle="modal" role="button" ng-controller="BuyController" ng-click="doProduct({'id':'8888','title':'testestest','price':13.99,'currency':'EUR''preorder_enabled':false,'crossedPrice':100,'stock':true,'short_desc':'bla bla bla.','lbonus':false,'bonus_txt':false})">
<span class="left">
<i class="fa fa-cart"></i>
<span itemprop="price">€13.99</span>
</span>
<span class="right">
{{GETIT}}</span>
</button>
Use the transclude function furnished as the second argument of the function created by the $compile service:
app.directive("compileBindExpn", function($compile) {
return function linkFn(scope, elem, attrs) {
scope.$watch("::"+attrs.compileBindExpn, function (html) {
var expnLinker = $compile(html);
expnLinker(scope, function transclude(clone) {
elem.empty();
elem.append(clone);
})
});
};
});
The above directive evaluates the compile-bind-expn attribute as an AngularJS expression. It then uses the $compile service to bind the evaluated HTML to the element. Any existing content will be removed.
Usage:
<div class="buy-button-container" compile-bind-expn="buttonCode">
<p>This Node disappears when expression binds</p>
</div>
Note that the directive uses a one-time binding in the $watch to avoid memory leaks.
The DEMO on JSFiddle
In order to make HTML render you have to use the following function:
$sce.trustAsHtml('<b>Your html</b>');
You will have to inject $sce into your Controller.
If you are doing this in a ng-repeat you will need a function in your controller that does this. Ex:
$scope.transformHTML = function(html) {
return $sce.trustAsHtml(html);
}
in your template...
<div ng-repat="foo in bar">
<div ng-bind-html="transformHTML(foo.html)"></div>
</div>
Anyway, I don't think that the "Angular" magic within your HTML will work.
I have some values as amount like 1000, 2000, <b>3000</b>, <4000>, <b>5000</b> inside JSON as an API response. I want to render this response inside a table. So I tried ng-bind-html. BUT it is showing only the value which are having tags like 3000,5000. I want to show all values , 1000,2000,4000 as a plain string and 3000,5000 in BOLD/or any other HTML tag.
angular.forEach($scope.arr2.test,function(item)
$scope.res=$sce.trustAsHtml(item.amount);
return $scope.res;
});
On HTML side, I have something like this
<td id="price" class="edit" ng-repeat="pro in d.procedure" ng-bind-html="valueCheck(d._id,pro._id,hos._id)"></td>
You can use ng-bind-html and ng-bind-html-unsafe for this. But please be mindful of the security concerns here.
You can find more details here
Do make sure you sanitize your strings, to prevent security vulnerabilities
First of all you need to download the ng-sanitize js
https://docs.angularjs.org/api/ngSanitize
and then inject ng-sanitize to angular module.
then you can use ng-bind-html and ng-bind-html-unsafe
you can use ng-sanitize module for the same - see here
var app = angular.module("myApp", ['ngSanitize']);
I have a directive which loads a template with a bunch on input fields. One of which is the jQuery/Bootstrap datepicker.
<my-directive-buttons></my-directive-buttons>
When a user selects/clicks on the datepicker field, the calendar is displayed. I have also attached an ng-click to the input field:
<div class='col-sm-6'>
<div class="form-group">
<div class='input-group datepick'>
<input type='text' class="form-control" ng-click="addCalendarFooter()"/>
<span class="input-group-addon">
<span class="glyphicon glyphicon-calendar"></span>
</span>
</div>
</div>
</div>
On click, the calender is displayed and $scope.addCalendarFooter is called:
app.directive('myDrectiveButtons', function($compile) {
return {
restrict: 'E',
replace: true,
transclude: true,
scope: {
},
templateUrl: 'controls/input-fields.html',
link: function(scope, elem, attrs) {
},
controller: function($scope) {
$scope.addCalendarFooter = function() {
$('#datepicker').append($('<div></div>').load('myDir/calendar/customFooter.html'));
}
}
}
});
I am successful in appending the contents of customFooter.html to the calendar, however, within customFooter.html are further ng-clicks, which when pressed, are not being called. E.g
customFooter.html
<div>
<button ng-click="controlClick()">Click Me</button>
</div>
Yet, if i move this button out of customFooter.html and in to input-field.html, to test the button logic is correct, the click is called.
I have tried $scope.$apply and $scope.digest after the .append, however i get a 'digest already in progress error'
UPDATE:
Based on comments, below, have tried to remove jQuery and use an 'angular way'
$scope.addCalendarFooter = function() {
var html = "<div ng-include src=\"myDir/calendar/customFooter.html\"><\div>";
var myEl = angular.element(document.getElementsByClassName('datepicker');
myEl.html(html);
$compile(myEl)($scope)
}
The above inserts my .html template via the ng-include however is it replacing the contents of the datepicker rather than inserting at the bottom of it. Tried .append but that didn't worth either.
You're basically loading the footer manually and bypassing angular completely. Angular doesn't see that you're loading the html and so doesn't compile the html template and bind directives, including ng-click, at all.
You can use ng-include directive that loads the specified template, instead of making a custom one yourself. Or if your directive needs other functionality, just have the ng-include in the directive template itself.
Quoting from your UPDATE:
The above inserts my .html template via the ng-include however is it replacing the contents of the datepicker rather than inserting at the bottom of it. Tried .append but that didn't worth either.
The aforementioned issue is due to using .html() method which inserts HTML to a DOM node and overwrites any existing content of the selected node:
var html = "<div ng-include src=\"myDir/calendar/customFooter.html\"><\div>";
var myEl = angular.element(document.getElementsByClassName('datepicker');
myEl.html(html); // <== here
$compile(myEl)($scope)
What you are doing with the above logic is that you first select the .datePicker element, then you replace its inner HTML with the .html() method.
As a workaround, you could have used .append() method instead.
NOTE: angular.element() is Angular's wrapper for an element just as in jQuery you had $(). Therefore, using document.getElementByClassName() method is redundant in your case.
Although the above workaround might solve your problem, but it is better to stick to a cleaner and concise approach which AngularJS may offer.
Angularesque Approach
You don't need to load a template partial by programmatically adding/appending the template in a controller function - at least in Angular's way. This way you might end up not binding the angular directive(s) within the dynamically added HTML correctly with a scope.
Instead, just include the partial within the original directive template (with ng-include) and use ngIf or ngShow to display it when the button is clicked.
Therefore, assuming that you've the footer template (customFooter.html) in the original directive template, you can achieve the expected result as in the following:
Directive Template
<div class='col-sm-6'>
<div class="form-group">
<div class='input-group datepick'>
<input type='text' class="form-control" ng-click="addCalendarFooter()"/>
<span class="input-group-addon">
<span class="glyphicon glyphicon-calendar"></span>
</span>
</div>
</div>
</div>
<div ng-include="myDir/calendar/customFooter.html" ng-if="isCalenderFooterAdded"></div>
Directive Controller
controller: function($scope) {
$scope.addCalendarFooter = function() {
$scope.isCalendarFooterAdded = true;
// or use this if you want to toggle it
// $scope.isCalendarFooterAdded = !$scope.isCalendarFooterAdded ? true: false;
}
}
Plunkr mimicking a similar situation.
What if you include your footer in your template initially but hide it with ng-if / ng-show. Then the function would only change a flag and show the previously hidden footer.
You said that your problem is the fact that after calling $scope.$apply or $scope.digest you get the $digest already in progress error.
A clever way to bypass this is using $evalAsync. One of its biggest advantages is that it knows if it should perform an extra digest cycle of not.
If you're using ng-include don't forget the singlequotes at the begining and end of the path.
Angular doc about ng-include: https://docs.angularjs.org/api/ng/directive/ngInclude
make sure you wrap it in single quotes, e.g. src="'myPartialTemplate.html'"
it should be:
var html = "<ng-include src=\"'myDir/calendar/customFooter.html'\"><\ng-include>";
or:
var html = "<div ng-include=\"'myDir/calendar/customFooter.html'\"><\div>";
but not:
var html = "<div ng-include src=\"myDir/calendar/customFooter.html\"><\div>";
I have an angular directive where I'm compiling a template via the templateCache after the directive has loaded. For some reason, my {{}} is being output in the template instead of being parsed and replaced with their respective values. Does anybody know why?
The template looks like this
<script type="text/ng-template" id="input">
<input class="cirque-input" ng-model="model" value="{{model}}" type="{{fieldtype}}" ng-change="updateForm()" />
</script>
and in my directives link function, I get the template and display it with
var tmpUrl=$templateCache.get(scope.template);
elm.html(tmpUrl);
$compile(elm.contents())(scope);
clearly I'm doing something wrong here, but I can't figure out what.
Compile first and then replace element with new html:
var tmpUrl=$templateCache.get(scope.template);
var compiledContents = $compile(elm.contents())(scope);
// here i'm not sure about the html method
elm.html(compiledContents);
// maybe you have to use
// elm.replaceWith(compiledContents[0])
I had a similar problem but I use replace... you may want to try:
var tmpUrl=$angular.element($templateCache.get(scope.template));
elm.append(tmpUrl);
$compile(tmpUrl)(scope);
or
var tmpUrl=$angular.element($templateCache.get(scope.template));
elm.append(tmpUrl);
$compile(elm)(scope);
I'm a beginner in AngularJS and I try to render a json in html with angularJS but html tags are not encoded. Is there a way to do that with an angularJS method ?
My HTML:
<p>{{template.title}}</p>
My JSON:
{
"title":"try a <br> to break line"
}
My JS:
$http.get(JSON).success(function (data) {
$scope.template = data;
});
Unfortunately, the render display the br tag
Angular wants to bind text as text by default.
In Angular <1.2.0 you need to bind the html unsafe (this can be dangerous):
<h1 ng-bind-html-unsafe="title"></h1>
In Angular 1.2.0 you need to bind the html:
<h1 ng-bind-html="title"></h1>
Dont forget to include ngSanitize to keep your server safe.
Overall, I recommend using Angular 1.2.0 rc2 or later versions as the ngSanitize will keep you safe.