0

I have not been able to find an answer to this question, however it is possible I just don't know what to search for.

This is for a "Cookie Clicker" type game. I have a list of servants, which, when unlocked, add an entry to a <ul>, with buttons to hire more of them, and appropriate info.

However, I have not been able to bind the buttons to the instance's methods. How would I achieve that, or something similar if my implementation is suboptimal ?

<ul id="servants"></ul>
<template id="servant-template">
  <li>
    <span class="count-span"></span> <span class="name-span"></span> : 
    +<span class="value-span"></span>/s
      <button type="button" class="hire-button">
        Hire (<span class="hire-cost"></span>$)
      </button>     
  </li>
</template>
class Servant {
  constructor(name, value) {
    this.count = 0;
    this.name = name;
    this.value = value;
    this.cost = value;
    this.unlocked = false;
  }
  work() {
    if (!this.unlocked) return;
    add_score(this.count * this.value * this.level);
  }
  hire() {
    if (!this.unlocked || balance < this.cost) return;
    balance -= this.cost;
    this.count += 1;
    this.cost *= 2 ** this.value;
    this.update_gui();
  }
  unlock() {
    this.unlocked = true;
    const template = document.querySelector("#servant-template");
    const clone = template.content.firstElementChild.cloneNode(true);
    clone.id = `servant-${this.name}`;
    console.log(clone);

    clone.querySelector(".hire-button").onclick = function () {
      this.hire(); //Doesn't work because "this" actually is the button at call time
    };
    servants_gui.appendChild(clone);
    this.update_gui();
  }
  update_gui() {
    if (!this.unlocked) return;
    const gui = document.querySelector(`#servant-${this.name}`);
    console.log(gui);
    gui.querySelector(".count-span").innerHTML = this.count;
    gui.querySelector(".name-span").innerHTML = this.name;
    gui.querySelector(".value-span").innerHTML = this.value;
    gui.querySelector(".hire-cost").innerHTML = this.cost;
  }
}
const servants = [new Servant("Miners", 1)];
servants[0].unlock();
Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
ice-wind
  • 690
  • 4
  • 20
  • Use an arrow function instead of traditional function. It preserves `this`. – Barmar May 02 '23 at 16:27
  • @Barmar can you explain a little more ? The information I am finding says arrow functions cannot be used as methods, which is very confusing – ice-wind May 02 '23 at 16:29
  • You're not using it *as* a method, you're using it *in* a method. – Barmar May 02 '23 at 16:35
  • `.onclick = () => this.hire();` – Barmar May 02 '23 at 16:36
  • _"This question has been closed with no suggestion of where to look for an answer. This is completely unreasonable and unfair."_ No, your question was closed as a duplicate, and there is a link to another question. Look at the blue box at the top of your question. – Mark Rotteveel May 03 '23 at 07:35
  • @MarkRotteveel There was no link when this part was added to the question text. If there is a link now, it was added afterwards. – ice-wind May 04 '23 at 10:37
  • It is not, it was added immediately when the question was closed: https://stackoverflow.com/posts/76156918/timeline, but I can't discount the possibility that the UX might be off if you're viewing the question while it is closed, and you don't explicitly refresh your question. The only way a duplicate could have been added after the fact is if the question had been reopened (which requires 3 users to vote to reopen) and then closed again, which is not the case as the timeline shows. – Mark Rotteveel May 04 '23 at 10:41

0 Answers0