angular 2 does not parse correctly html code - html

Trying to HTML code to view the resulting HTML using the innerHTML property, but as you can see in the example below, it doesn't. The HTML code is viewed as the HTML tags and only, instead of creating the elements it renders them as simple text.
https://codepen.io/Dralius/pen/OJzoZxm
#Component({
selector: 'my-app',
template: `
<span [innerHTML]='working'> </span>
<span [innerHTML]='notWorking'> </span>
`
})
class AppComponent {
working="<h1>hello world angular 6</h1>";
notWorking='<p> Random Text </p>'
constructor() {
// TODO: Define your Angular component implementation
}
}

an idea can be to parse the notWorking string into valid html with domparser (for sample) before inject it in innerHTML
https://codepen.io/jeremy-denis/pen/rNpZKzO?editors=1111
const { Component, VERSION } = ng.core;
#Component({
selector: 'my-app',
template: `
<span [innerHTML]='working'> </span>
<span [innerHTML]='notWorking'> </span>
`
})
class AppComponent {
working="<h1>hello world angular 6</h1>";
notWorking='<p> Random Text </p>'
constructor() {
this.notWorking = new DOMParser().parseFromString(this.notWorking, 'text/html').body.innerText;
}
}

This won't work just because of one little problem : It just won't. You are not using HTML tags, only the "symbols" of them. What is your problem exactly here? using < is mostly used for printing out the literal symbol on the page, not as HTML tag.

Related

Host Binding rearranges applied classes

I am using #HostBinding('class') to inject classes into the host element. The classes to be injected are generated based on user-supplied parameters. The problem I ran into and I could not find anyone else experiencing is that the classes are applied in an order different from the way I expected them.
For example, having a component defined below:
import {Component, HostBinding, Input} from '#angular/core';
#Component({
selector: '[icon]',
template: `
<ng-content></ng-content>
`
})
export class SuiIconComponent {
#Input() iconType = '';
#HostBinding('class')
get classes(): string {
return [this.iconType, 'icon'].join((' '));
}
}
When I apply the component like shown below:
<div icon iconType="car"></div>
And inspect, I see <div class="icon car"></div> instead of the appropriately formatted <div class="car icon"></div>.
I have tried reversing the array before joining but that did not help either.
Is there any way I get the classes to get rendered in the proper order?
Edit: I realized the classes are being rearranged in alphabetic order.
I'm not sure why angular changes the order, but you can solve your problem with little bit of change in your template.
#Component({
selector: 'icon',
template: `
<div [ngClass]="iconType + ' icon'">
<ng-content></ng-content>
</div>
`
})
export class SuiIconComponent {
#Input() iconType = '';
}
and use it as follows
<icon iconType="car">
Some content here
</icon>

Angular interpolate inside a component like mat-checkbox

So I want to have a mat-checkbox component with a HTML string inside the label.
I tried the following:
<mat-checkbox class="check">
{{ someHtml }}
</mat-checkbox>
But it prints the HTML string as a string and doesn't render it.
Using the following doesn't work either:
<mat-checkbox class="check" [innerHtml]="someHtml">
</mat-checkbox>
This just replaces the whole content, including the checkbox that gets generated at runtime. Is there any way to inject the html into the label?
You could use Angular Directives
The idea here is to fetch the element from the HTML, then append some raw HTML dynamically.
Supose this scenario
app.component.html
<mat-checkbox class="check" [appendHtml]="innerHtml"></mat-checkbox>
app.component.ts
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
innerHtml = `<div style="border: 1px solid red;"> Text inside </div>`;
constructor() {}
}
As you can see, I added a appendHtml attribute to the mat-checkbox element. This is a custom directive that expects a string as "raw" HTML.
append-html.directive.ts
#Directive({
selector: '[appendHtml]'
})
export class AppendHtmlDirective implements AfterViewInit {
#Input('appendHtml') html: string
constructor(private element: ElementRef) {
}
ngAfterViewInit() {
const d = this.element.nativeElement.querySelector('label');
d.insertAdjacentHTML('beforeend', this.html);
}
}
The AppendHtmlDirective expects an html property of type string and implements AfterViewInit interface (from Angular) to fetch the element once it is rendered. By injection, Angular provides us the element which is being applied; so, the ElementRef from the constructor is our MatCheckbox element, in that case.
We can use the insertAdjacentHTML function to append childs to the element. I just fetched the label element from the MatCheckbox to fit inside of it. In every case, you should see where to append the HTML.
I mean, label here works, bc MatCheckbox has a tag whitin matching that. If you want to reuse this Directive for other elements, you should be passing the literal to find inside.
i.e.:
append-hmtl.directive.ts
// ...
#Input() innerSelector: string
// ...
ngAfterViewInit() {
const d = this.element.nativeElement.querySelector(this.innerSelector);
d.insertAdjacentHTML('beforeend', this.html);
}
app.component.hmtl
<mat-checkbox class="check" [appendHtml]="innerHtml" innerSelector="label"></mat-checkbox>
Moreover, you can pass as many inputs as you need to customize the styling or behavior of your directive.
Cheers
I think you should just wrap everything in a div and put it on the outside.
<div>
<mat-checkbox class="check"> </mat-checkbox>
{{ someHtml }}
</div>

In Angular how do I dynamically wrap certain words in another html element?

