HTML not interpreted in Angular template - javascript

It has been several days since I am stuck on a problem that I do not see where it can come from.
I currently retrieve the content of my article in an observable and I loop over it in the angular template. So far I have no problem I get my information well that I display but the HTML is not interpreted with an innerHTML, nor with a pipe using the DomSanitizer.
I tried to store the information of my observable in a table to see if it does not come from the asynchronous but no.
I saw that it was necessary to use the DomSanitizer to force the security because when the string that contains the HTML is too long (which is my case because it is long paragraphs), the innerHTML has not no effect.
The string fits well in my pipe because when I make a console.log of my variable containing the string, it shows me well in my console with HTML tags around.
If you have any idea where my problem may come from, knowing that I have no errors in the console.
Here is my code without the pipe and HTML not interpreted :
<div *ngFor="let article of informationsArticle|async;">
<div [innerHTML]="article.contenu_part1" *ngIf="article.contenu_part1"></div>
</div>
With the pipe and HTML not interpreted:
<div *ngFor="let article of informationsArticle|async;">
<p [innerHTML]="article.contenu_part1 | keepHtml" *ngIf="article.contenu_part1"></p>
</div>
The pipe code :
import { Pipe, PipeTransform } from '#angular/core';
import { DomSanitizer } from '#angular/platform-browser';
#Pipe({ name: 'keepHtml', pure: false })
export class EscapeHtmlPipe implements PipeTransform {
constructor(private sanitizer: DomSanitizer) {
}
transform(content) {
return this.sanitizer.bypassSecurityTrustHtml(content);
}
}
I added it in "declarations" of app.module.ts file as well as its import at the top of the file.
Rendering the source code in the console :

Related

How can I dynamically load Angular components in subsections of a document being loaded as innerHtml?

I have an Angular component, "app-xml-content".
Within app-xml-content, I load some XML from an external source. I want to then highlight certain sections of that XML, and add a tooltip with some helpful information.
I have achieved this as follows:
<div id="xml-content" [innerHTML]="xmlString | customHighlight: criteria"></div>
My customHighlight pipeline will search the XML, and currently just does a RegEx replace:
const highlighter = (match) => `<mark class="highlight${diff.intensity}">${match}</mark>`;
if (diff.intensity) {
modifiedContent = modifiedContent.replace(new RegExp(pattern, 'gi'), highlighter);
}
But I would prefer for the highlighter to replace matches with a custom Angular component, rather than an HTML <mark />. E.g.
const highlighter = (match) => `<app-highlight intensity="${diff.intensity}" content="${match}"></app-highlight>`;
if (diff.intensity) {
modifiedContent = modifiedContent.replace(new RegExp(pattern, 'gi'), highlighter);
}
When I do this, the highlighted sections are simply not rendered.
I can see that the constructor for <app-highlight /> is not called.
I've investigated, and found ComponentFactoryResolver, but I don't really understand how to use it to render only the bits of the XML being replaced. Can I use the resolver in the pipe to resolve it to the AppHighlightComponent?
If someone can show me a pattern I can use that will help me in this, I'd really appreciate it.
Thanks.
One possible solution would be to create a web component from your angular component by using angular element. For this in your AppModule you need to add AppHighlight as an entry component, declare it as a custom element and the ngDoBootsrap method.
import { BrowserModule } from '#angular/platform-browser';
import { NgModule, DoBootstrap, Injector } from '#angular/core';
import { createCustomElement } from '#angular/elements';
import { AppHightlight } from 'path/to/AppHighlight';
#NgModule({
declarations: [
AppHighlight,
],
imports: [
BrowserModule,
],
entryComponents: [AppHighlight],
})
export class AppModule implements DoBootstrap {
constructor(private injector: Injector) {
const webComponent = createCustomElement(AppHighlight, {injector});
customElements.define('custom-app-highlight', webComponent);
}
ngDoBootstrap() {}
}
Then whenever custom-app-highlight is injected in the DOM, your browser will interpret it as your angular component.
<div>
<custom-app-highlight intensity="intensity string" content="content string" />
</div>
EDIT 1: Note that inputs for angular elements can't contain upper case and they should be strings
EDIT 2: removed the link to angular elements to give an implementation example with code

