0

And thank you in advance for your help. I've written a pretty standard Modal class in Vanilla JavaScript, and I am wondering why when I call the myModal.showModal method, we always call it on the last instance of the Modal.

Here is the code for my Modal:

(function() {
    /**
     * Creates a Modal dialog. The user should call `removeModal` when they are
     * finished using it.
     * @param {boolean} defaultShow whether or not the modal is shown by default
     * @param {HTMLElement} bodyContent the body of the modal
     * @param {HTMLButtonElement | undefined} footerContent footer of the modal
     */
    function Modal(defaultShow, initialBodyContent, initialFooterContent) {
        let isActive = false;

        // Create the modal and append it to the dom
        let containerElement = document.createElement("div");
        containerElement.className = "modal-container";
        containerElement.id = Math.random().toString();

        let modalBody = document.createElement("div");
        modalBody.className = "modal-body";
        if (initialBodyContent) {
            modalBody.appendChild(initialBodyContent);
        }
        containerElement.appendChild(modalBody);

        let modalFooter = document.createElement("div");
        modalFooter.className = "modal-footer";
        if (initialFooterContent) {
            modalFooter.appendChild(initialFooterContent);
        }

        containerElement.appendChild(modalFooter);
        document.body.appendChild(containerElement);

        /**
         * Shows the modal with new content, optionally
         * @param {HTMLElement | undefined} newBodyContent replacement body element
         * @param {HTMLElement | undefined} newFooterContent replacement footer element
         */
        function showModal(newBodyContent, newFooterContent) {
            if (isActive) {
                return;
            }

            if (newBodyContent) {
                modalBody.innerHTML = "";
                modalBody.appendChild(newBodyContent);
            }

            if (newFooterContent) {
                modalFooter.innerHTML = "";
                modalFooter.appendChild(newFooterContent);
            }

            isActive = true;
            containerElement.classList.add("show");
            containerElement.classList.remove("hide");
        }

        /**
         * Hides the modal, but does not delete it from the DOM
         */
        function hideModal() {
            isActive = false;
            containerElement.classList.add("hide");
            containerElement.classList.remove("show");
        }

        /**
         * Completely removes the modal from the DOM
         */
        function removeModal() {
            $(containerElement).remove();
        }

        Modal.prototype.showModal = showModal;
        Modal.prototype.hideModal = hideModal;
        Modal.prototype.removeModal = removeModal;
        Modal.prototype.isShowing = function() { return isActive; };

        if (defaultShow) {
            showModal();
        } else {
            hideModal();
        }
    }
    
    module.exports = { Modal: Modal };
}())

And I am using it like so:

const myModal1 = new Modal(false);
const myModal2 = new Modal(false);

At this point, I see both Modals on the DOM. However, when i call myModal1.show(content, footer), we're calling the showModal prototype of myModal2, instead of myModal1. However, if I change the prototype methods to:

function Modal() {
    ....
    this.showModal = showModal;
    this.hideModal = hideModal;
    etc...
    ...
}

the code behaves as I expect it to. What is going on here exactly? I would expect the prototype function to capture my variables, but perhaps I'm mistaken.

Matt Kae
  • 147
  • 5
  • Because methods on the prototype are shared by all instances. And you’re creating those functions to be specific to one instance, but then share the last version with all instances via the prototype. – deceze Aug 11 '20 at 17:29
  • Ah i feel silly now, but thank you for clearing that up for me! – Matt Kae Aug 11 '20 at 17:34

1 Answers1

2

Modal.prototype holds the same value for all your Modal instances, so the showModal method of all your Modal instances refer to the showModal method of the last instance.

For example :

function A () {
  const randomNumber = Math.floor(Math.random() * 100);
  A.prototype.id = randomNumber;
  console.log("creating instance with id: " + randomNumber);
}

const a1 = new A()
const a2 = new A()

console.log("Current ID of a1: " + a1.id);
console.log("Current ID of a2: " + a2.id);

console.log(a1.__proto__ === a2.__proto__); // Will return "true" because it's the same object

You can read more on the documentation.

Seblor
  • 6,947
  • 1
  • 25
  • 46