Search code examples
javascriptes6-moduleses6-class

Unable to access ES 6 function when rendered through innerHTML


I have following html code

<html lang="en">
 <body>
    <div id="placeholder"></div>
    <script type="module">
      import { WriteReview } from "./src/script.js"
      var inputElement  = new WriteReview(document.getElementById("placeholder"));
      inputElement.render();
    </script>
  </body>
</html>

In script.js have following code

export class WriteReview{
    constructor(element){
         this.rating ="5"
         this.element=element;
    }
    setChange(){
        this.rating = "3";
    }
    render(){
      console.log("inside render");
        this.element.innerHTML = `<input type="button" onclick="this.setChange()" value ="Click here" />`
    }
}

When I click the button, browser reports an error "TypeError: this.setChange is not a function". Why I can't access the function setChange() from my index.html, how to resolve this issue. Issue URL: https://playcode.io/1532407


Solution

  • There's a couple of problems here.

    First and foremost, within an onclick attribute, this refers to the element itself which obviously does not have a setChange() method.

    Secondly, you won't be able to set the click handler to your WriteReview instance method because anything referred to in an onclick attribute must be present in the global scope.

    Instead, create an element dynamically and attach an event listener, using an arrow function to keep lexical scope within the class instance.

    render () {
      const input = Object.assign(document.createElement("input"), {
        type: "button",
        value: "Click here",
      });
    
      input.addEventListener("click", (e) => {
        this.setChange();
      });
    
      this.element.append(input);
    }
    

    Here's a demo showing it working...

    class WriteReview {
      constructor(element) {
        this.rating = "5"
        this.element = element;
      }
      setChange() {
        console.log("WriteReview#setChange called");
        this.rating = "3";
      }
      render() {
        const input = Object.assign(document.createElement("input"), {
          type: "button",
          value: "Click here",
        });
    
        input.addEventListener("click", (e) => {
          console.log("[before] rating:", this.rating);
          this.setChange();
          console.log("[after] rating:", this.rating);
        });
    
        this.element.append(input);
      }
    }
    
    var inputElement  = new WriteReview(document.getElementById("placeholder"));
    inputElement.render();
    <div id="placeholder"></div>