How many times does Angular 2 render a single page before showing it? - html

I'm using Angular 2 for my project. I have a simple div in my template which calls a function in my .ts file that outputs a simple text like this:
<div>{{ test() }}</div>
private test(): void {
console.log("Test text");
}
When I load a page I get the same output many times like this:
Test text
Test text
Test text
Test text
Test text
Does that mean that Angular 2 renders the template many times before it actually shows it and consequently calls function every time?

Angular renders the AppComponent and it's child components exactly once, except when you add remove parts of the DOM, then these added parts will be rendered again.
What you experience is Angulars change detection which runs quite frequently. See also Why event triggers ChangeDetection even if OnPush strategy is ON?.
It is usually a bad idea to use functions in value bindings because such functions will be called every time Angular runs change detection.
Prefer to assign the value to a property and bind to this property instead.
<div>{{ testVal }}</div>
ngOnInit() {
this.testVal = this.test();
}
private test(): string {
console.log("Test text");
return 'some string';
}

Yes It renders multiple time since ChangeDetectionStrategy is always "Default" means it check always(multiple times) for UI update
ChangeDetectionStrategy.OnPush
Use OnPush: OnPush means that the change detector's mode will be set to CheckOnce during hydration.
If you use ChangeDetectionStrategy.OnPush then it will print only once
changeDetection: ChangeDetectionStrategy.OnPush
https://angular.io/api/core/ChangeDetectionStrategy
https://plnkr.co/edit/lNXNsS?p=preview
Code Snippet
#Component({
changeDetection: ChangeDetectionStrategy.OnPush,
selector: 'my-app',
template: `
<div>
Check Console
<h2>{{print()}}</h2>
</div>
`,
})
export class App {
name:string;
constructor() {
this.name = `Angular! v${VERSION.full}`
console.log("Called Once")
}
print(): void {
console.log("I am printing only one time"):
}
}

Related

Display a link in dynamically obtained html text

