how to include an external html with javascript in iFrame - angularjs

I am trying to get html with javascript (with relative paths inside this javascript script tag) using rest service and show it in the iFrame in my angularjs application.
basically we are integrating with webfocus and webfocus provides html contents when we call the rest service. This html content has script tag in it and this script tag has relative paths. so when I try to bind that html/javascript to iFrame's contentWindow.document.body I am getting relative path issue.
Any help would be much appreciated.
Angularjs directive is as follows.
.directive("preview", ['$sce',function ($sce) {
function link(scope, element) {
var iframe = document.createElement('iframe');
iframe.setAttribute("id", "ifWebFocusContent");
iframe.setAttribute("name", "nameWebFocusContent");
var element0 = element[0];
element0.appendChild(iframe);
var body = iframe.contentWindow.document.body;
//var body = iframe.document.body;
scope.$watch('content', function () {
body.innerHTML = $sce.trustAsHtml(scope.content);
});
}
return {
link: link,
restrict: 'E',
scope: {
content: '='
}
};
}])
And HTML code is <preview content="reportHtml"></preview>
I used this link to write this code.

It got resolved when I add base tag in the iframe as here
Also used these 3 lines inside watch instead of assigning inner html.
iframe.contentWindow.document.open();
iframe.contentWindow.document.write($sce.trustAsHtml(scope.content));
iframe.contentWindow.document.close()

Related

Syntax highlighted code snippet wont display with AngularJs ngBind

