-1

I've developed a script which acts as a modal trigger.

What it does is: whenever a user clicks on an element with the class "toggle-feature" it'll open activate a modal (from which the element has specified via data-toggle).

For example, if I click:

<button class="toggle-feature" data-toggle="random-modal" data-class="custom-class">Test</button>

It should add the class "custom-class" to this element:

<div id="random-modal">Random Modal</div>

So far, it works as semi-intended. However, if the element that is supposed to act as a "trigger" has children, and one of the children is clicked on, the modal won't activate.

I have tried so many approaches (which includes changing almost every line of code), along with e.stopPropagation() and the use of document.querySelectorAll(".toggle-feature, .toggle-feature *") - but none of them ever seemed to work.

This is my (simplified and prettied) JavaScript:

// globals
var regex;

// functionality
document.onclick = function(e){ // on document click
    var tf = document.getElementsByClassName("toggle-feature");
    e.stopPropagation(); // does not stop dom bubbling up

    for(var i = 0; i < tf.length; i++){ // iterate through each toggle button

        if(e.target == tf[i]){ // if the element clicked was one of the toggles

            if(tf[i].hasAttribute("data-toggle")){ // if the element has specified a modal to togal
                var modal = document.getElementById(tf[i].getAttribute("data-toggle")); // get the specified modal
                regex = new RegExp("(?:^|\\s)" + (tf[i].hasAttribute("data-class") ? tf[i].getAttribute("data-class") : "active") + "(?!\\S)"); // some regex for targeting a specific class

                if(modal.className.match(regex)){ // if the modal has the "active" class

                    modal.className = modal.className.replace(regex, ""); // remove the class

                } else { // vice versa

                    modal.className = modal.className + " " + (tf[i].hasAttribute("data-class") ? tf[i].getAttribute("data-class") : "active");

                }
            }
        }
    }
}

Here is the JsFiddle for it (along with all the original JS, and an example): https://jsfiddle.net/n8t6u4s6/

GROVER.
  • 4,071
  • 2
  • 19
  • 66
  • Is this bootstrap right? In your fiddle, you did not include bootstrap. – ngeksyo Jul 05 '17 at 16:13
  • @ngeksyo no - I don't use any third-party frameworks or libraries. – GROVER. Jul 05 '17 at 16:14
  • Instead of a regexp, use `modal.classList.includes()`. – Barmar Jul 05 '17 at 16:49
  • @Barmar not using `classList` property due to the fact that I want to support IE9. – GROVER. Jul 05 '17 at 16:50
  • I think the problem is that you shouldn't have a span inside a button. See https://stackoverflow.com/questions/26402033/missing-click-event-for-span-inside-button-element-on-firefox – Barmar Jul 05 '17 at 17:12
  • @Barmar I tried with an anchor tag, and still the same result: https://jsfiddle.net/n8t6u4s6/14/ – GROVER. Jul 06 '17 at 07:13
  • Can you just attach the event listener to the elements directly, rather than `document`? Are they being added dynamically so you need event delegation? – Barmar Jul 06 '17 at 12:20
  • @Barmar procedurally generated content unfortunately :( otherwise, I would've done exactly that haha – GROVER. Jul 06 '17 at 12:36

1 Answers1

0

I managed to figure out a working solution, which utilizes the children and parentNode properties - whilst defining a separate function to handle activating the modal(s).

This is what I came up with (for anyone who might face a similar problem in the future).

function toggleModal(clicked, parent){
    var elem = (parent == undefined ? clicked : parent), 
        regex = new RegExp("(?:^|\\s)" + (elem.hasAttribute("data-class") ? elem.getAttribute("data-class") : "active") + "(?!\\S)"),
        modal;

    if(elem.hasAttribute("data-toggle")){
        modal = document.getElementById(elem.getAttribute("data-toggle"));
        modal.className = (modal.className.match(regex) ? modal.className.replace(regex, "") : modal.className + " " + (elem.hasAttribute("data-class") ? elem.getAttribute("data-class") : "active"));
    } else if(elem.hasAttribute("data-open")){
        modal = document.getElementById(elem.getAttribute("data-open"));
        modal.className = (!modal.className.match(regex) ? modal.className + " " + (elem.hasAttribute("data-class") ? elem.getAttribute("data-class") : "active") : modal.className);
    } else if(elem.hasAttribute("data-close")){
        modal = document.getElementById(elem.getAttribute("data-close"));
        modal.className = (modal.className.match(regex) ? modal.className.replace(regex, "") : modal.className);
    }
}

document.onclick = function(e){
    var tf = document.getElementsByClassName("toggle-feature");
    for(var i = 0; i < tf.length; i++){
        if(e.target == tf[i]){
            toggleModal(tf[i]);
        } else {
            for(var x = 0; x < tf[i].children.length; x++){
                if(e.target == tf[i].children[x]){
                    toggleModal(tf[i].children[x], tf[i]);
                }
            }
        }
    }
}

Hopefully it helps someone out!

Fiddle: https://jsfiddle.net/n8t6u4s6/15/

GROVER.
  • 4,071
  • 2
  • 19
  • 66