I am dynamically obtaining a list of strings.I display it in angular using ngFor. But when displayed, certain strings include few hyperlinks ,but they are displayed as normal strings. I want the hyperlink distinguished like underlined.
Eg: Refer https://support.google.com/accounts/answer/abc?hl=en# to 'Create a Google Account' using email
If I get it right, its really simple and you can do that like this :
{{Text Variable}}
you can make a pipe, but this pipe must be used in a [innerHtml]
#Pipe({name: 'linkPipe'})
export class LinkPipe implements PipeTransform {
constructor(private _domSanitizer: DomSanitizer){}
transform(value: string): any {
if (value.indexOf("http")>=0)
{
//search the "link"
const link=value.match(/(http(s)?:\/\/.)?(www\.)?[-a-zA-Z0-9#:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9#:%_\+~#?&//=]*)?(\[.*\])?/)
if (link) //if has a link
{
const valueSplit=link[0].split('[') //check if is in the way:
//http://direccion[text to show]
value=value.replace(link[0],
"<a href='"+valueSplit[0]+"'>"+
(valueSplit[1]?valueSplit[1].slice(0,-1):valueSplit[0])+
"</a>")
}
}
return this._domSanitizer.bypassSecurityTrustHtml(value)
}
}
e.g. of use
<p [innerHTML]="'see the http://www.google.com[page of Google] for more information'|linkPipe "></p>
<p [innerHTML]="'http://www.google.com'|linkPipe"></p>
see stackblitz

Translate strings inside Angular Typescript code

Is it possible to translate strings inside the source code of a component in Angular6.
F. e.
window.confirm("HELP me");
I haven't found anything besides the normal translation for the HTML files (Angular Docs i18n).
Thank you in advance
You can use https://github.com/ngx-translate/i18n-polyfill until Angular i18n get built-in support for it, probably around version 9. The author is working on Angular i18n, so I think it is safe to trust his expectation that it will be close to the future feature in Angular i18n.
There is a lot of interesting information about the future of Angular i18n in this issue: https://github.com/angular/angular/issues/16477
i've tried a solution for that and it works, this how i managed it to translate my ngx-toaster alerts that are called inside my ts file, for example i have this:
ngOnInit() {
this.toastrService.success('created successfully', '');
}
i converted it to this
#ViewChild('test') myDivElementRef: ElementRef;
...
constructor(private toastrService: ToastrService) {}
ngOnInit() {
this.toastrService.success(this.myDivElementRef.nativeElement.outerHTML, '', {
enableHtml : true
});
and in my template, i create a div with #test reference
<h2 i18n="##testTitle" #test [hidden]="true">created successfully</h2>
In Material Angular 6:
import { locale as english } from './i19n/en';
import { locale as français } from './i19n/fr';
import { ToastrManager } from 'ng6-toastr-notifications';
Declaration
#ViewChild('espiontest') myDivElementRef: ElementRef;
in constructor
constructor(
public toastr: ToastrManager){
}
in your function or OnInt
this.toastr.successToastr(this.myDivElementRef.nativeElement.outerHTML, null, {enableHTML: true});
In html, this element {{'Add_Profil_application_lang.Creationeffectuée' | translate}} is translation in files ./i19n/en and ./i19n/fr
<pre>
<p [hidden]="true">
<span #espiontest>{{'Add_Profil_application_lang.Creationeffectuée' | translate}}
</span>
</p>
</pre>

(click) event not work in innerHtml string Angular 4

My function isn't called when I click the <a... tag.
I have the following code in my component:
public htmlstr: string;
public idUser:number;
this.idUser = 1;
this.htmlstr = `<a (click)="delete(idUser)">${idUser}</a>`;
public delete(idUser){
alert("id " + idUser);
}
My html
<div [innerHTML]="htmlstr"></div>
but the function delete isn't called and does not show the alert.
The <div... is created dynamically
If anyone face same issue and above all answer not working then try my trick :
In HTML :
<button onclick="Window.myComponent.test()"> test </button>
In component :
class
constructor(){
Window["myComponent"] = this;
}
test(){
console.log("testing");
}
Your main issue here, on-top of the things pointed out by #Matt Clyde and #Marciej21592, is that you're trying to dynamically add HTML code that needs to be compiled before it can be used (you're trying to bind to a method and variable).
Some ways of doing this can be seen here.
From the code you have supplied, however, there are much easier ways to accomplish what you are after. For starters, I would have that code in the HTML to begin with and hide/show it as needed with ngIf.
i use this method and its work
public htmlstr: string;
public idUser:number;
this.idUser = 1;
this.htmlstr = `<a id='innerHtmlClick'>${idUser}</a>`
this.htmlstr.querySelector(`innerHtmlClick`).addEventListener('click', () => {
this.delete(idUser);
});
public delete(idUser){
alert("id " + idUser);
}
EventListener listen the event bye using id of innerHtml
I assume that it is not a bug but rather Angular's security measure against XSS attacks - for more information I would suggest taking a look here https://angular.io/guide/security#sanitization-example
I somewhat also fail to understand why you insist on passing the event via string literal instead of just simply using:
<div>
<a (click)="delete(idUser)">${this.idUser}</a>
</div>
Your component has inner Html.
Angular will not allow events inside inner Html portions for security reasons. You can use Child components. to make events from inside of inner Html portions. Create a child component and put your html inside the child component and pass the data by using any angular events between parent and child using Input, Output features in Angular
I don't often use [innerHTML], but it looks like the template string you're using <a (click)="delete(idUser)">${idUser}</a> is referencing ${idUser} when you might have meant ${this.idUser}?
Below code snippet worked for me:-
In component :
ngAfterViewChecked () {
if (this.elementRef.nativeElement.querySelector('ID or Class of the Html element')) {
this.elementRef.nativeElement.querySelector('ID or Class of the Html element').addEventListener('click', this.editToken.bind(this));
}
}
inside constructor parameter:-
constructor( private readonly elementRef: ElementRef) {}
import { ElementRef } from '#angular/core';---> at the top of the file
implement 'AfterViewChecked'

Render CSS, either from #Input or object property

We have an RTF control in our main application (standalone) which also generates CSS classes, and HTML that uses these classes. This is being loaded via an API.
It's outputted like this:
.cs95E872D0{} .csCF6BBF71{font-weight:normal;font-style:normal;}
and the HTML is outputted like so:
<p class="cs95E872D0"><span class="csCF6BBF71">this is a test</span></p>
It's terribly formatted but I guess that's what you get with auto-generated stuff! We are unable to change the generation of this CSS/HTML so unfortunately this is what I have to work with.
I need to display this HTML on a page (easy enough with the [innerHTML] attribute) however when it comes to doing it with the CSS I can't seem to figure it out.
I've tried creating a new component:
import { Component, Input } from "#angular/core";
#Component({
selector: 'htmlrender',
template: `<span [innerHtml]="html"></span>`,
styles: ['{{styles}}']
})
export class TestComponent {
#Input() html: string;
#Input() styles: string;
}
However it gets rendered as this:
<htmlrender _ngcontent-c9="" _nghost-c11="" ng-reflect-styles=".cs95E872D0{} .csCF6BBF71{font">
<span _ngcontent-c11=""></span>
</htmlrender>
Which doesn't work. I've also just tried to render the CSS inside <style> tags but that doesn't seem to work.
If the output is always the same you can use a string.slice() and string.replace().
I did it like this:
this.str = '.cs95E872D0{} .csCF6BBF71{font-weight:normal;font-style:normal;}';
let slice = this.str.split(".", 3);
console.log('.' + slice[1]);
console.log('.' + slice[2]);
They output of slice[1] and slice[2] look like:
.cs95E872D0{}
.csCF6BBF71{font-weight:normal;font-style:normal;}

In angular2, how to call a function inside an element without mouse event?

Below is part of code in parent component, I already get the enable value from eventEmitter in its child component, which is enable=true.
<img src="{{currentImg}}" alt="Play Image not found" (click)="onMouseClick()">
<pause-button (isPauseBtnClicked)="enable = $event"></pause-button>
status is: {{enable}}
Then how can I assign a value for currentImg="someImg.png" after it listened the eventEmitter(enable=true)? Should I write a function? if so, how can I call that function in img tag without any mouse event?
I konw with mouse click event, things becomes easier, currentImg can be assign a value inside function.
onMouseClick() {
this.currentImg = this.clickedImg;
}
Look I don't know what you want to achieve. But writing this answer by thinking that you want to go with EventEmitter way without calling any mouseevent.
Note: Your expectation might be different. But It might help you out. If doesn't, kindly use it as a reference. I might have understood something completely different but purpose is not to guide you in wrong way
<img src="{{currentImg}}" alt="Play Image not found" (click)="onMouseClick()">
<pause-button (isPauseBtnClicked)="fire($event)"></pause-button><br>
status is: {{enable}}<br> // haven't played with status
{{currentImg}}
boot.ts
fire(arg) {
console.log('test start');
//this.animate.subscribe((value) => { this.name = value; });
this.currentImg=arg;
console.log(arg);
}
Working Plunker
PasueButton.ts
#Component({
selector: 'pause-button ',
template: `
________________________________________________________
<br>
I'm child
<br>
<img src="img path" (click)="clickMe()"/>
<= click the img
<br>
_____________________________________________________
`
,
})
export class PasueButton implements OnInit {
#Output() isPauseBtnClicked: EventEmitter = new EventEmitter();
constructor() {
console.log('Constructor called');
}
ngOnInit() {
console.log('onit strat');
}
clickMe()
{
this.isPauseBtnClicked.next('child Img path is copied');
}
}