Uploaded image for project: 'Moodle'
  1. Moodle
  2. MDL-67357

Not possible to listen to the 'shown.bs.tab' event when the tab from the hash is loaded

    XMLWordPrintable

    Details

    • Type: Bug
    • Status: Closed
    • Priority: Minor
    • Resolution: Not a bug
    • Affects Version/s: 3.8
    • Fix Version/s: None
    • Component/s: JavaScript
    • Testing Instructions:
      Hide

      To test you need to reproduce on last weekly version first and then test on integration.

      1. Put the attached testtabs.php to your moodle root
      2. Open it in a browser (as a logged in user)
      3. Open console window
      4. Click on the "Other tab"
      5. Refresh the window multiple times, in console you will see either:

      Active tab: #defaulttab
      Switch to tab: #othertab
      

      or

      Active tab: #othertab
      

      It will usually be the first one but may change randomly. If you modify the source of testtabs.php and add a delay in the setTimeout() function it will usually be the second one.
      6. Now when you reproduced the randomness on the last weekly version do the same test on integration (after purging the caches)
      7. Make sure that regardless of the timeout in setTimeout() function the result is always

      Active tab: #othertab
      

      Show
      To test you need to reproduce on last weekly version first and then test on integration. 1. Put the attached testtabs.php to your moodle root 2. Open it in a browser (as a logged in user) 3. Open console window 4. Click on the "Other tab" 5. Refresh the window multiple times, in console you will see either: Active tab: #defaulttab Switch to tab: #othertab or Active tab: #othertab It will usually be the first one but may change randomly. If you modify the source of testtabs.php and add a delay in the setTimeout() function it will usually be the second one. 6. Now when you reproduced the randomness on the last weekly version do the same test on integration (after purging the caches) 7. Make sure that regardless of the timeout in setTimeout() function the result is always Active tab: #othertab
    • Affected Branches:
      MOODLE_38_STABLE
    • Pull Master Branch:
      MDL-67357-master

      Description

      theme_boost/loader.js contains the following code:

              var hash = window.location.hash;
              if (hash) {
                 jQuery('.nav-link[href="' + hash + '"]').tab('show');
              }
      

      This is a good addition to the bootstrap tabs, it allows to automatically open a tab from the hash.

      It is also possible in js code to create a listener to the event 'shown.bs.tab' that does something when the tab is shown.

      However it is very difficult to write code that would add a listener to be executed on any tab change AND ALSO on this initial show.

      • we can not execute any code before theme_boost/loader is called. There is no guarantee that it will be loaded before theme_boost/loader
      • at the same time it is not possible to wait for theme_boost/loader to complete before executing the code that contains listener.

      For example:

      require(['jquery', 'theme_boost/loader'], function($) {
          $('a[data-toggle="tab"]').on('shown.bs.tab', myMethod);
          myMethod($('.nav-link[href="' + window.location.hash + '"]'));
      });
      

      this code will be randomly executed BEFORE or AFTER we loaded the tab from the hash, which means that the "myMethod" will randomly be executed once or twice on this tab.

      This happens because there is a nested "require" in the theme_boost/loader and waiting for the theme_boost/loader to load does not guarantee that the nested require will also finish.

      Currently the only solution is the following:

      var timer = setInterval(function() {
          for (var i = 0; i < M.util.complete_js.length; i++) {
              if (M.util.complete_js[i][0] === 'theme_boost/loader:children') {
                  $('a[data-toggle="tab"]').on('shown.bs.tab', myMethod);
                  myMethod($('.nav-link[href="' + window.location.hash + '"]'));
                  clearInterval(timer);
              }
          }
      }, 100);
      

      This is what we currently use in workplace. It could be done nicer if

      theme_boost/loader did not have nested require
      OR
      theme_boost/loader triggered some kind of event in the end saying "Boostrap loaded"

        Attachments

          Activity

            People

            Assignee:
            marina Marina Glancy
            Reporter:
            marina Marina Glancy
            Peer reviewer:
            Andrew Nicols
            Participants:
            Component watchers:
            Andrew Nicols, Jun Pataleta, Michael Hawkins, Shamim Rezaie, Simey Lameze
            Votes:
            0 Vote for this issue
            Watchers:
            5 Start watching this issue

              Dates

              Created:
              Updated:
              Resolved:

                Time Tracking

                Estimated:
                Original Estimate - Not Specified
                Not Specified
                Remaining:
                Remaining Estimate - 0 minutes
                0m
                Logged:
                Time Spent - 2 hours, 25 minutes
                2h 25m