I have this simple Angular Component:
#Component({
selector: 'my-component',
template: '<p>{{someString}}</p>',
})
export class MyComponent {
#Input() someString: string;
}
someString could be any string of any length. As an example, imagine that someString's value is :
"If you want my body and you think I'm sexy, come on, sugar, tell me so."
In that case the HTML generated by Angular would essentially be equivalent to:
<p>If you want my body and you think I'm sexy, come on, sugar, tell me so.</p>
How would I modify MyComponent so that it detects each occurrence of the word sexy in someString and have Angular wrap that word in another HTML element such as <b>. So in this example case it would generate something like:
<p>If you want my body and you think I'm <b>sexy</b>, come on, sugar, tell me so.</p>
What if I wanted to wrap every occurrence of the word sexy in an Angular Component instead of a native HTML Element? Would that necessitate a different approach?
You can try this :D
#Component({
selector: 'app-test',
template: `
<p [innerHTML]="stringFormatted()"></p>
`,
styles: []
})
export class TestComponent {
someString = "If you want my body and you think I'm sexy, come on, sugar, tell me so.";
stringFormatted() {
return this.someString.replace(/sexy/g, '<b>sexy</b>');
}
}
You can use the something like below - wherein after rendering the main sentence, you can replace the special word with a span element and apply a CSS class, say .special to that span tag.
import { Component, Input, ElementRef, AfterViewInit } from '#angular/core';
#Component({
selector: 'my-component',
template: '<p>{{sentence}}</p>'
})
export class MyComponent implements AfterViewInit {
#Input() sentence: string;
#Input() specialWord: string;
constructor(private el: ElementRef) {
}
ngAfterViewInit() {
this.el.nativeElement.innerHTML = this.el.nativeElement.
innerHTML.replace(new RegExp(`${this.specialWord}`, 'g'),
`<span class="special">${this.specialWord}</span>`);
}
}
To keep your code generic, you can use additional #Input() for special word.
In your application's styles.scss, you can define the CSS class .special.
.special {
font-weight: bold;
}
If you wonder why you can't use similar logic to replace the content of sentence by something like below:
this.sentence = this.sentence.replace(new RegExp(`${this.specialWord}`, 'g'),
`<span class="special">${this.specialWord}</span>`);
then, note that Angular will escape the HTML tags and they will appear as is in the output. So you will see something like this in the browser, instead of styled spans.
Hello, it's a <span class="special">beautiful</span> day and I am in a very <span class="special">beautiful</span> city
That's why, I had to resort to manipulating the innerHTML so that replacement is done after Angular has rendered the sentence to DOM.
This solution avoids using innerHTML and relies strictly on Angular constructs.
#Component({
selector: 'my-component',
template: `
<p>
<ng-container *ngFor="let segment of segments">
<span *ngIf="!segment.shouldBeBold()">segment.text</span>
<b *ngIf="segment.shouldBeBold()">segment.text</b>
</ng-container>
</p>
`,
})
export class MyComponent {
#Input() someString: string;
private wordsToBold = new Set(['sexy', 'body', 'sugar']);
get segments() {
const regex = this.makeRegex();
const segments = this.someString.split(regex);
return segments.map(segment => {
return { text: segment, shouldBeBold: wordsToBold.has(segment.toLowerCase()) };
});
}
private makeRegex() {
const expression = [...this.wordsToBold].join('\\b|\\b');
return new RegExp(`(\\b${expression}\\b)+`, 'gi');
}
}

Angular 6, a tag with href using #link links to base page not the current page

The issue I am currently facing is that the link generated by the a tag links to the base page. As you can see in the image it links to
localhost:3000#hello
My goal is to get it to link to
localhost:3000/bodyText#hello
The a tag will come from an external source so my test example mimics that. I have so far been using innerHTML directive to put the external html in the html template.
Here is the component I am working with
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-test',
template: '<div [innerHTML]=html></div>',
styleUrls: ['./test.component.css']
})
export class TestComponent implements OnInit {
constructor() {
}
html = "A tag <a name=\"hello\" id= \"hello\"/> "
ngOnInit() {
}
}
I solved this by adding a click handler to the html tag and then using scrollIntoView and getElementById instead of using an a tag.

how to change labeltext inside template in Angular 4

I am having a angular component here is my component
#Component({
selector: 'labelnumeric',
template: '<label>hello</label>'
})
here in template i am using hello as label text
and here component is defining in HTML control
here is my HTML
<labedate></labedate>
so on the basis of HTML control i want to change the label text how can i done this ?
is there is any possibility to set the name based on attributes ?
What you are looking for is #Input in your component
See the documentation here:
https://angular.io/guide/component-interaction
What you basically need todo is to import Input and then define an input property in your component
#Component({
selector: 'labelnumeric',
template: '<label>{{something}}</label>'
})
export class XYZ {
#Input() something: string;
}
and then you can use this like so in the html part
<labelnumeric [something]= "Text"></labelnumeric>
I think all you need is #input
#Component({
selector: 'labelnumeric',
template: `<label>{{numeric}}</label>`,
})
export class HelloComponent {
#Input() numeric: string;
}
Then use it like :
<labelnumeric numeric='10'></labelnumeric>
//OR
<labelnumeric [numeric]='your_varible'></labelnumeric>
WORKING DEMO (Basic Working demo of #input)