Issue with Click event not working on dynamically added button in Angular 8

My goal is to dynamically add and remove product images when a user clicks the add or delete button on the screen. However, I am encountering an issue where the function is not being called when dynamically injecting HTML and binding the click event. Below is a simplified version of the code.

<div class="product_images">
          <div class="imageHeading">
                        <p>
                            Images
                        </p>
                    </div>
                    <div class="kt-form__group">
                        <div class="row">
                            <div class="col-lg-2 imageLabel">Main Image</div>
                            <div class="col-lg-3 imageLabel">Choose Image</div>
                            <div class="col-lg-2 imageLabel">Image</div>
                            <div class="col-lg-2 imageLabel">Actions</div>
                        </div>
                    </div>
                    <div class="imagesContainer" [innerHtml]="containerToAdd | sanitizeHtml">
                    </div>
                </div>

Ts file

// Angular
import { Component, OnInit, ElementRef, ViewChild, ChangeDetectionStrategy, OnDestroy, ChangeDetectorRef } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
// Material
import { SelectionModel, MatPaginator, MatSort, MatSnackBar, MatDialog, MatRadioButton } from '@angular/material';
import { ProductManagementService } from '../../../../../core/e-commerce/_services/product-management.service';
import { ToastrService } from 'ngx-toastr';
import { ViewEncapsulation } from '@angular/core';

@Component({
  selector: 'kt-product-edit',
  templateUrl: './product-edit.component.html',
  styleUrls: ['./product-edit.component.scss'],
  encapsulation: ViewEncapsulation.None
})
export class ProductEditComponent implements OnInit {

previewUrl : any = "/assets/media/images/noimage.jpg";
containerToAdd : string = "";

constructor(
    private products: ProductManagementService,
    private router: Router,
    private route: ActivatedRoute,
    private toastr: ToastrService,
    private cdr: ChangeDetectorRef,
    private FB: FormBuilder,
    ) {

    }
 ngOnInit() {
    this.addImage();
}
addImage(){
     this.containerToAdd = `
      "<div class="kt-form__group image-container container-1">
          <div class="row">
              <div class="col-lg-2"><input type="checkbox" /></div>
              <div class="col-lg-3"><input type="file" accept="image/*" (change)="imagePreview($event)" /></div>
              <div class="col-lg-2"><img [src]="previewUrl" class="prod_image" /></div>
              <div class="col-lg-2">
                  <span class="deleteElement" (click)="deleteImage()">
                    Del
                  </span>
              </div>
          </div>
      </div>"`;
  }
  deleteImage() {
    console.log("deleteImage");
  }
}

Unfortunately, when clicking the span with the deleteImage() click event, the function is not being called.

Answer №1

When binding to the innerHtml, keep in mind that any angular syntax within the html won't function correctly as it's not a compiled angular template. Therefore, your click binding will be considered invalid. It would be best to utilize a simple *ngIf instead.

<div class="product_images">
    <div class="imageHeading">
        <p>
            Images
        </p>
    </div>
    <div class="kt-form__group">
        <div class="row">
            <div class="col-lg-2 imageLabel">Main Image</div>
            <div class="col-lg-3 imageLabel">Choose Image</div>
            <div class="col-lg-2 imageLabel">Image</div>
            <div class="col-lg-2 imageLabel">Actions</div>
        </div>
    </div>
    <div class="imagesContainer" [innerHtml]="containerToAdd | sanitizeHtml">
        <div class="kt-form__group image-container container-1" *ngIf="addImage">
            <div class="row">
                <div class="col-lg-2">
                    <input type="checkbox" />
                </div>
                <div class="col-lg-3">
                    <input type="file" accept="image/*" (change)="imagePreview($event)" />
                </div>
                <div class="col-lg-2"><img [src]="previewUrl" class="prod_image" /></div>
                <div class="col-lg-2">
                    <span class="deleteElement" (click)="deleteImage()">
                    Del
                  </span>
                </div>
            </div>
        </div>
    </div>
</div>
export class MyComponent{
previewUrl : any = "/assets/media/images/noimage.jpg";
public addImage = false

