Fixed 2FA setup: "TypeError: $el.qrcode is not a function"

Steffen

Well-known member
Affected version
2.0.2
During "Two-step verification setup", if the JavaScript variable $ is not used by jQuery but by something else then no QR code is shown and the error "TypeError: $el.qrcode is not a function" is logged in the browser console.

This can be fixed by modifying the template "two_step_totp" as follows:
Diff:
--- two_step_totp.tpl    2018-03-05 13:38:28.260078805 +0100
+++ two_step_totp.tpl    2018-03-05 13:38:40.366005709 +0100
@@ -6,9 +6,9 @@
         {{ phrase('totp_enter_secret_into_app_x', {'secret': $secret}) }}
     </xf:formrow>
     <xf:js>
-    $(function()
+    jQuery(function()
     {
-        var $el = $('#js-totpQrCode');
+        var $el = jQuery('#js-totpQrCode');
         $el.qrcode({
             text: '{$otpUrl|escape('js')}'
         });
 
What exactly is the scenario that $ is not used by jQuery? Obviously we expect it to be (and use it extensively throughout our JS code) so I'm not sure we'd consider this a bug.
 
jQuery only sets window.$ if it has not yet been set by another library. If you include another JavaScript library before jQuery that sets window.$ (by modifying templates) then jQuery does not overwrite window.$ and is only accessible via window.jQuery.

All other XenForo JavaScript code is working fine. It's true that your code uses $ a lot but only inside IIFE that explicitly set $ which is fine:
Code:
(function($) {
    // ...
})(jQuery);
 
But the root of the problem is still that you're including a different JavaScript library before jQuery which therefore invalidates our (valid IMO) assumptions. Isn't the solution to include that library after jQuery?
 
That's a valid argument.

On the other hand, all the other XenForo JavaScript code has been explicitly coded to avoid a dependency on window.$ by using the IIFE pattern mentioned above. I wouldn't stop at 99% if the fix is this simple and could reduce future support burden. I probably won't be the last user to include another library. :)

This patch is even simpler:
Diff:
--- two_step_totp.tpl    2018-03-05 13:38:28.260078805 +0100
+++ two_step_totp.tpl    2018-03-05 14:01:29.355901325 +0100
@@ -6,7 +6,7 @@
         {{ phrase('totp_enter_secret_into_app_x', {'secret': $secret}) }}
     </xf:formrow>
     <xf:js>
-    $(function()
+    jQuery(function($)
     {
         var $el = $('#js-totpQrCode');
         $el.qrcode({
 
Top Bottom