Angular wrapper of JS library doesn't load styles

I want to use this library https://bootstrap-datepicker.readthedocs.io/en/latest/markup.html#date-range in my application. But it has to be angular component so for the first time in my short career I wanted to create wrapper of library but I think I did something wrong becouse It doesn't looke like original picker.
This is how it should looks like:
And this is how it looks like as my angular component:
Also when I want to select only month or year it looks weird:
Ok so now time to see my component code:
import {AfterViewInit, Component, ElementRef, Input, OnInit} from
'#angular/core';
import 'bootstrap-datepicker';
declare var $;
#Component({
selector: 'cb-daterangepicker',
templateUrl: './daterangepicker.component.html',
styleUrls: ['./daterangepicker.component.scss']
})
export class DaterangepickerComponent implements OnInit, AfterViewInit {
#Input()
datepickerOptions: DatepickerOptions;
constructor(private elementRef: ElementRef) {
}
ngOnInit() {
}
ngAfterViewInit(): void {
// $(this.elementRef.nativeElement).datepicker();
$('.input-daterange input').each(function() {
$(this).datepicker('clearDates');
});
}
}
As You see there is no for example selection of range, or just start and end dates, it simply looks different so I thought it becouse not loaded styles but I might be wrong. I need Your help Guys, maybe my wrapper isn't correctly done?
*Network console with styles:
Addin styles to index.html and angular.json helped with some things:
But still range between dates is not highlighted..
Are you sure that bootstrap is correctly loaded ? you have to check this first and you have to check if the css for the library is loaded afterwards.
try to check that with the browser network console :)
othewise try to call the library style with the cdn :
https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.8.0/css/bootstrap-datepicker.min.css

AngularJs sanitizing and displaying html

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>

Title service in angular2

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.

Angular 2 Execute JS from file using AfterViewInit

Quite new to Angular 2, and after looking around for few hours I'd like to have some help.
I have a JS file with some generic functions. For example:
$(document).ready(function(){
$('[data-toggle="tooltip"]').tooltip();
});
This file contains in fact way more code. As you can imagine, I'd like to enable tooltips of all components. I can't simply include this file in index.html because subcomponents aren't present (yet) when the file is loaded.
After some digging, afterViewInit() came up. This post suggests to copy/paste JS code into ngAfterViewInit(). That's the ugly way (in my opinion)...
So here I come with 2 related questions:
1# Is there a way to execute JS code when a child component is loaded? For example, something like:
// In app.component.ts
ngAfterChildComponentLoaded(){
// JS code here
}
This solution is quite interesting because I'm not forced to implement ngAfterViewInit() with the same content in all my components. But is it possible?
2# Is there a way to import JS code instrad of copy/paste it into ngAfterViewInit()? I don't want copy/paste 300 lines of JS code into 15 differents components (for obvious reasons).
Thanks a lot for your help!
See the following for how to get external js files for a particular component in angular 2/4:
import { Component, OnInit , AfterViewInit} from '#angular/core';
import { Router } from '#angular/router';
declare var $: any;
#Component({
moduleId: module.id,
selector: 'dashboard',
templateUrl: './dashboard.html',
styleUrls: ['./dashboard.css']
})
export class DashboardComponent implements OnInit,AfterViewInit {
constructor() {}
ngOnInit() {
}
ngAfterViewInit(){
$.getScript('assets/assets/build/js/custom.min.js');
}
}
Got a less-ugly solution, if someone has a better one I'll gladly accept his answer!
ngAfterViewInit(){
$.getScript('assets/js/myscript.js', function(){});
}

Categories

Resources