  constructor(
    private products: ProductManagementService,
    private router: Router,
    private route: ActivatedRoute,
    private toastr: ToastrService,
    private cdr: ChangeDetectorRef,
    private FB: FormBuilder) {
  }

  ngOnInit() {
    this.addImage();
  }

  addImage(){
     this.addImage = true;
  }

  deleteImage() {
   this.addImage = false
    console.log("deleteImage");
  }
}

EDIT 1:

<div class="product_images">
    <div class="imageHeading">
        <p>
            Images
        </p>
    </div>
    <div class="kt-form__group">
        <div class="row">
            <div class="col-lg-2 imageLabel">Main Image</div>
            <div class="col-lg-3 imageLabel">Choose Image</div>
            <div class="col-lg-2 imageLabel">Image</div>
            <div class="col-lg-2 imageLabel">Actions</div>
        </div>
    </div>
    <div class="imagesContainer">
        <div class="kt-form__group image-container container-1" *ngFor="let image of images; let index = i">
            <div class="row">
                <div class="col-lg-2">
                    <input type="checkbox" />
                </div>
                <div class="col-lg-3">
                    <input type="file" accept="image/*" (change)="imagePreview($event, image)" />
                </div>
                <div class="col-lg-2"><img [src]="previewUrl" class="prod_image" /></div>
                <div class="col-lg-2">
                    <span class="deleteElement" (click)="deleteImage(i)">
                    Del
                  </span>
                </div>
            </div>
        </div>
    </div>
</div>
export class MyComponent{
previewUrl : any = "/assets/media/images/noimage.jpg";
public images = []

  constructor(
    private products: ProductManagementService,
    private router: Router,
    private route: ActivatedRoute,
    private toastr: ToastrService,
    private cdr: ChangeDetectorRef,
    private FB: FormBuilder) {
  }

  ngOnInit() {
    this.addImage();
  }

  addImage(){
     this.images.push({});
  }

  deleteImage(index: number) {
    this.images.splice(index, 1)
    console.log("deleteImage");
  }

  imagePreview($event, image){
    image.path = event.value;
  }
}

Answer №2

In my opinion, incorporating some additional code can be beneficial:

html:

<div class="product_images">
  <div class="imageHeading">
    <p>
      Images
    </p>
  </div>
  <div class="kt-form__group">
    <div class="row">
      <div class="col-lg-2 imageLabel">Main Image</div>
      <div class="col-lg-3 imageLabel">Choose Image</div>
      <div class="col-lg-2 imageLabel">Image</div>
      <div class="col-lg-2 imageLabel">Actions</div>
    </div>
  </div>
  <div class="imagesContainer" #elementRef>
  </div>
</div>

ts:

@ViewChild("elementRef", { static: true }) deletableItem: ElementRef<
    HTMLDivElement
  >;
  containerToAdd: any;

  previewUrl: any;

  constructor(private sanitizer: DomSanitizer, private renderer: Renderer2) {}

  ngOnInit() {
    this.addImage();
  }

  ngAfterViewInit() {}

  addImage() {
    // Functionality to add image dynamically
  }

  deleteImage() {
    console.log;
  }

Visit the stackblitz link for more details.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Sending state information through props in a Vuex environment

One of the challenges I am facing is how to make a reusable component that can display data from the store. My idea is to pass the name of the store module and property name through props, as shown below: <thingy module="module1" section=" ...

Getting access to scope variables in an Angular controller written in ES6 style can be achieved by using

In my new Angular project, I decided to switch to using ES6 (Babel). However, I encountered an issue where ES6 classes cannot have variables. This led me to wonder how I could set my $scope variable now. Let's consider a simple controller: class Mai ...

What causes the non-reachable part of the ternary operator to be evaluated prior to updating the state with setTimeout?

