Angular Inject custom tag in innerHTML - html

Text with custom tag to inject inside innerHtml:
const test = '<FREEZE> the image. Then try again.'
<td [innerHtml]="test | htmlEscape"></td>
I am using a custom pipe to disable Angular's built-in sanitization for the provided value.
custom-pipe.ts
#Pipe({
name: 'htmlEscape'
})
export class HtmlEscapePipe implements PipeTransform {
constructor(private sanitizer: DomSanitizer) {
}
transform(content: string): SafeHtml {
if (!content) {
return null;
}
const t = this.sanitizer.bypassSecurityTrustHtml(content);
return t;
}
}
Unfortunately <FREEZE> tag inside the string is stripped out. Any suggestions would be appreciate it.

Related

DomSanitizer doesn't parse text to HTML

I am working on an Angular project and I am taking data from a database where it has data with HTML tags. To put it in the HTML I can do that through this code:
[innerHTML]="element.texto"
What Im looking for is to use it on the ts to put the text on a pdf. Im using DomSanitizer but the output is wrong and does not transform it on the HTML. This is the exaple code im using:
import { DomSanitizer } from "#angular/platform-browser";
///
constructor(
private sanitizer:DomSanitizer
) { }
dataTransformer() {
let textoHTML = "<p>Hello <b>World</b></p>"
alert(this.sanitizer.bypassSecurityTrustHtml(textoHTML)) //It shows: SafeValue must use [property]=binding: <p>Hello <b>World</b></p> (see http://g.co/ng/security#xss)
}
In the other hand, I have used the following code for parseing the code but with a wrong solution.
this.sanitizer.bypassSecurityTrustHtml(textoHTML)['changingThisBreaksApplicationSecurity'] //It shows: <p>Hello <b>World</b></p>
What im looking for is: Hello World
Thanks!
you can use pipe
[innerHTML]="element.texto | safeHtml "
import { Pipe, PipeTransform } from '#angular/core';
import { DomSanitizer, SafeHtml } from '#angular/platform-browser';
#Pipe({
name: 'safeHtml',
pure: false
})
export class SafeHtmlPipe implements PipeTransform {
constructor(protected sanitizer: DomSanitizer) {
}
transform(value: any): SafeHtml {
return this.sanitizer.bypassSecurityTrustHtml(value);
}
}
#erfan-farhadi has given a reusable code.
Use the following as quick fix
Change your ts file to something like this
import { DomSanitizer } from "#angular/platform-browser";
sanitizedValue: undefined; // member var to hold sanitized HTML
constructor(
private sanitizer:DomSanitizer
) { }
dataTransformer() {
let textoHTML = "<p>Hello <b>World</b></p>"
this.sanitizedValue = this.sanitizer.bypassSecurityTrustHtml(textoHTML));
}
/// ...
In html template use like following
[innerHTML]="sanitizedValue"

How to create HTML in angular?

I have been working on React for a year. Now, I am writing angular. How can I create a piece of html code in ts.file?
In react, I do it that way:
const example = (item: string): React.ReactNode => {
return <p> something.... {item} </p>
}
I want to do same thing in Angular8+
I know some way to do it. For example:
const example2= (name: string): string => {
return `
<div>
<p>heyyy ${name}</p>
</div>
`;
};
Are there any other ways to do it?
In Angular, there are a couple of ways to do this. If you need to generate HTML in the typescript and then interpolate it into the template, you can use a combination of the DomSanitizer and the innerHTML attribute into other elements (for example a span).
Below would be an example of what I suggested above:
hello-world.component.ts:
#Component({
selector: "hello-world",
templateUrl: "./hello-world.component.html",
styleUrls: ["./hello-world.component.scss"]
})
export class HelloWorld {
innerHTML: string = `<p>Hello, world!</p>`;
}
sanitze.pipe.ts:
#Pipe({
name='sanitize'
})
export class SanitizePipe {
constructor(private sanitizer: DomSanitizer) { }
transform(value: string): SafeHtml {
return this.sanitizer.bypassSecurityTrustHtml(value);
}
}
hello-world.component.html:
<div [innerHTML]="innerHTML | sanitize"</div>

Angular - Dynamically load html that includes angular markups

