1

I have a pop-up with 2 buttons, Update and Delete. When the Update button is pressed, I want to make the initial pop-up disappear and a new pop-up appear populated with the same fields but editable with another 2 buttons at the bottom, Confirm and Delete.

I want to configure the code for the Update pop-up in a separate method and call it from the HTML button when the Update button is pressed

How do I call the desired method (myFunction) from the HTML written inside the TypeScript Component at the button component?

 private initMap(): void {
    this.map = L.map('map', {
      center: this.centroid,
      zoom: 2.8
    });

    this.tiles = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', 
    {
      minZoom: 2.8,
      attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
    });

    this.tiles.addTo(this.map);
    
    this.powerPlantService.getAll().subscribe((data: any)=>{
      console.log(data);
      this.geoJsonFeature = data;
      
      L.geoJSON(data, {onEachFeature: myOnEachFeatureMethod}).addTo(this.map)

    }) 

    function myOnEachFeatureMethod(feature:any, layer:L.GeoJSON)
    {
      
        layer.bindPopup(
          "Power Plant Id: " + feature.properties.xxx +
          "<br>Power Plant Name: " + feature.properties.xxxx +
          '<div style="text-align:center"> '+

          //below in the button i want to call the myFunction method. How do I do that?
          '<br><button type="button" class="btn btn-primary" style="margin-right: 5px" data = "' + feature.properties.xxx + '" ' + '>Update</button>' + 

          '<button type="button" class="btn btn-danger" style="margin-left: 5px" data = "' + feature.properties.xxxx + '" ' + '>Delete</button>'   +
          '</div>'
          );  
    }  
  }  
 
  myFunction(layer: any) {
    console.log("Yeet");
    layer.bindPopup("Yeet");
  }

This is the pop-up displayed when the map pin is clicked

enter image description here

8
  • Have you tried to just add a regular onclick event? <button onclick="myFunction()">Update</button> Probably it won't work as this function should be defined in a regular javascript file and then included in your project like this: websparrow.org/angular/…. It's probably not what you want to achieve though. I believe, the template you provide will just be interpreted as regular html and won't be compiled by Angular. Commented May 23, 2022 at 16:57
  • I did, I just get this error: "Uncaught ReferenceError: myFunction is not defined onclick home.component.css:1" . I tried with onclick and other ways such as creating a form and using input type and in that situation it just wouldn't do anything. I'm running out of ideas and think I should just take the HTML code and move it to the HTML component and refactor the whole component. Commented May 24, 2022 at 6:31
  • 1
    The 'problem' is that Leaflet is rendering the text which you provide within the bindPopup and not Angular. You provide regular html code, which is correctly interpreted by the browser, but it doesn't have any clue where to find these javascript functions. All your code written within an Angular component is recompiled and isolated by Angular. So you can't access this from regular html. Commented May 24, 2022 at 7:30
  • In order to trigger javascript from within the popup, you'll probably have to declare a regular script file where you bind the function to the window object, include it in the assets, and add it to your angular.json. But still, you want be able to access any code within the component from within this script file, unless you define a global observable through rxjs, also bind to the window object, and subscribe to it within the component. Not 100% sure it will work, but it sounds reasonable. Commented May 24, 2022 at 7:30
  • For some reason it looks for it in the .css component, as it says when it throws the error. Could you please help me with the code you explained because this is my first experience with Angular/Javascript. I work exclusively with Java and this has been a nightmare for me so far, lol. Commented May 24, 2022 at 7:54

1 Answer 1

1

In order to pass messages to the component from the button click event, we will use use normal javascript file and include it in the angular.json.

We also need rxjs declared on the window object. rxjs which is installed within Angular through npm isn't though, so we include a cdn script file in the head of the index.html file.

src/index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    ....
    <script type="text/javascript" src="https://unpkg.com/rxjs@%5E7/dist/bundles/rxjs.umd.min.js"></script>
  </head>
  <body>
    <app-root></app-root>
  </body>
</html>

Create a custom.js file within the /src/assets/js folder, and create a new RxJS Subject and also declare the function you want to call. Within that function just call next on the subject to emit a new event/message.

src/assets/js/custom.js

var my_custom_subject = new rxjs.Subject()
function myFunction() {
  my_custom_subject.next('hello from custom')
}

In order the render this script within your application, you can either include it in the head tag as well or include it within the scripts array in the angular.json file. It's either the head tag or either in the configuration file, otherwise it will try to declare the my_custom_subject twice.

angular.json

{
  ...
  "projects": {
    YOUR_PROJECT_NAME: {
      "architect": {
        "build": {
          "options": {
            "scripts": [
              "src/assets/js/custom.js"
            ]
          }
        }
      }
    }
  }
}

Within your component declare a const with the same name as the subject you created in the custom.jsfile. Within the ngOnInit subscribe to the Observable to listen to the events.

import { Component, OnDestroy, OnInit } from '@angular/core';
import { Subject } from 'rxjs';

declare const my_custom_subject: Subject<any>

@Component({
  selector: 'app-home',
  templateUrl: './home.component.html',
  styleUrls: ['./home.component.css'],
})
export class HomeComponent implements OnInit, OnDestroy {
  private subcription: Subscription;

  ...

  ngOnInit(): void {
    this.subcription = my_custom_subject.subscribe(data => console.log('subscription', data))
  }

  ngOnDestroy(): void {
    this.subcription.unsubscribe();
  }

  ...

}

This will allow you the call myFunction declared with regular javascript which will pass a message to your component. By subscribing to it, you're actually listening to the click events.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks, I feel this will only complicate things because afterwards I need to create another pop-up within this pop-up. So I have done more research and will try to approach this by creating elements like this : let div = document.createElement('div'); div.style.textAlign = "center"; let updateButton = document.createElement('button'); And then binding them to the pop-up. So far it's working. I'll post a solution once I have finished.
That looks like a good fit as well! Good luck!

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.