I have a scenario where i have to embed a inline js to an iframe src by dynamically building the iframe at runtime when the component loads.
The example runs fine in both Chrome and Edge but fails in IE11 , what could be the possible reason? IE dosen't even complain and if we check the console log nothing gets printed, where as in chrome it will print my name in the console log .
Stackblitz link.
Note - Please run the app in chrome as well as IE to see the difference .
import { Component, OnInit, Renderer2, ElementRef } from '#angular/core';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent implements OnInit{
name = 'Angular 6';
constructor(private renderer : Renderer2, private elRef : ElementRef ){}
ngOnInit(){
const outerDiv = this.elRef.nativeElement.getElementsByTagName('div')[0];
const el = this.renderer.createElement('iframe');
let script =encodeURI(`data:text/html,<script>console.log('DONE');var execute = function(context){ console.log(context.data.name);}; window.addEventListener('message', function(msg){execute(msg);});</script>`);
el.setAttribute('sandbox', 'allow-scripts');
el.setAttribute('src', script);
outerDiv.appendChild(el);
el.onload = function() {
el.contentWindow.postMessage({name: 'Rahul'}, "*");
}
}
}
<div></div>
Due to security reason in IE, you can not give base64 data of any image/ pdf or any other assets to a HTML object. Instead you can use path of the server having the asset.
how to display base64 encoded pdf?
This gives an example.
Related
I am a newbie working on a project. Some components in my app need external (third-party) scripts for some features to work properly, and all I just need to do is include, locally or via a CDN, the script via the tag in the HTML templates of the components. I've read so many questions on this platform and none of them has particularly addressed my use case:
I just want to add an external script tag like this: <script src="./assets/vendor/bla-bla-bla.min.js"></script> to my Component's template, and force Angular to be aware of the script and load them dynamically when ever I route to my Component. That's all!
Angular CLI 13.0.4,
npm 8.19.2,
node 18.12.1
here you can use this logic :
apiVariableNameHere is variable name or api from your url that needs to be called.
declare let apiVariableNameHere: any;
#Component({
selector: "app-root",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent implements OnInit {
constructor(
private renderer: Renderer2,
) { }
ngOnInit() {
this.loadScript(yourUrl);
}
public loadScript(url) {
let node = document.createElement('script');
node.src = url;
node.type = 'text/javascript';
node.async = true;
node.charset = 'utf-8';
document.getElementsByTagName('head')[0].appendChild(node);
}
}
So I followed the Angular tutorial, downloaded the example app and wanted to use my own javascript. I first tried importing it like usual with the tag in app.component.html, but that didnt work. What Im trying to achieve is a button, that just outputs "hello" to the console onclick with external javascript.
Code of the external js file:
function yep() {
console.log("hello");
}
With <button onclick="yep()"> and the script tag it didnt work, so i searched it up. Someone suggested to link the script file in scripts in angular.json, but that didtn solve it, I linked it b ut yep() is still undefined.
I wouldn't use Nicolar Stadler's solution - in Angular accessing DOM in ts code directly is a security vulnerability.
I linked the external file in angular.json, and it worked. In angular.json in
projects/#projectName#/architect/build/scripts I added
"scripts": ["src/assets/external.js"]
(that's the path to my external file). And I tried calling it in 2 ways, either yours:
<button onclick="yep()">
And more Angular way:
<button (click)="callYep()">
where callYep() is defined in the component:
callYep() {yep();}
where yep() is the external method, but it has to be declared for the typescript:
declare global { const yep: () => {}; }
And the external method was called both times on button click.
Works with following code:
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
title = 'app';
loadScript(url) {
const body = <HTMLDivElement> document.body;
const script = document.createElement('script');
script.innerHTML = '';
script.src = url;
script.async = false;
script.defer = true;
body.appendChild(script);
}
ngOnInit() {
this.loadScript('../assets/scripts/index.js');
}
}
I'm trying to display an html and execute a script which are both stored in a string.
I have created a pipe which transform the string with the this.sanitizer.bypassSecurityTrustHtml() method.
Then, I inject the content of the string in the innerHtml attribute and combine it with my pipe.
You can execute it on stackblitz : https://stackblitz.com/edit/angular-uilj36
This is a part of my code :
safe.pipe.ts
import { Pipe, PipeTransform } from '#angular/core';
import { DomSanitizer, SafeHtml} from '#angular/platform-browser';
#Pipe({
name: 'safe'
})
export class SafePipe implements PipeTransform {
constructor(protected sanitizer: DomSanitizer) {}
transform(value: any, args?: any): any {
return this.sanitizer.bypassSecurityTrustHtml(value);
}
}
app.component.ts
import { Component } from '#angular/core';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
public html = '<div>Html content</div> <script>console.log("run js ok");</script>';
}
app.component.html
<h1>Code injection :</h1>
<div [innerHtml]="html | safe"></div>
The problem is that the script doesn't execute.
Anybody have an idea why the script is not executed ?
PS : I know that it's not recommended but someone asked me to do it :)
You could also use an iFrame instead of a div element. On the iFrame you can set the srcdoc property.
<iframe [srcdoc]="html | safe"></iframe>
it should display and run the html with its scripts.If you want to restrict the iframe you can use the sandbox property.
For your example it could look like this:
<iframe [srcdoc]="html | safe" sandbox="allow-scripts"></iframe>
iframes are made for such security things like executing scripts in an isolated environment.
I am trying to display dynamically html inside a div. However the div ng-bind-html does not display at all (on firefox, chrome and safari).
Looking at the other posts of this website I saw that I have to include ngSanitize.
I found this snippet here https://www.npmjs.com/package/angular-sanitize :
angular.module('myApp', ['ngSanitize']);
However I do not know where I should write this code ... Do you have any idea how I could do it ?
Thank you very much !
Here is my code :
Code in the component.ts:
import { Component, OnInit, SecurityContext } from '#angular/core';
import { DomSanitizer, SafeHtml } from '#angular/platform-browser';
#Component({
selector: 'app-player-filter',
templateUrl: './player-filter.component.html',
styleUrls: ['./player-filter.component.css']
})
export class PlayerFilterComponent implements OnInit {
text = '<h1>Test</h1><script></script>';
text_sanitized: SafeHtml;
constructor(private _sanitizer: DomSanitizer) { }
ngOnInit() {
this.text_sanitized = this.htmlProperty;
}
public get htmlProperty(): SafeHtml {
return this._sanitizer.sanitize(SecurityContext.HTML, this.text);
}
}
Code in the component.html:
<div ng-bind-html="text_sanitized"></div>
Normal: {{text}} Sanitized: {{text_sanitized}}
Output on firefox:
Normal: <h1>Test</h1><script></script> Sanitized: <h1>Test</h1>
Output console:
WARNING: sanitizing HTML stripped some content (see http://g.co/ng/security#xss).
The console output shows that the sanitizing operation happenned (confirmed by the output sanitized that got rid of the script).
Wierd thing, there is no error shown in the console from having unsafe html displayed...
The 'ng-bind-html' belongs to angularJS(older version before angular 2+) so its not suppose to work or display anything with Angular 6.
Use [innerHTML] instead as mentioned in Agular Documentation:
<div [innerHTML]="text_sanitized"></div>
I have used the Tile service of Angular, and title are getting set successfully.
Here is the code:
import { Component, OnInit } from '#angular/core';
import { Title } from '#angular/platform-browser';
#Component({
selector: 'app-homepage',
templateUrl: './homepage.component.html',
styleUrls: ['./homepage.component.css']
})
export class HomepageComponent implements OnInit {
constructor(private titleService: Title) { }
ngOnInit() {
this.titleService.setTitle('homepage first title');
}
}
but the problem is that when i check the title change through "view page source", none of the changes are getting reflected and the default title in index page is showing , what can i do to resolve this.
View page source is the plain index.html source file (like you have it on your/server file system). No JavaScript is executed or anything, so obviously nothing will show.
If you would like to have that the application is already compiled, take a look at NgUniversal, to leverage server side rendering. Not sure if that will work for your use-case though.