Name.Spacing (see what I did there?)
The first thing to note when working on projects is that we always namespace our scripts and where possible we make sure the namespacing is descriptive (conveys direct meaning for the purpose of the script). When we can, make sure we keep the script self-contained and modular (no namespace declarations for the script external to the script). Throughout the guide, I will highlight snippets of js with colours to highlight what I am referring to in my explanations, keep an eye on this.
Let’s look at a quick example. We may have a project called News project which, being under the scope of My Project, will be under the following namespace: MyCompany.MyProject.
So with this in mind, we know that all of our controls will use this common namespacing, this is a good piece of code to put in a global script to the project called ‘Namespaces.js’.
Setting up a Namespace
Now we have the namespace setup, we don’t need to declare it any more, we can just use it. Take a look at this extract from the News CreateArticle.js script, to see how we should be utilising this new namespace in our scripts.
So we have an anonymous self-invoking function, which passes in two parameters, the first being the namepace (declared in the same way we did in the namepsace script, to ensure it is setup correctly) and then the jQuery object.
So, looking at the above script you can see that the namespace object within our anonymous function is held within the ‘my‘ variable and the jQuery object is now a local variable called ‘$‘.
So, let’s take a look at how we can use these in this next section, by taking an abbreviated MyCompany.MyProject.News projects CreateArticle.js script code as a real world scenario.
Utilising Namespaces in Shorthand
There are a couple of things to note from the function shown in the snippet above (the inner code isn’t that important right now), the first of which I will discuss in this section and then I will continue to elaborate on the other points as we go through the subsequent parts of this tutorial.
We have now got our local variable which has been passed into our anonymous function, known as my. The parameter my is of course MyCompany.MyProject but you know that already so this is the last time I will mention it. Seeing as we now have this variable we can create additional variables and functions from it. There’s no need to declare this new function as a new var, because it is an extension of MyCompany.MyProject and that object is already instantiated.
So as long as we are inside the scope of this anonymous function, we can create all of our public functions using this shorthand.
When creating functions and variables within JS we must ensure that they are named descriptively but sensibly. I have seen functions called things like ‘DoWork‘ and ‘RenderColumn1‘. This should make you as angry as it makes me. It is lazy, counter intuitive and creates obfuscation by sheer bad practice.
This goes for variables as well, things like ‘collectionoflistItemsfromfooterlistfordaveinfinanceandsallyinmarketing’ and then the opposite of over descriptive names such ‘string1’. No, don’t do this. It makes me angry even typing it and it should make you angry to.
So, follow the rules below to make sure you are doing it right for naming functions and variables:
- Then follow this by a lower case letter if it is exposed globally (externally from the scope of your script).
- The difference being, with local private functions, make sure they start with an underscore before the lower case letter.
- All subsequent words in the function or variable should start with an upper case Letter (e.g. _variableName or variableName if it is public).
- The first word of a function should be a verb (action) describing what it is for (e.g. Get, Set, Update, Delete)
Make sure the function is descriptive in short hand, do not elaborate more than is necessary but make sure it conveys it’s intended purpose.
- If you have a local private variable used for storing a collection of user profile properties call it ‘_userProfileProperties‘ or even shorter and perhaps better ‘_userProperties‘ (it should be obvious from the code it’s a collection).
- If you have a global function which is used to set footer links, call it ‘SetFooterLinks‘.
Public vs Private
Most of the time this should be avoided at all costs (just like how you avoid doing this with server side code like c#). The reasons for avoiding this, is for the same reasons as why you avoid it on server side code, you are exposing your functions and variables for use, potentially in a way that you did not intend (this breeds bugs and can lead to people changing your code for their own purposes without thinking about how it will affect your functionality).
So, the ‘public vs private‘ rules are as follows:
- Only make a variable or function globally accessible (public) if it needs to be for the intended functionality to work
- Make sure you follow the steps in the naming convention section of this guide, to ensure that the variables and functions are named in such a way it is obvious that it is private or public
Really Really Basic Syntax Mistakes
- Make sure you do not miss off semi-colons from the end of lines
- For the love of god do not put jQuery in KnockOut
- Make sure your code is efficient. If you have copied and pasted something from another project or from the internet, make sure that it does exactly what you need with minimal overhead
- Remember that you can use both single and double quotes in JS. Take advantage of this and do not escape quotes if you can use the alternative
- Avoid putting HTML mark-up in your JS. Use knockout or Angular to avoid these scenarios.
- Follow the rules in this guide, it will make you a better human being.
Careless Self Invocation
Do not make a function self-invoking unless it needs to be. For example, if you have a footer script that needs to run on every page after page load, this is an excellent candidate for a self-invoking function (a function that runs when it has loaded). Most of the time, your code can run from a Script Editor webpart or from an event being fired, so please take some time to think about this before you write your script.
Comparisons (Conditional Statements)
You can see that we are using a non-exact comparison between the two. This means that if_news.count was for some reason or another is of type ‘string’ and _target.count was of type ‘integer’, then the example would return true (which isn’t the case). So when is it ok to use a non-exact comparison?
Well the answer to this is in all scenarios apart from one, you should always do an exact comparison. The only time it’s ok is when you need to check if something is either null or undefined. Using a non-exact comparison will do that for you by simply checking for a null (e.g._counter == null is the same as _counter === null || _counter === undefined). Anyway, let’s take a look at an exact comparison:
The only thing we changed was the comparison operand, using an extra equals in the conditional statement allows us to do an exact comparison. The usual response I get from this, is that they need the above example to equate to true, and the answer is always the following:
Ensure that the variables you are comparing are of the same type before comparing them (if they are not, make them so).
The next thing to mention here, is that when you have lots of conditions in your conditional statement, consider using a switch statement instead of an if statement. It makes the code a lot more legible and improves the flow of logic.
If you don’t use them already, make sure you make use of shorthand comparisons. These are really helpful for variable assignment and to show how much they can help, I have pulled together a quick example (the first snippet that follows, shows how you could instantiate a new variable and then depending on a condition, assign it a value).
This code be abbreviated to the following snippet, using shorthand code:
So this works by checking to see if the statement equates to true, if it does then the variable equals what’s after the question mark. If it does not, then the variable _counter equals what is after the colon.
I have seen in a lot of scripts, a litany of local variables used for storing config or option settings. Seeing as all of these variables are for essentially a common task, you should probably look into encapsulating them inside a _config or _option object like below:
Then, not only do you have a nice encapsulated array object with your variables, you can also use intellisense to easily get at these whilst writing your code (which is awesome).
Ensuring You Have What You Need
Always, without exception, make sure that the necessary scripts have loaded before running your code. You can do this easily by using the built in SP.SOD.executeFunc function, like in the following example:
You can also nest these to ensure that several scripts have been loaded before running your code (in this case SP.ClientContext which is found in the SP.js file and SP.Publishing which is found in the SP.Publishing.js file):
The next thing to note is that often when controls and functionality is coded in isolation, they tend to do their own data calls and this can sometimes become dangerous. If you have a page , that has the scenario where multiple controls each need to use the same data source. For example they each called the user profile service and then made use of one or more properties returned.
You can see how this would affect page load times and the efficiency of the site. Each control, calling this endpoint and retrieving the data independently. So this could be changed, so that we call this endpoint once, and then consume the result set returned by this asynchronous call, in each of the controls on the page.
The main thing to take away from this point is, from a functional point of view, is the data you need, needed on other controls on the given page. If it is, then re-structure what you are doing to make this so (avoiding the need for other users to re-purpose your code or refactor what you have done).
Notifying that your Script has Loaded
Script dependencies as discussed in the ‘Ensuring You Have What You Need’ section of this guide, we can tap into what SharePoint does within notification that a script or function has finished loading/executing.
You can do this by putting in a line of code at the end of your script that ends like the following:
This way, later, within other scripts (like within JSLink files or Display templates), we can run ensure that our main JS file has been loaded, with the well-known:
Promises or Subscriptions
Promises are great, you give them, then you fulfil them and then something else happens. They have numerous applications, but they also have the tendency to breed spaghetti code. Not as much as nested Async call back delegates do, but they still do to some extent. The other problem they can have is they rely on the code being in one place. You call off to modular functions elsewhere but that calling code, needs to sit somewhere in the promises chain. So there are some scenarios where promises restrict the modularity of your code (this is where subscription events come into play).
A subscription widget takes the following shape:
You can see that we are extending the jQuery library, to add a new widget called SubscriptionEvent which has three callback events (publish, subscribe and unsubscribe). This means that we can run some code which when it completes, notifies any subscribing code, that it is ok to execute. To take a look at how this is done, look at some example code of how we setup a piece of code which will not run until it is told to do so (subscribing):
Now, you can see that the subscription takes a name, which means you can have multiple subscription event stems happening at any one time. The second thing to notice is that the delegate callback function (the function that fires when the subscription event is told it’s ok to do so) can be parsed one or more parameters (in this case, a variable called ‘data‘).
Now, on the other side of this paradigm, the trigger that lets these code block(s) run, would look something like the following:
Nice and easy, simply providing the same name for the subscription event and then publishing the variable(s) to any subscribing code snippets.
This is the penultimate section of the guide and with it, I will give you some points I really want you to think about when creating your script.
- Will your code need to be reused on other scripts? If it does, make it as modular as possible and if it does not need to do a data call or interact with the DOM, integrate it into a global project so that it can be reused without effort. Reduce technical debt and ensure that where possible, code is accessible and modular.
- Avoid cross domain calls, they are a headache and should be avoided at costs. Rethink what you are trying to do and find another way around it, no matter how tempting it is to look at this.
- Make sure your functions are trying to do only one thing. If it spirals into more than this, take a step back and refactor what you have done, so this is not the case.
- Do not host a script in a remote project which needs to interact with the DOM or do a cross domain call.
- Be careful with caching on jQuery Ajax calls. On chrome and Firefox, this can cause problems with the back button and history object.
- If you learn how to do something new, that no one else has done yet, tell the other people working on your project
- Keep comments to a necessary minimum, your code when written correctly should explain what’s going on. Only comment what’s needed (a particularly tricky sequence events, an explanation for doing something a different way etc…).
- Where possible use while loops instead of for loops as they are much more performant.
Questions and Answers
When is it Private and when is it Global?
A fairly common question about self-invoking functions, which I thought I would delve into and elaborate on to a wider audience. The question was, if you make a function self-invoke, does this not make all it’s variables and functions global?
So this is a fair question that probably requires a more in-depth answer. The short answer is that it does not make any internal variable or function global (e.g. accessible once the self-invoking function has loaded), it can make private functions run if they are also self-invoking or if they are called directly from code.
So taking the following code snippet, you can see the different scenarios that you may come across..
Now you can see from the above that we have an internal private function which self-invokes (see the bold brackets at the end of ‘_iAmNotGlobalButIDoRunAutomatically’), you could have written the following and it would have done the same thing:
So out of the above, if you copy and paste this into you console window on Chrome or IE, you can then only access to of these functions (with the namespace being one of them):