I am getting issue in changing inner HTML of div - javascript

I found a problem in changing html of div:
document.getElementsByClassName("lab")[0].setAttribute("ng-bind-html", "binds");
$scope.binds="<h1>run</h1>";
I am setting attribute ng-bind-htmlin java script because I have have integrated some plugin in my code in which div of class="lab" is getting declared through JavaScript. The attribute binds is attached properly, I checked this in inspect element. In fact whenever I attached property of ng-bind-html in JavaScript then ng-bind-html does not work. What is the correct way to do it? There is no error in the code.

Basically you have added ng-bind-html attribute dynamically, which will add directive attribute to the DOM but ng-bind-html directive wouldn't get evaluated the html content. You need to recompile that DOM using
$compile(document.getElementsByClassName("lab")[0])($scope)
To making sure this should work you need to add ngSanitize module in your angular app.
Demo plunkr
The way you are doing is not a standard way of doing DOM manipulation
in AngularJS. The standard approach would be keep ng-bind-html attribute there itself in html rather than adding it dynamically.
Standard way
HTML
<h1>Cleaner way</h1>
<pre ng-bind-html="binds"></pre>
Code
(function(angular) {
'use strict';
angular.module('bindHtmlExample', ['ngSanitize'])
.controller('ExampleController', ['$scope', '$compile', function($scope, $compile) {
$scope.binds="<h1>run</h1>";
}]);
})(window.angular);
Plunkr

Related

Custom directive tag not triggering directive code, in angularjs 1.2.29