I used some Syntax highlighting API for highlighting code snippet for my web application.To do that i have used highlightjs .I created popup model and inside model i have put <pre> tag and when model open it should display my highlighted xml string.
HTML Code snippet
<pre id="tepXml" ><code class="xml">{{tepXml}}</code></pre>
In AngularJs controller dynamically bind the value to tepXml from server.
AngularJs controller
...$promise.then(function(data){
$scope.tepXml=data.xml;
}
But the problem was that when i open popup model my xml content is empty.nothing display anything.But when i removed <code class="xml"></code> from <pre> xml content would display with out highlighting.I referred some posts and used $compile in angularJs controller but the problem was still the same.
AngularJs controller with $compile
var target = angular.element($window.document.querySelector('#tepXml'));
var myHTML = data.xml;
target.append( $compile( myHTML )($scope) );
If someone knows where i went wrong please point me out.
Plunker
The quick answer is to do:
$promise.then(function(data){
$scope.tepXml=data.xml;
// Call highlight api
$timeout(function() {
$('pre#tepXml code').each(function(i, block) {
hljs.highlightBlock(block); //or whatever the correct highlightjs call is.
});
});
The more Angular way of doing things is to call a jQuery function from Angular is to write a Directive. Something like this:
.directive("highlightCode", function($interval) {
return {
restrict: "A",
scope: { highlightCode: "=" },
link: function(scope, elem, attrs) {
$scope.$watch('highlightCode', function() {
$(elem).find('code').each(function(i, block) {
hljs.highlightBlock(block); //or whatever the correct highlightjs call is.
});
}
}
});
Used like this:
<pre id="tepXml" highlight-code="tepXml"><code class="xml">{{tepXml}}</code></pre>

Angular extending anchor element with directive on interpolated values

I have angular on the front-end of an application with html characters being interpolated and rendered. The data is coming from a backend CMS.
Almost all of the anchor values are linking to the value of their inner text.
For example:
http://google.com
Instead of repeatedly entering this same pattern I'd like to extend the a tag with a directive:
app.directive('a', function(){
return{
link: function(scope, element, attrs){
var value = $(element)[0].innerText;
if(!attrs.href){
attrs.href = value;
}
if(!attrs.target){
attrs.target = '_blank';
}
}
}
})
My data is coming into angular through bindings like this:
<div class="issue-article-abstact">
<h6 class="main-section" realign>Abstract</h6>
<p ng-bind-html="article.abstract | to_trusted"></p>
</div>
"article.abstract" would be a json object containing <a>http://google.com</a>
This currently only picks up anchor tags that are not rendered on the page through interpolation. Is it possible to create a directive that will see values on the page from bindings and extend their functionality through a directive like this?
Angular doesn't compile html that is inserted using ng-bind-html.
There are third party modules you can use to do it, however you could also do the conversion in a service, controller, custom filter or httpInterceptor before data gets inserted.
Following uses jQuery since it seems you are including it in the page
Simple example:
function parseLinks(html) {
// create container and append html
var $div = $('<div>').append(html),
$links = $div.find('a');
// modify html
$links.not('[href]').attr('href', function(i, oldHref) {
return $(this).text();
});
$links.not('[target]').attr('target', '_blank');
// return innerHtml string
return $div.html();
}
$http.get('/api/items').then(function(resp){
var data = resp.data;
data.forEach(function(item){
item.abstract = parseLinks(item.abstract);
});
return data;
});
This will be more efficient than having to compile all of this html in the dom using directive also

Create a nested fallback src for an Image using angularjs directive

In my tag if the src returns a 404 then I can display a fallback image using directives, but if this fallback image is also returns 404 the how can I show another image using directive
Create a directive to go through a series of error images and provide them one after the other.
You can provide alternative image urls in the tag itself.
<img fallbacksrc="http://url1/error.jpg,http://url2/error.jpg" src="http://url0.image.jpg">
Then write a directive for fallbacksrc and bind the tag for error event. Use split function to alternative images in to an array. You can then choose from this array inside the link function.
The information you are looking for is that the error event will occur any number of times as long as the src fails. So there is no limit for this to occur if all the images you are setting inside the directive fails continuously.
Here is a sample code. I'm using an array of error images in the scope itself in this example without providing them inside the tag.
function MyCtrl($scope) {
$scope.image = "http://greentreesarborcareinc.com/wp-content/uploads/2014/01/image-placeholder.jpg1"
$scope.errorImageIdx = 0;
$scope.errorImages = ["http://spanning.com/assets/uploads/images/11954453151817762013molumen_red_square_error_warning_icon.svg_.med_.png", "http://fivera.net/wp-content/uploads/2014/03/error_z0my4n.png"]
}
myApp.directive('fallbacksrc', function() {
return {
link: function(scope, ele) {
ele.bind('error', function() {
if (scope.errorImageIdx <= scope.errorImages.length - 1) {
angular.element(this).attr("src", scope.errorImages[scope.errorImageIdx]);
scope.errorImageIdx++;
}
});
}
}
});
Here the tag will try to display the image referenced in $scope.image. But that is invalid. So, it tries to load the images from the array.
Try setting the first element of the array to something invalid. It will automatically select the second image in this case.
You can create angular directive like this -
app.directive('onError', function() {
return {
restrict:'A',
link: function(scope, element, attr) {
element.on('error', function() {
element.attr('src', attr.onError);
})
}
}
});
And use like -
<img class="pic" on-error="default-image.jpg" ng-src="{{author.profileImageUrl}}">

angularjs directive rendered by third party component is not working

I have a simple angularjs directive that I use to show a tooltip.
<div tooltip-template="<div><h1>Yeah</h1><span>Awesome</span></div>">Click to show</div>
It works fine but now I'm trying to use it inside a timeline javascript component (visjs.org)
I can add items with html to this timeline like this
item...
item.content = "<div tooltip-template='<div><h1>Yeah</h1><span>Awesome</span></div>'>Click to show</div>";
$scope.timelineData.items.add(item);
The item is well displayed on the page BUT the code of the tooltip-template directive is never reached.
I suspect that because a third party component is rendering the item, the dom element is not read by angular.
I've tried to do a $scope.$apply(), $rootScope.$apply but the result is the same. The directive is never reached.
How can I tell angular to read my dom to parse these directives ?
Here is the directive code :
.directive("tooltipTemplate", function ($compile) {
var contentContainer;
return {
restrict: "A",
link: function (scope, element, attrs) {
var template = attrs.tooltipTemplate;
scope.hidden = true;
var tooltipElement = angular.element("<div ng-hide='hidden'>");
tooltipElement.append(template);
element.parent().append(tooltipElement);
element
.on('click', function () { scope.hidden = !scope.hidden; scope.$digest(); })
$compile(tooltipElement)(scope);
}
};
});
Edit
Added plunker : http://plnkr.co/edit/lNPday452GiZJBhMH4Kl?p=preview
I tried to do the same thing and came with a solution by manually creating scope and compile'ng the html of the directive with the scope using $compile method. Below a snippet
I did the below part inside a directive that created the timeline . Using the scope of that directive ,
var shiftScope = scope.$new(true);
shiftScope.name = 'Shift Name'
var shiftTemplate = $compile('<shift-details shift-name="name"></shift-details>')(shiftScope)[0];
I passed shiftTemplate as the content and it worked fine .
But trying to do this for >50 records created performance issues .

How to use angular directive inside a markdown that is converted via Showdown?

I have a markdown directive that loads a markdown file and displays it as HTML:
// detail.html
<div markdown link="{{post.file"}}"></div>
This works fine, even when I have HTML tags in the markdown files. But I am trying to use AngularUI Bootstrap directives, Tabs in particular, on a markdown page.
Those tabs have content that is specific to each markdown file so for that reason I cannot place a directive outside the markdown file.
I figured it out. You have to use $compile service. Here is the complete code example:
angular.module('MyApp')
.directive('markdown', function($http, $compile) {
var converter = new Showdown.converter();
return {
link: function(scope, element, attrs) {
attrs.$observe('file', function(file) {
if (file) {
$http.get('posts/' + file).success(function(response) {
var htmlText = converter.makeHtml(response);
element.html(htmlText);
$compile(element.contents())(scope);
});
}
});
}
}
});

Resources