0

I have a set of radio buttons which are loaded in via AJAX once a user has been selected. They have the option to have their access set to Yes or No depending if it is required or not. When the button is clicked the active class is applied and when i get the value of the checked item it returns the expected value.

The problem i am having is that the change event and the click event, neither of them will fire when the button is clicked?

HTML:

<div class="col-md-4">
    <div class="btn-group" data-toggle="buttons" style="width:100%">
        <label class="btn btn-default <?php if($access['has_access']){?> active <?php } ?>" style="width:50%">
            <input type="radio" name="<?=$access['id']?>" id="option1" value="1" <?php if($access['has_access']){?> checked <?php } ?>>Yes
        </label>
        <label class="btn btn-default <?php if(!$access['has_access']){?> active <?php } ?>" style="width:50%">
            <input type="radio" name="<?=$access['id']?>" id="option2" value="0" <?php if(!$access['has_access']){?> checked <?php } ?>>No
        </label>
    </div>
</div>

JS:

$(document).on('click', 'input[type="radio"]', function(){
    var data = {};
    data.access_id = $(this).attr('name');
    data.value = $(this).val();
    data.user_id = $('input[name="user_id"]').val();
    $.ajax({
        url: '/ajax/change_access.php',
        type: 'POST',
        cache: false,
        data: data,
        dataType: 'JSON',
        headers: {"cache-action":"no-cache"}
    }).done(function(data){
        console.log('here');
    }).fail(function(data){
        console.log("error");
    });
});

I have tried changing the target to just input but this has no affect on radio buttons but is triggered by text inputs. Could be missing something obvious but unable to see it, any help would be much appreciated.

Lewis Blundell
  • 210
  • 2
  • 11
  • Listen for the `change` or `input` event on the radio buttons. The radios should not be clicked with bootstrap. The labels around them are clicked. – Taplar Apr 01 '19 at 18:21
  • As stated above i have tried both change and click, will try input event – Lewis Blundell Apr 01 '19 at 18:22
  • input event did not work either, any other ideas? – Lewis Blundell Apr 01 '19 at 18:23
  • https://jsfiddle.net/kbq0nxe4/ change works fine. – Taplar Apr 01 '19 at 18:27
  • It sounds like the $(document).on('click', 'input[type="radio"]' should set up listeners for the buttons but this code is being run before the buttons are loaded by ajax. Maybe something like load buttons .then $(document).on('click' ..? You can see if they are set by opening the dev console in Chome and clicking Elements then Event Listeners then Click. – Tim 333 Apr 01 '19 at 18:28
  • @Tim333 it's a delegate event listener. The time that the buttons are created doesn't matter. – Taplar Apr 01 '19 at 18:31
  • That script is loaded in before the Ajax is ever called (different file), would this cause issues? It’s loads in when the page is loaded in. – Lewis Blundell Apr 01 '19 at 18:32
  • The only thing that has to exist when creating a delegate event listener is the parent element, which in this case is the document, which always exists. – Taplar Apr 01 '19 at 18:32
  • That’s what I thought, never ran into this sort of problem before. I feel as though bootstrap maybe be conflicting some how? – Lewis Blundell Apr 01 '19 at 18:33
  • @LewisBlundell did you take a look at the fiddle I shared? It's using bootstrap and works fine. – Taplar Apr 01 '19 at 18:34
  • @Tim333 I would encourage you to read up on delegate event listeners. https://stackoverflow.com/questions/203198/event-binding-on-dynamically-created-elements – Taplar Apr 01 '19 at 18:35
  • @Taplar Currently on my phone, tried to look but wasn’t phone friendly so will have to get back to you on that one – Lewis Blundell Apr 01 '19 at 18:35
  • It might be $(document).on('click before the document's ready. You could try a $(document).ready(function(){ around the thing. (like https://www.w3schools.com/jquery/tryit.asp?filename=tryjquery_click) – Tim 333 Apr 01 '19 at 18:57
  • Sorry, it’s already in a document ready function. – Lewis Blundell Apr 01 '19 at 18:58
  • @Taplar Tried the above jsfiddle you linked. jsFiddle works and I can see that but doesn't seem to work for me in my environment. This leads me to feel like it is something to do with the order libraries and plugins are being loaded in? Problem is i'm not getting any dependency errors – Lewis Blundell Apr 02 '19 at 09:34
  • @Taplar Sorry for the slow response, haven't been able to work on it until today. One thing i have found out is that the label is what is causing the issue and if removed the change event fires. Any ideas since i thought bootstrap js dealt with this? – Lewis Blundell Apr 06 '19 at 22:23

1 Answers1

0

NOTE: This is technically wrong/unnecessary, per comments below. Although it would still attach events. It's just not the best way to attach events.

(Incorrect statement; original post) The above code will ONLY attach events on initial document load. NOT when the DOM is mutated (when you insert these elements via AJAX). This will fix your issue:

$(document).on('DOMNodeInserted', function(e) {

   //You can use $(this) instead of $(e.target) if you'd like.
   if($(e.target).attr("type") === "radio") {

      $(e.target).click(function() {

        var data = {};
        data.access_id = $(this).attr('name');
        data.value = $(this).val();
        data.user_id = $('input[name="user_id"]').val();
        $.ajax({
            url: '/ajax/change_access.php',
            type: 'POST',
            cache: false,
            data: data,
            dataType: 'JSON',
            headers: {"cache-action":"no-cache"}
        }).done(function(data){
            console.log('here');
        }).fail(function(data){
            console.log("error");
        });

      });

    }

});

This will be triggered every single time a new element is attached to the DOM. And I added a check to make sure the added element is a radio button. If so, then attach the click to it.

Asyranok
  • 950
  • 1
  • 7
  • 17
  • The code in the question is using a delegate event listener, which **is not** an issue with dynamic element. It is, in fact, the primary solution to having events for dynamic elements. I would advise you to read more on the topic. https://stackoverflow.com/questions/203198/event-binding-on-dynamically-created-elements http://learn.jquery.com/events/event-delegation/ – Taplar Apr 02 '19 at 17:02
  • Interesting. I've used them before and they never have worked for me in this situation. Only the DomNodeInserted even has worked for me before. – Asyranok Apr 02 '19 at 17:06
  • Can you show an example of your attempt to use a delegate that did not work? – Taplar Apr 02 '19 at 17:07
  • Exactly as was done by the OP. It would attach events on page DOM load, but never when inserting new elements that match the css selector. It has happened every time I have used $(document).on("event", "selector", function(){}); i'm happy to learn I'm wrong though, because it seemed silly. Must be something bigger wrong with my MVC project to do that then. Although, the one thing that may be relevant and didn't occur to me. I'd been putting it inside of $(document).ready... Does it need to be on its own, outside of that event? – Asyranok Apr 02 '19 at 17:28
  • https://jsfiddle.net/jbg0eyak/ It relies entirely on the event being allowed to bubble up from the dynamic children to the pre-existing parent that the event listener is bound to. If anything prevents the event from bubbling up, or it is an event that does not bubble, the delegate option will not work. – Taplar Apr 02 '19 at 17:32
  • 1
    All that matters for a delegate is that the parent exists. Not that the children exists. Wheither or not you need a document ready for that, depends entirely on if the parent already exists. In the case of `document`, it always exists. – Taplar Apr 02 '19 at 17:33
  • Thank you very much for the explanation! I will figure out the root of my issue. – Asyranok Apr 02 '19 at 18:03