2

I have the following code to display a dialog with three buttons. I'm trying to execute a specific function depending on the button clicked. However so far I have had no luck in getting the functions to execute:

  this.myMarkers.push({
    latitude: val["Latitude"],
    longitude: val["Longitude"],
    title: 'Tree ' + val["TreeID"],
    custom: {id: 123456},
    infoWindow: {content: `
            <div id="content">
              <div id="siteNotice"></div>
              <h1 id="firstHeading" class="firstHeading">Tree ${val["TreeID"]}</h1>
              <div id="bodyContent">
                <p>Description: ${val["Description"]}</p>
                <p>Fruit Bearing: ${val["FruitBearing"]}</p>
                <button type="button" onclick="this.updateTree()">Update</button>
                <button type="button" onclick=${this.editTreeInfo()}>Edit Info</button>
                <button type="button" onclick="${this.showTreeHistory()}">Historical</button>
              </div>
            </div>`}
  });

  updateTree(){
    console.log("Update Tree: ");
  }

  editTreeInfo(){
    console.log("Edit Tree: ");
  }

  showTreeHistory(){
    console.log("Show Tree History: ");
  }

In the console, after the page loads, the following is outputted:

welcome.js:56 Edit Tree: 
welcome.js:60 Show Tree History: 
welcome.js:56 Edit Tree: 
welcome.js:60 Show Tree History: 
welcome.js:56 Edit Tree: 
welcome.js:60 Show Tree History: 
welcome.js:56 Edit Tree: 
...

And when clicking the buttons, nothing happens - except for:

Uncaught TypeError: this.updateTree is not a function
    at HTMLButtonElement.onclick ((index):1)

Nothing happens for the other buttons. I have tried using click.delegate but this doesn't seem to do anything either.

TomSelleck
  • 6,706
  • 22
  • 82
  • 151
  • did you try this ? - https://stackoverflow.com/questions/3316207/add-onclick-event-to-newly-added-element-in-javascript Idea is to attach event listeners after the html is created. – Pramod Solanky Jul 29 '17 at 16:52
  • hmm looks promising - tried this `` but get an error: ` (index):1 Uncaught SyntaxError: Unexpected token ( ` – TomSelleck Jul 29 '17 at 17:01
  • Im not sure on Aurelia. But in Javascript above is how I would go about attaching events to dynamically created html. Or perhaps use jquery and bind classes or ids to events. Having said that, here is a link which might help but I'm not sure - http://www.jeremyg.net/entry/adding-a-view-to-a-custom-attribute-in-aurelia – Pramod Solanky Jul 29 '17 at 17:12
  • I should mention this element is a point displayed on a google map - this might affect something - not sure.. – TomSelleck Jul 29 '17 at 17:14
  • Also, since you say, your html is rendered nicely you could get the element and attach an event separately. something like this `var element = document.getElementById('id'); element.onclick = function(){// handle click };` needless to say, this must be executed everytime you render your html as id would be uniq. – Pramod Solanky Jul 29 '17 at 17:17
  • BTW, doesn't it look like a typo ? `` shouldn't this be `` as your other buttons follow this syntax. – Pramod Solanky Jul 29 '17 at 17:21
  • `` Gave this a try - seems to fire as soon as the page loads... – TomSelleck Jul 29 '17 at 17:26

2 Answers2

2

I really don't think this is the way to go about it, but a quick fix might be to write your onclick function like so:

onclick='(${this.updateTree})()'

Your current code is executing at once because of the parantheses immediately after updateTree

Be wary though that with this method you will not reference your function but rather copy it to each pushed marker. The onclick in html will look something like this:

onclick="(function () {
        // ALL CODE from inside updateTree function
    })()"

Which mean that you wont be able to use any code from the viewmodel which resides outside that function. Lets say you have a variable in the viewmodel like this.variable = "not undefined". That will be undefined when the onclick action triggers.


I'd probably try to import the TemplatingEngine from aurelia-framework, create the infowindow in a variable first, and then enhance it with the templatingengine. Then you should be able to use click.delegate:

import { TemplatingEngine, inject } from 'aurelia-framework';

@inject(TemplatingEngine)
export class App {
  templatingEngine: TemplatingEngine;

  constructor(te: TemplatingEngine) {
    this.templatingEngine = te;
  }

prepareMarker(){
 let infoWindowContent = document.createElement('div');
 infoWindowContent.id = "content";
 infoWindowContent.innerHTML = `<div id="siteNotice"></div>
          <h1 id="firstHeading" class="firstHeading">Tree ${val["TreeID"]}</h1>
          <div id="bodyContent">
            <p>Description: ${val["Description"]}</p>
            <p>Fruit Bearing: ${val["FruitBearing"]}</p>
            <button type="button" click.delegate="updateTree()">Update</button>
            <button type="button" click.delegate="editTreeInfo()">Edit Info</button>
            <button type="button" click.delegate="showTreeHistory()">Historical</button>
          </div>`;
   this.templatingEngine.enhance({ element: infoWindowContent, bindingContext: this });

   this.myMarkers.push({
    ...
    infoWindow: infoWindowContent
   });
  }

I'm assuming you're using google maps, and from what I know, they accept a htmlelement as well as a string as 'content': Link

Sidenote: If you push more than 1 marker, you're going to have multiple elements of the same id(content, sideNotice, firstHeading, bodyContent). You should probably swap all ids for classes.

Sitl
  • 440
  • 5
  • 6
0

this.updateTree is not a function because your function updateTree is defined in the context of a window object, while this refers to the DOM element. Try removing this in the button onclick call,

onclick=updateTree()

Jarek Kulikowski
  • 1,399
  • 8
  • 9