angular click() event not working after rendering dynamic html - javascript

Few html elements loaded from server side and angular click() event also part of it. but event is not firing after rendering the elements. I understand that i need to notify the DOM. I can not do this.
component.ts
mport { Component} from '#angular/core';
#Component({
selector: 'app-root',
templateUrl: '../Views/Dashboard.html',
providers: []
})
export class DashboardComponent {
public deviceData="<div (click)="Go()">Click</div>"; //e.x: loaded from server
constructor(){
}
Go():void{
alert("Go");
}
}
html
<div [innerHTML]="deviceData"></div>

You can bind event using
<div class="classname" [innerHTML]="deviceData"></div>
this.deviceData = "<a herf='javascript:void(0);'>Click</a>";
ngOnInit()
{
var obj=this;
$(document).on('click', '.classname', function () {
obj.Go();
});
}
Go()
{
alert("Go");
}

A click function (or any Angular specific tag) to be rendered as html is not best practice. Try to only render bare basic html and put the click function in separately.

Related

How to create a custom event in Angular, within same component?

Is it possible to create a custom event in Angular, within same component?
I am trying to create a custom click event in "app.component.html" file:
<li (customClick) = "cClick($event)"> Test </li>
and then in the app.component.ts file:
cClick(e){ (alert("custom event clicked!"))}
How to achieve this calling within same component? Please help :)
footer component
#Component({
selector: 'a-footer',
template: `
<div>{{footerText}}</div>
<button ion-button (click)="doIt()">Footer Button</button>
`
})
export class AFooterComponent {
#Input() footerText:string
#Output() footerClicked = new EventEmitter()
doIt() {
this.footerClicked.emit({value:this.footerText})
}
}
home.page component create the event handler to be passed into footer component doFooterClicked
#Component({
selector: 'page-home',
templateUrl: 'app/home.page.html'
})
export class HomePage {
appName = 'Ionic App';
userCourse =[]
constructor(private navController: NavController) {
this.userCourse = [{CourseName:"course one"},{CourseName:"course two"}]
}
edit4(_someStuff) {
}
doFooterClicked(_event) {
console.log(_event)
alert("footer clicked "+ _event.value)
}
}
in the home.page html somewhere you create the component element
<a-footer [footerText]="'someText'"
(footerClicked)="doFooterClicked($event)">
</a-footer>`
<li (customClick) = "cClick($event)"> Test </li>
You have to create a directive, where you can listen to whatever event you want and trigger them in your custom output emitters
Angular2 Directive to modify click handling

Angular functions are performed twice when called in the html file

I tried to start an angular project, I've created a simple component and started a console.log in it but I have Confusing problem. when I calling a function in html file from ts file its run twice
TS:
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-hello',
templateUrl: './hello.component.html',
styleUrls: ['./hello.component.less']
})
export class HelloComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
log(val)
{
console.log(val);
}
test() {
let time = new Date()
console.log(time.getSeconds());
}
}
html :
hello works!
{{log('test')}}
{{test()}}
image log:
enter image description here
Where and how often do you call your component?
Can you produce a simple example on stackblitz?
Without any further info, we can just guess what it is.
You propably have called your component via '' twice.
Each instance will call all your template and hence its calling functions.

click event is not working in innerhtml string angular 6

I am working on an generate dynamic template using angular 6. I have an API that return strings like below:
<button type="button" (click)="openAlert()">click me</button>
and html
<div [innerHtml]="myTemplate | safeHtml">
</div>
function is bellow:
openAlert() {
alert('hello');
}
You cannot bind angular events directly to innerHTML.
Still if you need to attach the event listeners you need to to do it after the html content is loaded.
Once the content is set to the variable, ngAfterViewInit Angular life cycle event will be triggered. Here you need to attach the required event listeners.
Checkout the working example below.
component.html
<button (click)="addTemplate()">Get Template</button>
<div [innerHTML]="myTemplate | safeHtml"></div>
component.ts
import { Component, ElementRef } from '#angular/core';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
name = 'Angular';
myTemplate = '';
constructor(private elementRef:ElementRef){
}
openAlert() {
alert('hello');
}
addTemplate(){
this.myTemplate = '<button type="button" id="my-button" (click)="openAlert()">click mee</buttn>';
}
ngAfterViewChecked (){
if(this.elementRef.nativeElement.querySelector('#my-button')){
this.elementRef.nativeElement.querySelector('#my-button').addEventListener('click', this.openAlert.bind(this));
}
}
}
safe-html.pipe.ts
import { Pipe, PipeTransform } 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);
}
}
this should work too:
component.html
<div #template></div>
component.ts
#ViewChild('template') myTemplate: ElementRef;
addTemplate(){
this.myTemplate.nativeElement.innerHTML = '<button type="button">click me</button>';
this.myTemplate.nativeElement.addEventListener('click', this.openAlert);
}
Basically this will not work. When you write code in Angular, it is transpiled by webpack and converted to javascript that is executed in the browser.
However, now you are injecting Angular code dynamically and not building it. The event detection (click) would not work natively and the function openAlert is also not in the global scope where it is injected. You will have to consider a different approach and generate content using <ng-template> based on response from the API.

my javascript function does not load on initial page load

I'm building an app with an Angular2 frontend and a web API backend using the asp.net Angular2 template. I have an inline script in my index.html file that does not get loaded on the initial page load, but when i refresh the page it gets loaded. Below is the code.
<script>
$(function () {
$('.toggle-nav').click(
function () {
$('#body-holder').toggleClass('show-nav');
return false;
});
});
</script>
I tried loading it in my component.ts file within the ngOnInit function but i get a cannot find $ error when i try that.
import { Component, OnInit } from '#angular/core';
declare var $:any; // this is required
#Component({
selector: 'app-root',
template: `Something`
})
export class AppComponent implements OnInit {
ngOnInit() {
$('.toggle-nav').click(function () {
$('#body-holder').toggleClass('show-nav');
});
}
}

Angular 2 - Binding and Unbinding HostListener Events

I am attempting to bind and unbind a HostListener click event based on a component's input variable.
The component is a popup which has a single input called show. This input holds the active/inactive state of the popup. I would like to fire a click event on the entire document but only when the input show is set to true.
Is there a way to bind and unbind the hostlistener event inside the ngOnChanges function I have?
The current code I have:
import {Component, OnInit, Input, ViewEncapsulation, HostListener} from '#angular/core';
#Component({
selector: 'custom-popup',
templateUrl: './popup.component.html',
styleUrls: ['./popup.component.scss'],
encapsulation: ViewEncapsulation.None
})
export class PopupComponent implements OnInit {
#Input() show: boolean = false;
constructor() {
}
ngOnInit() {
}
#HostListener('document:click', ['$event.target'])
clickHandler(targetElement) {
// Custom code to handle click event
}
ngOnChanges(show: boolean) {
if (this.show) {
// Bind Click Event
}
else {
// Unbind Click Event
}
}
}
Any assistance and insight would be greatly appreciated.
To ensure that only 1 host listener is set up when a popup is shown, introduce a new child component PopupBody that has the host listener on it, and an #Output() to pass the event back up to the Popup component.
Then, in your template, make the PopupBody component conditional using *ngIf="show" and it should then only bind the host listener when the popup is shown, and unbind it when the popup gets hidden.
In the end I implemented a solution using a service. The service handles the click events on the document and uses an observable to enable components to subscribe to the event.
The popup component subscribes to the stateService click observable when it is opened and unsubscribes when it is closed.
Popup Component:
import {Component, OnInit, Input, ViewEncapsulation, HostListener} from '#angular/core';
import {StateService} from "../services/state.service";
import {Subscription} from "rxjs";
#Component({
selector: 'custom-popup',
templateUrl: './popup.component.html',
styleUrls: ['./popup.component.scss'],
encapsulation: ViewEncapsulation.None
})
export class PopupComponent implements OnInit {
#Input() show: boolean = false;
constructor(private stateService: StateService) {
}
ngOnInit() {
}
ngOnChanges(show: boolean) {
if (this.show) {
// Timeout to ensure subscription after initial click
setTimeout(() => {
// Subscribe to the document click service when the input opens
if (!this.clickSubscription || this.clickSubscription.closed) {
this.clickSubscription = this.stateService.documentClick$.subscribe(targetElement => {
// Logic for closing the popup
});
}
});
}
else {
// Remove the subscription when the input closes
if (this.clickSubscription && !this.clickSubscription.closed) {
this.clickSubscription.unsubscribe();
}
}
}
}
#GregL Thank you for your suggestions

Categories