39155

'this.function' is not a function - OO JS

I have a modal object that has various functions as its properties, but when I click to open a modal I'm getting the error this.openModal is not a function. I've tried debugging but it just falls over as soon as it hits the function I want it to run. I suspect it might be an issue with the 'this' binding, but I'm not sure where the problem is. All my JS is below, one function kind of chains onto another so it's easier to see the whole object.

var modal = function () { // Modal Close Listeners this.closeModalListen = function(button) { var modalFooter = button.parentElement; var modalContent = modalFooter.parentElement; var modalElement = modalContent.parentElement; var backdrop = document.getElementById("modal-backdrop"); this.closeModal(modalElement, backdrop); } // Open Modal this.openModal = function(button) { var button = button; var modal = button.getAttribute("data-modal"); var modalElement = document.getElementById(modal); var backdrop = document.createElement('div'); backdrop.id="modal-backdrop"; backdrop.classList.add("modal-backdrop"); document.body.appendChild(backdrop); var backdrop = document.getElementById("modal-backdrop"); backdrop.className += " modal-open"; modalElement.className += " modal-open"; } // Close Modal this.closeModal = function(modalElement, backdrop) { modalElement.className = modalElement.className.replace(/\bmodal-open\b/, ''); backdrop.className = backdrop.className.replace(/\bmodal-open\b/, ''); } // Initialise Function this.init = function () { // Create Events for creating the modals if (document.addEventListener) { document.addEventListener("click", this.handleClick, false); } else if (document.attachEvent) { document.attachEvent("onclick", this.handleClick); } } // Handle Button Click this.handleClick = function(event) { var thisModal = this; event = event || window.event; event.target = event.target || event.srcElement; var element = event.target; while (element) { if (element.nodeName === "BUTTON" && /akela/.test(element.className)) { thisModal.openModal(element); break; } else if (element.nodeName === "BUTTON" && /close/.test(element.className)) { thisModal.closeModalListen(element); break; } else if (element.nodeName === "DIV" && /close/.test(element.className)) { thisModal.closeModalListen(element); break; } element = element.parentNode; } } } // Initalise Modal Engine var akelaModel = new modal(); akelaModel.init();

I'm looking to fix this with pure js and no jquery.

Answer1:

You need to bind the function to the object before giving it as a event listener:

document.addEventListener("click", this.handleClick.bind(this), false); document.attachEvent("onclick", this.handleClick.bind(this));

Otherwise it becomes detached from its original object and doesn't have the expected this.

Answer2:

As an alternative to using bind, you can move:

var thisModal = this;

from the handleClick method to the constructor.

Also, it's convention to give constructors names starting with a capital letter so it's easier to see that they're constructors.

<div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false"> <div class="snippet-code">

var Modal = function () {

  var thisModal = this;

  // Open Modal
  this.openModal = function(button) {
    console.log('openModal called on ' + button.tagName);
  }

  // Initialise Function
  this.init = function () {
    // Create Events for creating the modals
    if (document.addEventListener) {
        document.addEventListener("click", this.handleClick, false);
    }
  }

  // Handle Button Click
  this.handleClick = function(event) {
    thisModal.openModal(event.target);
  }
}

// Initalise Modal Engine
var akelaModel = new Modal();
akelaModel.init();
<div>Click <span>anywhere</span></div>


Recommend

  • ng-include seems to do nothing
  • mvc ajax submitting from a modal
  • Bootstrap Modal popup is disappearing after summitting data in Yii2?
  • on Change event in select with knockout
  • BPEL Designer for Eclipse: how to debug a BPEL process
  • How to select all local links in jQuery
  • addEventHandler() in a loop has unexpected results
  • OnChange event handler not working
  • Google Contacts API get phone number (PHP)
  • Sending HTML Form Multiple box via POST request with AJAX?
  • Merge HTML Element object with a custom object
  • Android Chrome input onkeydown
  • HTML5 canvas draw multiple rectangles that move in the canvas
  • Double.parseDouble is not working on my webpage
  • Rendering a google line chart, curveType not setting and animation not working as expected
  • How to get the position of a click event relative to its layer in KineticJS?
  • Get highlight text in current window and send it in a popup
  • Socket io in node app on google app engine
  • button in popup.html not working
  • Remove previous Directions Route Google Maps
  • $_POST for text in DIV elements
  • Why does the following throw an “Object doesn't support property or method 'importNode
  • Making Google Visualization - Annotation Chart to work in GWT
  • Getting error 'Cannot read property 'document' of undefined' while importing exp
  • Update Google Maps traffic layer without page reloading
  • Access variable of ScriptContext using Nashorn JavaScript Engine (Java 8)
  • Chart.js Multiple dataset
  • Bad request using file_get_contents for PUT request in PHP
  • FileReader+canvas image loading problem
  • Insert into database using onclick function
  • Deselecting radio buttons while keeping the View Model in synch
  • Why HTML5 Canvas with a larger size stretch a drawn line?
  • How to redirect a user to a different server and include HTTP basic authentication credentials?
  • Can I make an Android app that runs a web view in Chrome 39?
  • Change an a tag attribute in JavaScript based on screen width
  • LevelDB C iterator
  • Linking SubReports Without LinkChild/LinkMaster
  • How to get NHibernate ISession to cache entity not retrieved by primary key
  • How can I use `wmic` in a Windows PE script?
  • Unable to use reactive element in my shiny app