1

I have a php page, a.php, with the following code:

<ul class="dropdown-menu noclose">

which works fine, causing the drop-down menu to not close until the user has clicked outside of the box.

However, when I load this entire a.php page inside of a div on b.php, the noclose no longer works and I can't figure out why.

//in a.js, which gets called via ajax through a.php
$("#info").load("a.html");

It functions like a normal drop-down menu - when a user selects an option, it closes the drop-down.

The noclose syntax is available by adding the following lines to the header:

<!-- Bootstrap Dropdown Enhancements-->
<link rel="stylesheet" href="/dropdowns-enhancement.css">
<script type="text/javascript" src="/dropdowns-enhancement.js"></script>

I've tried adding these into a.php, b.php, and on both, but the noclose will still not work when the page is loaded inside a div. What am I doing wrong?

Update:

This is the button that loads on a.php.

<button type="button" id="seButton" class="btn btn-primary dropdown-toggle" data-toggle="dropdown">
  Select Options<span class="caret"></span>
</button>
<ul class="dropdown-menu noclose" role="menu">
  <li> ... </li>
</ul>

Now that I've put the following into my ajax success function, it now stays open, (through no help on the part of the noclose!)

$("#info").on('click.bs.dropdown.data-api', '.dropdown-menu.noclose > li', function (e) {
    e.stopPropagation();
});

This button is loaded on a.php inside of the #info div. The button controls the loading of more information inside a second div, still on a.php, through the use of ajax as well. That call is here:

$.ajax({
  url: "search.php", 
  type: "post",
  dataType: "json",
  data: {partNumber: q , cr:newCr},
  success: function(data) {
      $("#info").on('click.bs.dropdown.data-api', '.dropdown-menu.noclose > li', function (e) {
          e.stopPropagation();
      });
      var seOutput = data;
      if (data.length > 0) {
          $("#auto").html("");   //unloads the spinner so the table can load.
          addTable(seOutput);  // calls the addTable function to create the table in #auto
      } else {                          
          //else = seOutput is empty, so there are no results to return
          $("#autoCross").html("");   //unloads the spinner so the table can load.
          toastr.options = {
              "positionClass": "toast-top-full-width"
          }
          toastr.warning('There are no ' + newCr + ' parts to report', '');
      } //closes else statement                                              
  } //closes success function
});

Once I click the above button and this ajax call succeeds, a table is generated in the #auto div, and the button that is the source of this post in #info no longer drops down. I can click on it, and if I attach an onclick event to it, I can call a console.log statement to show the browser sees me clicking it, but the drop-down no longer drops down, so I can't access the data in that dropdown unless I reload the page.

falsarella
  • 12,217
  • 9
  • 69
  • 115
Brian Powell
  • 3,336
  • 4
  • 34
  • 60

2 Answers2

2

Since its an AJAX request, you need to attach events after the request is complete. Your code for the noclose should be in the callback for the load. If you need to attach the script file dropdowns-enhancement.js then use $.getScript to load the js

$("#info").load("a.html", function(){
   // noclose bindings
   $.getScript('/dropdowns-enhancement.js');
});
anpsmn
  • 7,217
  • 2
  • 28
  • 44
  • I don't understand what I'm supposed to add here: `//noclose bindings`. Historically, the only way I've enabled scripts is by adding the `.css` or `.js` files to the header (which I did here, and which doesn't work,) but I'm not sure what specific code needs to be in the `callback for the load` – Brian Powell Mar 11 '15 at 13:48
2

It seems that the library might not support content loaded after Ajax requests (although it's using jQuery's .on - which makes it weird not being supported), and unfortunately the noclose handler is not exposed to outside the plugin script scope.

So you might want to rerun that handler* manually for the loaded elements, as a workaround:

* (search for noclose in their source code)

$("#info").load("a.html", function() {
    $("#info")
        .on('click.bs.dropdown.data-api', '.dropdown-menu.noclose > li', function (e) {
            e.stopPropagation();
        });
});

Btw, proposing a pull request (with ajax-support scripts) or opening an issue would be an even better attitude!


Edit:

Another try would be reexecuting the complete dropdown-enhanced handling, something like this, as you can see in their repository:

$(document).off(namespace)
    .on('click' + namespace, closeOpened)
    .on('click' + namespace, toggle, proto.toggle)
    .on('click' + namespace, '.dropdown-menu > li > input[type="checkbox"] ~ label, .dropdown-menu > li > input[type="checkbox"], .dropdown-menu.noclose > li', function (e) {
        e.stopPropagation()
    })
    .on('change' + namespace, '.dropdown-menu > li > input[type="checkbox"], .dropdown-menu > li > input[type="radio"]', proto.change)
    .on('keydown' + namespace, toggle + ', [role="menu"], [role="listbox"]', proto.keydown);

But that would require copying also their namespace, closeOpened, toggle, proto.toggle, proto.change, proto.keydown. So, it would be easier to actually reload it entirely, as have been suggested.

I thought it mightn't be necessary, but if that didn't work, try re-executing the dropdowns-enhancement.js. It is almost like anpsmn's solution, but I actually got it from a mix os answers from this other question, so it also removes the former script tag before re-adding it and uses cachebuster to make sure it will be re-loaded:

function reload_js(src) {
    $('script[src="' + src + '"]').remove();
    $('<script>').attr('src', src + '?cachebuster='+ new Date().getTime()).appendTo('head');
}

Then, call it after every ajax that puts any content containing an enhanced dropdown:

$("#info").load("a.html", function(){
   // noclose bindings
   reload_js('/dropdowns-enhancement.js');
});
Community
  • 1
  • 1
falsarella
  • 12,217
  • 9
  • 69
  • 115
  • Thank you! 50 bounty may not be a lot for you, but it was a third of mine, you get it in 13 minutes :) This worked - the dropdown menu now stays open until I click outside of it. The only other thing (which is not part of the original question,) is now, once I make my selections and click the Submit button, this button triggers another ajax request to populate ANOTHER div inside the page, and when that happens, the button stops working. I can click it, and attach an `onclick` event to it to show it's being clicked, but the dropdown doesn't fire anymore unless I reload the page. Any ideas? – Brian Powell Mar 11 '15 at 15:57
  • @JohnWu What button stops working, and what do you mean by stops working? So, you say it stops to work, but on console you can see the event is being triggered? Please, also note that you need to run that script for every ajax load you do, so your another ajax request will also need the above script. – falsarella Mar 11 '15 at 17:14
  • I edited my original question with an `update` section - easier than trying to explain it here. – Brian Powell Mar 11 '15 at 18:46
  • 1
    @JohnWu I've updated my answer, but I'd try [anpsmn's solution](http://stackoverflow.com/a/28980173/1064325), or anything to [force the reload/reexecution of the script](http://stackoverflow.com/q/9642205/1064325) – falsarella Mar 11 '15 at 19:28
  • Well, that did it! forcing the reload of the `dropdown-enhancements.js` worked! Phew! I have been working on this stupid thing for like 3 weeks, so thank you SO much for your expertise! – Brian Powell Mar 11 '15 at 19:55
  • @JohnWu I hope you understood what was happening and why it solved. Glad that worked! – falsarella Mar 11 '15 at 20:22