In Angular 9+ I can successfully convert a string to a html and then load that that html using innerHtml and bypassSecurityTrustHtml().
My question is it possible to also dynamically load/render the converted html to include and recognise angular/javascript markup language eg *ngIf, handle bars and click events.
Below is the code and stackblitz at the attempt so far but as you can see it doesn't recognise the markup.
https://stackblitz.com/edit/dynamic-angular?file=app/app.component.ts
export class AppComponent implements OnInit {
text: string = "Hello world";
content: any;
constructor(private domSantizer: DomSanitizer) {}
ngOnInit() {
let body: any =
'<div>{{text}}<div><br><button (click)="test()">Test</button>';
this.content = this.domSantizer.bypassSecurityTrustHtml(body);
}
test() {
alert("It works");
}
}
Html
<div [innerHTML]="content"></div>
I have researched and tried many solutions.
My research and trial results are below.
html
<div #container></div>
typescript side as below
export class AppComponent implements OnInit {
#ViewChild("container", { read: ViewContainerRef })
container: ViewContainerRef;
constructor(private compiler: Compiler) {}
text: string = "asdasd";
ngOnInit() {
this.addComponent(
`<div>{{text}}<div><br><button (click)="test()">Test</button>
`,
{
text: "Hello word",
test: function() {
alert("It's work");
}
}
);
}
private addComponent(template: string, properties?: any = {}) {
#Component({ template })
class TemplateComponent {}
#NgModule({ declarations: [TemplateComponent] })
class TemplateModule {}
const mod = this.compiler.compileModuleAndAllComponentsSync(TemplateModule);
const factory = mod.componentFactories.find(
comp => comp.componentType === TemplateComponent
);
const component = this.container.createComponent(factory);
Object.assign(component.instance, properties);
// If properties are changed at a later stage, the change detection
// may need to be triggered manually:
// component.changeDetectorRef.detectChanges();
}
demo
some posts I have reviewed
compile dynamic Component
angular-html-binding
I think it makes the most sense :)

Convert stored string that contain html tag into html text formatting

I have an Angular project that stores data inside firebase. The data is stored as string (prdName: string;) inside the database. I want to ask if is it possible if i put a html tag inside the string like <b>this is text</b> and store it and then bind/view them as html text format? (the text become bold)
//service.ts
getData() {
this.List = this.firebase.list('Product');
return this.List;
}
insertProduct(Product: Product) {
this.productList.push({
prdName: Product.prdName,
prdCategory: Product.prdCategory,
prdSup: Product.prdSup,
prdImage: Product.prdImage,
prdDescription: Product.prdDescription
});
}
//component.ts
ngOnInit() {
var x = this.ListService.getData();
x.snapshotChanges().subscribe(item => {
this.List = [];
item.forEach(element => {
var y = element.payload.toJSON();
y["$prdKey"] = element.key;
this.List.push(y as List);
});
});
}
<!--component.html-->
<label>Product Name: </label> {{ListService.selectedProduct.prdName}}
Please let me know if more snippets are needed. Thank you very much in advance.
You have to use innerHtml to bind html tags :
<div [innerHTML]="ListService.selectedProduct.prdName"></div>
Check this : https://angular.io/guide/template-syntax#!#property-binding-or-interpolation-
I used such pipe in my project to make it work right
import { PipeTransform, Pipe } from '#angular/core';
import { DomSanitizer } from '#angular/platform-browser'
#Pipe({ name: 'safeHtml'})
export class SafeHtmlPipe implements PipeTransform {
constructor(private sanitized: DomSanitizer) {}
transform(value) {
return this.sanitized.bypassSecurityTrustHtml(value);
}
}
then in the place where you want to have your html you simply do
<div [innerHTML]="someHtmlContent | safeHtml"></div>
pipe is needed to make this html content trusted, more information about this:
https://angular.io/guide/security#bypass-security-apis

Angular 5 DomSanitizer with Hyperlinks