I'm trying to use an element directive (restrict: "E") to define a custom component. Here's my page.html template, which gets pulled into index.html via the ng-view directive:
<eng-popup>This text appears, but is rendered in a span</eng-popup>
Angular IS running; index.html has the ng-app="templatesApp" directive in the body tag and app.js sets up the module as below:
var app = angular.module("templatesApp", ['ngRoute']);
Further along, in app.js I have the popup directive defined:
app.directive('engPopup', function() {
console.log("This console log does not trigger. I have tried 'eng-popup' as the directive's first parameter, but that doesn't work either.");
return {
restrict: 'E',
transclude: false,
template: '<div id="thisDoesNotEvenAppear"></div>'
};
});
The problem is, when I look at the resultant html of the component, it looks like this:
<span class="ng-scope" jQuery110209261664696867675="7">This text should appear, surely</span>
</eng-popup class="ng-scope" jQuery110209261664696867675="8"><//eng-popup>
So I have a few questions:
Why does the eng-popup directive console.log call NOT get triggered?
Why does the content in the eng-popup tag end up in a span?
And most mysteriously of all, why does the eng-popup tag start with an END tag and end with a tag with 2 slashes?
Finally, what am I messing up, to make this all happen?
EDIT
As requested, here's a Plunker. It looks like the span and end-tag issues are not happening in this simplified version, but the eng-popup directive is still not being triggered:
https://plnkr.co/edit/mVa6Mye5besJAtWihMWF?p=preview
RE-EDIT
Just in case this is still solvable, here's the latest Plunkr I've been able to put together. It's not working, which it at least has in common with our real project. Not sure if it's the same problem though.
https://plnkr.co/edit/sJoYnYjqx9ZGIH0KhObC
I've modified your example a bit (very little), and it seems to work OK?
https://plnkr.co/edit/3NlHNDOCBVRktk3ZcsnV?p=preview
What i've done is, remove the ui-router requirement, since you had not added the script reference. After that, it works. So, are you including ui-router in your project properly?
So a colleague has pointed out it 'works' in Chrome. Turns out it's an IE8 issue. Who would have thought...
(The whole reason we're using 1.2.29 is because many of our users will be accessing it via IE8, but it looks like custom directives are off the table).

ng-show / ng-hide / ng-if don't work on Angular directive

I'm building a directive that takes the form of a card. When I load the card template I want to ensure that the card is hidden if a user has previously hid the card. I can track this via the request.hide attribute.
Here is my directive (barebones):
app.directive('request', ['$http', '$timeout', function($http, $timeout) {
return {
replace: true,
templateUrl: '/assets/request.html',
transclude: false,
scope: {
request: '='
},
controller: ['$scope', '$http', '$timeout', function($scope, $http, $timeout) {
// Cool stuff goes in here
}]
};
}]);
And here is my template:
<div>
<div ng-hide"request.hide" class="card">
<!-- Cool stuff goes in here -->
</div>
</div>
When the page loads, each request has a hide attribute. In theory, when I call my directive, it should be hidden if hide === true. Unfortunately this doesn't seem to be the case. No matter what I try, I cannot get my directive to be hidden when it's initialized. I've tried using ng-hide="request.hide", ng-show="!request.hide", and ng-if="!request.hide" on the root element, but nothing works.
I wondered to myself if these directives don't work on the root element of a custom directive, so I tried wrapping my directive in an additional div and using ng-hide, ng-show, or ng-if on the .card div, which is now a child element, but that had no effect either.
It seems as though ng-hide is either not being evaluated at all, or is being evaluated before request is defined on the directive's scope.
There's a small typo in the template markup you provided, missing an = sign after ng-hide. But I'm guessing that's just a typo while you were writing up the question.
Otherwise, the directive code looks fine, and it should work. You should double check the "request" object that you're binding the directive to, and make sure that the hide property is actually a boolean value, and not a string.
ng-if, ng-show, and ng-hide all set up watchers, so the issue shouldn't be that the expression gets evaluated before the scope is populated.
Just for testing purposes, try setting up a boolean on your scope in your directives controller, and do the hide or if against that.
Try using ngCloak on the wrapper-div. It should hide the div and its children as long as angular is still evaluating things.
https://docs.angularjs.org/api/ng/directive/ngCloak
edit:
Actually, no. ngCloak doesn't work like I remembered. It hides the element and all its children, but only as long as it wasn't encountered in the compile phase - which is too early for my liking. You could write your own cloaking directive, though.
Here is ngCloak's source:
var ngCloakDirective = ngDirective({
compile: function(element, attr) {
attr.$set('ngCloak', undefined);
element.removeClass('ng-cloak');
}
});
You would need to mimic its behavior in the pre-/post-link phase.
ng-show can be unreliable.
<div>
<div ng-show"!!request.hide" class="card">
<!-- Cool stuff goes in here -->
</div>
</div>
I finally came up with a solution to my problem, though I'd still like to know what caused the problem and the best way to address it.
I had a theory that ng-show/ng-hide/ng-if were not being evaluated when my directive was compiled, so I decided to use ng-hide="hide" on my directive's root element as before, but in my controller, rather than immediately set $scope.hide = $scope.request.hide, I decided to move this within a $timeout block with a delay of 10ms, like so:
$timeout(function() {
$scope.hide = $scope.request.hide;
}, 10)
This triggers a digest cycle after the directive is compiled, causing ng-hide to be reevaluated. The delay is long enough for the directive to compile but short enough to be imperceptible to the user.

append as html in angular

I want to append the value as html in angular
<div class="storycontent" ng-class="{show: show}">
{{review.name}}: {{review.story}}
</div>
Here in the {{review.story}} I will have value like <b>hello</b><i>something</i> etc
The problem is its displaying the content as <b>hello</b><i>something</i> instead of hellosomething (ie the styling is not applied)
I have to use jQuery to do this
$(".content").each(function () {
$(this).html($(this).text())
});
How can i directly append as .html() instead of .text() in angular?
You don't even need Jquery for that. ng-bind-html can do the trick by himself.
<div class="storycontent" ng-class="{show: show}">
{{review.name}}:
<span ng-bind-html="review.story"></span>
</div>
Moreover, it's also better to add this on your controller when you get the value. Because without this, ng-bind-hmtl isn't safe.
$scope.review.story = $sce.trustAsHtml($scope.review.story);
Note : $sce have to be injected in your controller. It's not available directly with angularJS.
.controller('ControllerName', ['$scope', '$sce', function($scope, $sce) {...
You can use directive ngBindHtml, more info here: https://docs.angularjs.org/api/ng/directive/ngBindHtml
Also you have to remeber that before binding html you have to ensure Angular that it is safe. You can use ngSanitize for it and $sce.trustAsHtml function:
https://docs.angularjs.org/api/ng/service/$sce#trustAsHtml
use ng-bind-html="expression"
expression is your html here
You can use ng-bind-html in angular.
By Docs: ng-bind-html
Evaluates the expression and inserts the resulting HTML into the
element in a secure way. By default, the resulting HTML content will
be sanitized using the $sanitize service. To utilize this
functionality, ensure that $sanitize is available, for example, by
including ngSanitize in your module's dependencies (not in core
Angular). In order to use ngSanitize in your module's dependencies,
you need to include "angular-sanitize.js" in your application.
Use: ng-bind-html="review.story">
Refer docs

How to bind text as a DOM object in Angularjs

I want to show MathML DOM object dynamically with Angularjs.
This is what I wrote:
var mathML = angular.module('mathML', ['ngSanitize']);
mathML.controller('mathMLCtrl', ['$scope', function ($scope) {
$scope.result = function(){
return "<math xmlns='http://www.w3.org/1998/Math/MathML'><msup><msqrt><mrow><mi>a</mi><mo>+</mo><mi>b</mi></mrow></msqrt><mn>27</mn></msup></math>";
//return "<p>p tag</p>";
};
}]);
With ng-bind-html, I can insert text as a HTML text, but MathML's XML is not inserted properly. (All tags are deleted.)
It looks like necessary to insert MathML text as DOM Objects. But I don't know how to do it.
How can I show MathML with Angularjs?
ng-bind-html sanitizes the output by removing tags that are not listed as "safe". The math tag is not listed under the allowed tags. If you trust this html to never have exploits, you'll want to use the $sce service to mark the code as trusted. See this answer:
https://stackoverflow.com/a/19417443/1248889
Another alternative would be to save this text as a partial, in it's own separate file. Then in your html, use ng-include to load the partial into the dom.

AngularJS to render a template inside a compile inside a loop inside a partial

I have a partial, which has a directive which renders a bunch of things in a loop, using compiled HMTL-as-a-string inside the directive. This HTML-as-a-string itself contains an ng-include, which doesn't render out.
Please see my jsfiddle example
Basically, this doesn't include template2.html:
element.html('<span>The name is ' + scope.content.name + '!</span><div ng-include src="template2.html"></div><br>');
Any pointers would be much appreciated.
Thanks!
WORKING DEMO
just needed to write as
src=" \'template2.html\'"
var linker = function(scope, element, attrs) {
element.html('<span>The name is ' + scope.content.name + '!</span><div ng-include src=" \'template2.html\'"></div><br>');
$compile(element.contents())(scope);
};
more info in DOCS
Vinod's answer above (replace src="template2.html" with src="\'template2.html\'") is correct, though I would recommend using an actual template instead of manually compiling the template yourself inside the link function. In your example, you aren't actually receiving the benefit of the two way binding. You are just taking the html output of the compile function, and it will never update if the underlying data changes. Here is your example modified to show the bindings (and Vinod's template fix):
http://jsfiddle.net/kf3vZ/5/
Notice how if you change the value of any of the checkboxes, the value in the directives do not change.
Now here is a version using the template argument to the directive:
http://jsfiddle.net/kf3vZ/7/
Now if you change the text fields, the directive values will change also.
Another note, since you are already using the script tags for your templates, you could replace template in your directive with templateUrl and provide the id of the script template.

Categories