Why doesn’t my jQuery work?

First, a disclaimer. This post is written for (C/)AL developers who are struggling with JavaScript, who copy and paste JavaScript code from Stack Overflow right into VS Code and are happy when it works, and confused when it doesn’t. Still, if you are not a (C/)AL developer but want to learn a bit of JavaScript yourself, this post is not at al about AL, it’s purely about JavaScript, and about demystifying a piece of it that JavaScript developers take for granted, and that developers with experience only with simpler languages (such as AL) find confusing.

Now let’s jump into the point. A friend asked me for help with a control add-in in which “jQuery doesn’t work, I can do jQuery() but I cannot do $()”

This is one of the schoolbook examples of what happens when you don’t isolate scope in JavaScript, so let’s first see what happened, and then let’s see how you can fix it.

What happened?

Everyone is used to do jQuery stuff through the $ variable. Almost every AL control add-in out there does this at some point

What is this $ and why can you access it anyway? $ is a function exposed globally by jQuery and it allows you to invoke jQuery functionality. jQuery in fact exposes two variables globally: jQuery and $ and both refer to the same function, so using either of them achieves exactly the same results. You could say that $ is a shortcut to jQuery. People are using $ simply because it’s simpler to write $(“something”) than jQuery(“something”). It also looks cooler, doesn’t it?

However, JavaScript has a funky trait: it allows variables to be redeclared (if you click the link, search for Redeclaring part, it’s not directly linkable). While “normal” languages would go bananas if you do something like this…

… JavaScript almost couldn’t care less. It’s fine with you doing it as often as you want. It has its function and it’s very useful, but it can also be dangerous.

In short, what happened when your jQuery still works and your $ doesn’t is that you, or somebody else in a script you are using, has redeclared
$.

jQuery does this (effectively, not literally) at the global level:

And his allows you to invoke jQuery functionality either through jQuery or $. However, if you (or someone you trust enough to load their script) does this at the global scope:


… in short, you are screwed.

From that point on jQuery still refers to whatever it used to refer to, but $ refers to “banana”, and while doing jQuery(“whatever”) may make sense, doing “banana”(“whatever”) does a lot less so.

Keep in mind, the officially supported way of invoking jQuery is through the jQuery keyword, and $ is provided just as a shortcut.

How to fix it?

To fix this, you need to do something that nearly all of jQuery examples out there do:


Yes, you’ve seen it, but you never thought it necessary, maybe because you didn’t quite understand the syntax, and for you it all worked without all this (function() {})() scaffolding. But this (function() {})() stuff is essential, and in fact it’s so essential that when you understand what it does and how, you’ll want to use it forever and you’ll want to rewrite all your existing JavaScript code to use it back since you started writing JavaScript.

So, what exactly does (function() {})() do, how, and why?

First of all, in JavaScript, unlike in AL, functions are first-class. It means that you can declare a variable of function type:


… or you can pass a function to another function as an argument (this one is very commonly used!):


… or you can return a function from another function as a return value:


All of these are used a lot in JavaScript. In all of these situations we call these functions anonymous functions, and they are anonymous because they don’t have a name through which you can invoke them (which doesn’t mean you can’t invoke them, it’s just that they don’t have a name).

However, JavaScript has another trait that’s at work here, and that’s the fact that it has expression statements, which means that if it encounters an expression that seemingly does nothing at all, the runtime will still evaluate that expression even though the rest of the code does nothing at all with the return value of an expression. Expressions can be implicit, like:


(where b + c is an implicit expression)

… or explicit:


(where (b + c) is an explicit expression achieved by applying the grouping operator).

Expressions in JavaScript can evaluate to any type, including function type, which is why you can do this:


This simply evaluates to a function. Since it evaluates to a function, you can invoke that function using function invocation syntax () like this:


Obviously, just like any other language, functions can accept arguments, so you could do this:


If it’s not immediately obvious, here you have a function that declares parameters a and b, and returns their sum, then you return that entire function from an expression, and then you immediately invoke that function by passing 1 and 2 to it. This concept is called Immediately Invoked Function Expression and it’s all over the place in JavaScript. If you didn’t click that link, this pattern is also called Self-Executing Anonymous Function, and it’s called that for a reason: it’s an anonymous function that self-executes (kind of, it’s the runtime that executes it, it doesn’t execute itself).

Now, thinking of our original situation (function($) {})(jQuery) it should be obvious why it solves the problem.

First, it declares a function expression for a function that has one parameter $. Then you immediately invoke that function by passing jQuery as its parameter. From within that function parameter $ – which is now in function’s local scope! – hides the global $ (which may refer to jQuery or “banana” or whatever else) and replaces it with whatever jQuery is at time of invocation. So, if you did $ = “banana” but left jQuery variable alone, doing this:


… will allow you to use $ from within your function just like that piece of code you copied from Stack Overflow has it, without having to worry about

What if…

Yes, what if somebody tramples over jQuery the way they trampled over $?

In that case your jQuery is lost and you cannot salvage it. The only way is to find the offending script and get rid of it (or fix it if it’s feasible).

But can you do anything to prevent this kind of thing? No, there isn’t, because anyone can redeclare any variable as they see fit. But yes, there is, because JavaScript is such a beautiful language that it allows you to do things that many other languages cannot do. But let’s talk about in the next post, shall we?

Vjeko

Vjeko has been writing code for living since 1995, and he has shared his knowledge and experience in presentations, articles, blogs, and elsewhere since 2002. Hopelessly curious, passionate about technology, avid language learner no matter human or computer.

This Post Has 9 Comments

    1. Vjeko

      Thanks 🙂 But you know this stuff by now, don’t you – you’ve been to my JavaScript for C/AL Developers workshop.

  1. ajkauffmann

    Thanks for this great explanation!

    1. Vjeko

      You’re welcome!

Leave a Reply