I am using a WYSIWYG editor (CKEditor) and trying to render the content with Angular 5.
What I am trying to figure out is the proper way to use DomSanitizer in Angular 5. The problem I am facing is that Hyperlinks are not working (are not "clickable") in the resulting sanitized HTML.
I am using the following Typescript code to return a safeHtml content:
public getSafeContent(): SafeHtml {
return this.sanitizer.bypassSecurityTrustHtml(this.page.content);
}
and using it in my template this way:
<div [innerHTML]="getSafeContent()"></div>
This will render the HTML with all inline styles intact, but hyperlinks won't work.
I tried doing this instead:
public getSafeContent(): SafeHtml {
return this.sanitizer.sanitize(SecurityContext.HTML, this.page.content);
}
Which results in that Hyperlinks actually works, but inlines styles are not.
Is there a way to get both styles and hyperlinks to work with sanitized content?
Update
This is what the page looks like in Chrome dev tools:
<div _ngcontent-c22="" class="row">
<div _ngcontent-c22="" class="col-lg-12">
<div _ngcontent-c22="">
<p>google</p>
</div>
</div>
</div>
and the google link is not clickable.
bypassSecurityTrustHtml allows <script> tags in the content. For URLs you need bypassSecurityTrustUrl. See here: https://angular.io/api/platform-browser/DomSanitizer#bypassSecurityTrustUrl.
I've never tried stacking the bypassXXX methods, so I don't know if you can do something like this bypassSecurityTrustUrl(bypassSecurityTrustHtml(myContent)) but I would guess probably not since each method takes a string but returns an object (of type SafeHtml/SafeUrl), so it can't be used as the input to the stacked function call which expects a string.
So, you may need to parse the contents, pass each URL into the bypassSecurityTrustUrl and then combine everything back together again.
Update
I just looked at the sanitize method. I haven't tried this, but something like this might work:
this.sanitizer.sanitize(SecurityContext.HTML, this.sanitizer.bypassSecurityTrustUrl(myContent));
since sanitize can take a SafeValue as an input. The inner bypassSecurityTrustUrl sanitizes the URLs and returns a SafeUrl, which is unwrapped by the outer sanitize and used as input to make it HTML safe. Like I said, I haven't tried it, but it looks good in theory...
in .ts pipe for 'URL' sanitizer
import { Component, Pipe, PipeTransform } from '#angular/core';
import { DomSanitizer } from '#angular/platform-browser';
#Pipe({ name: 'sanitizeUrl' })
export class SafeUrlPipe implements PipeTransform {
constructor(private sanitizer: DomSanitizer) {}
transform(url) {
return this.sanitizer.bypassSecurityTrustResourceUrl(url);
}
}
in .html
<div [innerHTML]="Content | sanitizeUrl| sanitizeHtml">
</div>
pipe for 'HTML' sanitizer
import { Component, Pipe, PipeTransform } from '#angular/core';
import { DomSanitizer } from '#angular/platform-browser';
#Pipe({
name: 'sanitizeHtml'
})
export class SafeHtmlPipe implements PipeTransform {
constructor(private sanitized: DomSanitizer) {}
transform(value) {
return this.sanitized.bypassSecurityTrustHtml(value);
}
}
Please consider the above solution. this will apply both pipes without disturbing any style and link click event at same time
I used DOMPurify library to sanitize the DOM. DOMPurify is a DOM-only, super-fast, uber-tolerant XSS sanitizer for HTML, MathML and SVG.
I created angular PureTextPipe pipe to sanitize the raw content
import { Pipe, PipeTransform } from '#angular/core';
import DOMPurify from 'dompurify';
#Pipe({
name: 'pureText',
pure: true
})
export class PureTextPipe implements PipeTransform {
transform(str: any): any {
let res = str;
if (str === null || str === undefined || str === '' || str === 0) {
res = '--';
}
return DOMPurify.sanitize(res);
}
}
Now to use this pipe you just need to add it to HTML like:
<div [innerHTML]="yourRawData | pureText"></div>
Documentation of DOMPurify at
https://www.npmjs.com/package/dompurify
import DOMPurify from 'dompurify';
var clean = DOMPurify.sanitize(dirty);
I have found a working solution to this. With this both the URL and the style would work. It is again with the use of "bypassSecurityTrustHtml". It's surprising how using this in html or TS does not make the link work, but using this in a seperate file as a pipe makes this work like a charm.
Here is what I did
Create a Custom Pipe
.safe.dom.pipe
import { Component, Pipe, PipeTransform } from '#angular/core';
import { DomSanitizer, SafeHtml, SafeResourceUrl, SafeScript, SafeStyle, SafeUrl } from '#angular/platform-browser';
#Pipe({
name: 'safeDom'
})
export class SafeDomPipe implements PipeTransform {
constructor(private sanitizer: DomSanitizer) {}
public transform(value: any, type: string): SafeHtml | SafeStyle | SafeScript | SafeUrl | SafeResourceUrl {
switch (type) {
case 'html': return this.sanitizer.bypassSecurityTrustHtml(value);
case 'style': return this.sanitizer.bypassSecurityTrustStyle(value);
case 'script': return this.sanitizer.bypassSecurityTrustScript(value);
case 'url': return this.sanitizer.bypassSecurityTrustUrl(value);
case 'resourceUrl': return this.sanitizer.bypassSecurityTrustResourceUrl(value);
default: throw new Error(`Invalid safe type specified: ${type}`);
}
}
}`
In Case you have a common module in your project that is included where you require to implement it, you can declare and export this package from there. Else just declare this pipe in the module you want to implement this.
import { SafeDomPipe } from './pipes/safe.dom.pipe';
#NgModule({
imports: [
.....
],
exports: [
....
SafeDomPipe
....
],
declarations: [
....
SafeDomPipe
....
])
Now in Html you can directly use this pipe.
<div [innerHtml]="data | safeDom: 'html' "> </div>
This would allow both link and style.
If you're data content is consisting of HTML with Hyperlinks. But we want to sanitize with hyperlink working. This worked for me:
HTML
<div [innerHTML]="getSafeContent()"></div>
TS:
public getSafeContent(): SafeHtml {
return this.sanitizer.sanitize(SecurityContext.HTML, this.page.content);
}
This works for me:
Component:
content = '<b>Hello World</b><p style=\'font-size:14pt\'>
<a href=\'http://www.google.com\'>Go to Google</a></p>Test123';
public getSafeContent(): SafeHtml {
return this.sanitizer.bypassSecurityTrustHtml(this.content);
}
HTML:
<div [innerHTML]="getSafeContent()"></div>
Link works and inline styles are intact