0

I wrote a JavaScript object literal to handle multiple modals on a HTML page. When I click on a buttton to show the Modal, I'm getting the following error.

Uncaught TypeError: this.showModal is not a function
    at HTMLButtonElement.modalBtns.(anonymous function).onclick (file:///C:/dj-sites/ux_bee/js/base.js:63:22)

I'm thinking the problem is that the "this" keyword is pointing to the button, but not the object literal. Not sure how should I fix this.

var myModalObj = {
    findAncestor: function(el, cls) {
        while ((el = el.parentElement) && !el.classList.contains(cls));
        return el;
    },
    showModal: function(btn){
        var modal_id = btn.getAttribute('data-modal')
        var modal = document.getElementById(modal_id);
        modal.style.display = "block";
    },
    closeModal: function (btn){
        var modal = this.findAncestor(btn, 'modal')
        modal.style.display = "none";
    },
    init: function(){
        var modalBtns = document.getElementsByClassName('my-modal-btn');
        for(var i = 0; i < modalBtns.length; i++) {
            var btn_modal = modalBtns[i];
            modalBtns[i].onclick = function() {
                this.showModal(btn_modal);
            }
        }

        var closeBtns = document.getElementsByClassName('modal-close');
        for(var i = 0; i < closeBtns.length; i++) {
            var btn_close = closeBtns[i];
            closeBtns[i].onclick = function() {
                this.closeModal(btn_close);
            }
        }
    }
}
myModalObj.init()
Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
user1187968
  • 7,154
  • 16
  • 81
  • 152
  • Bind your event handler callback function to the proper context - by default, the button element the handler is registered against, not your myModalObj object. Like this: modalBtns[i].onclick = function() {this.showModal(btn_modal)}.bind(this); – IAmDranged Dec 24 '16 at 07:28

1 Answers1

0

Simple answer - just replace all instances of this with myModalObj, like so.

var myModalObj = {
    findAncestor: function(el, cls) {
        while ((el = el.parentElement) && !el.classList.contains(cls));
        return el;
    },
    showModal: function(btn){
        var modal_id = btn.getAttribute('data-modal')
        var modal = document.getElementById(modal_id);
        modal.style.display = "block";
    },
    closeModal: function (btn){
        var modal = myModalObj.findAncestor(btn, 'modal')
        modal.style.display = "none";
    },
    init: function(){
        var modalBtns = document.getElementsByClassName('my-modal-btn');
        for(var i = 0; i < modalBtns.length; i++) {
            var btn_modal = modalBtns[i];
            modalBtns[i].onclick = function() {
                myModalObj.showModal(btn_modal);
            }
        }

        var closeBtns = document.getElementsByClassName('modal-close');
        for(var i = 0; i < closeBtns.length; i++) {
            var btn_close = closeBtns[i];
            closeBtns[i].onclick = function() {
                myModalObj.closeModal(btn_close);
            }
        }
    }
}
myModalObj.init()

The reason you have to do this is because the function you're trying to call is only stored in myModalObj, so that's the only way you can call it.

TrojanByAccident
  • 227
  • 1
  • 6
  • 20