Check out my latest code snippet for a react component that renders a massive component. While the huge component is still rendering, a loading indicator will be displayed. import * as React from "react"; import ReactDOM from "react-dom"; import {HUGECom ...

Enhancing State Management with Multiple @Select Decorators in NGXS

I have a variety of @Selects within a component structured like this: @Select(ItemState.getMode) mode: Observable<Item>; @Select(QuestionState.SingleQuestion) question: Observable<Question>; @Select(ItemState.getItemNames) itemNames: Observabl ...

Customized Bootstrap Dropdown with the ability to add text dynamically

I am working on a Bootstrap dropdown menu that allows users to generate expressions by clicking on the menu items. For example, when the "Action" item is clicked, it should insert {{Action}} into the textbox. The user can then type something like "Hello" a ...

Tips on sorting a nested array in a React TypeScript project

Hey there! I currently have a working filter in React that utilizes a List (I am using Mantine.dev as my CSS template): <List> {locations.filter(location => { const locServices: Service[] = []; location.services.forEach(service => { ...

The i18n feature in Nuxt 3 retrieves language locales from an external API

While working on my Nuxt 3 app, I encountered an issue when trying to integrate i18n. Despite conducting extensive research, I couldn't find any helpful information, hence I have a question. I am utilizing i18n with Prismic CMS. The locales array is s ...

Encountering a 500 error while trying to access the document page in a Next.js Vercel app after

I am facing an issue with my next.js app hosted on Vercel, where I keep receiving a 500 error when trying to load a specific page. Upon inspecting the Chrome dev tools, I noticed that the error occurs when attempting to access the /dashboard page. Despite ...

Is it possible to create an online game using JavaScript?

Hey there, I'm interested in creating a simple online game that can be played in the browser. My main question is this: if I want two players to compete against each other online, can I achieve this by using HTML for the front-end and JavaScript for t ...

Merging the functions 'plainToClass' and 'validate' into a single generic function in NodeJs

Here's the issue I'm facing: export const RegisterUser = async (request: Request): Promise<[number, UserResponse | { message: any }]> => { let userRequest = plainToClass(UserRequest, request.body); let errors = await validate(u ...

Python Selenium not registering button click

I'm working on scraping data from the website using Python with Selenium and BeautifulSoup. This is the code I have: driver = webdriver.Chrome('my file path') driver.get('https://www.ilcollege2career.com/#/') first_click = Web ...

Attempting to automate the process of clicking a button on a webpage using cefsharp

Hello, I am currently working with cefsharp and vb.net to develop a code that will help me navigate to the next page of a specific website. The website link is: https://www.recommendedagencies.com/search#{} My goal is to extract the list of company names ...

What are some javascript libraries that can be used to develop a mobile image gallery for both Android and iPhone

I currently have the touch gallery system in place, but unfortunately it isn't functioning properly on Android devices. ...

What is the method for assigning classes to a Vue.js Functional Component from its parent component?

Imagine a scenario where I have a functional component: <template functional> <div>Some functional component</div> </template> Now, when I render this component within a parent element with classes: <parent> <som ...

Exploring the method to retrieve data on the server side through Express when it is shared by the client within a put request

Here is the angular http put request I am working with: sendPutRequest(data) : Observable<any>{ return this.http.put("http://localhost:5050", data).pipe(map(this.handleData)); } After making this call, the server side method being invoked is ...

How can Vue be used to dynamically change the input type on focus?

What Vue method do you recommend for changing an input element's type on focus? e.g. onfocus="this.type = 'date'" I am specifically looking to switch the input type from text to date in order to utilize the placeholder property. ...

Differences in jQuery selector behavior when targeting elements in parent windows compared to popup windows

In order for my userscript to function correctly, I have implemented a temporary solution. To create code that is easier to understand and maintain, it's essential for me to gain a deeper understanding of WHY the temporary fix works. Here is some code ...

Tips on completing landing page animations and displaying the main page of a website by utilizing React JavaScript

https://i.stack.imgur.com/M4VgY.pngIs there a way to stop the landing page animation after 2-3 seconds and show the main page instead? Can I achieve this by using setTimeOut function in JavaScript? [ export default Loader; ...

The parameter type cannot be assigned an undefined argument

I am new to TypeScript and trying to check if an item already exists. However, when I define the previous variable, I'm encountering an error: "Argument of type '(prev: CartItemsType[]) => CartItemsType[] | undefined' is not assignable to ...

Having trouble with the Angular router link suddenly "failing"?

app.routes.ts: import { environment } from './environment'; import { RouterModule } from "@angular/router"; import { ContactUsComponent } from './static/components/contact-us.component'; import { HomeComponent } ...