Dec 2 2013

JavaScript Intensive Web Application 1: Getting JavaScript Intellisense

Category: JavascriptFrancesco @ 03:43

JavaScript Intensive Web Applications 2: Enhancing Html with JavaScript

JavaScript Intensive Web Applications 3: Enhancing Applications with Ajax

This is the first of a series of tutorials on the use of client techniques in Web Applications. We will discuss when it is convenient to use Ajax, or JavaScript intensive Web pages, or Json communication or Single Page Applications, and how to solve some typical “nightmares” that these techniques bring with them.

In this first tutorial we will try to remove (or just to lower…) one of the main barriers that discourages the development of large JavaScript codebases: the absence of syntax checks and Visual Studio Intellisense comparable with the ones we have in other strongly typed languages.

Actually Visual Studio and a lot of other JavaScript editors are able to signal immediately pure syntax errors. The main problem is that they are not so smart also in inferring types, and  consequently in furnishing adequate intellisense. The reason of this incapability are basically two:

  1. JavaScript is a dynamic, not strongly typed language. This means that the same variable or function parameter may store different data types, and that consequently the JavaScript editor cannot rely on the variable/parameter data type to perform type checking and to give adequate intellisense.
  2. JavaScript contains no concept of module  reference and/or linking, so a JavaScript file comes to know all details about external functions and prototypes only at run-time when all needed modules are for sure available.

Visual studio offers tools for resolving easily the second problem: namely when you are in a JavaScript file you may add some kind of references to other JavaScript files used by the current module by using the syntax of Xml comments. Xml comments are JavaScript comments composed by /// followed by adequate Xml expressions. Since they are comments they are ignored by both JavaScript minifiers and JavaScript's interpreters.

The syntax for a JavaScript reference Xml comment is basically:

  1. /// <reference path="/path/subpath/..../JavascriptFileToReference.js" />

We may use also “~” to denotes the root of our web application.

When we are editing a JavaScript file, it is enough to drag the file we would like to include from the Solution Explorer to the file we are editing to get automatically the reference Xml comment.

If a JavaScript file is included in an Html page or .cshtml page there is no need to reference it also with a reference Xml comment to get JavaScript help on its code. However, often Html, or .cshtml files use JavaScript files that they don’t include directly for different reasons such as: 1) they might use code retrieved via AMD, 2) the JavaScript files might be included in a _Layout page or in another .cshtml page in case they are partial views, 3) the .cshtml file might be used to produce a dynamic JavaScript file, instead of an Html page.

In all above cases we may use a reference Xml comment inside the <script> tags that enclose the JavaScript code. However, unluckily, in this case we can’t drag the file to reference but we have to insert the reference Xml comment manually.

So now we are able to reference JavaScript library to get intellisense…so the problem now is to to actually get intellisense on each JavaScript variable. While JavaScript is not strongly typed, starting from Visual studio 2012, the JavaScript intellisense improved a lot, and now Visual Studio is able to infer the type that should be contained in a variable from the previous code. For instance if you write:

(function () {
    var simpleOperation = function () {
        this.mult = function (x, y) {
            return x * y;
        };
    };

and then:

  1. var operation = new simpleOperation();

Then we get help on the variable operation:

jsNewIntellisense

We get the same help also if the object is returned by a farm function:

(function () {
    var simpleOperationFarm = function () {
        return{
            mult: function (x, y) {
                return x * y;
            }
        };   
    }
    var operation = simpleOperationFarm();

 

jsFarmIntellisense

 

 

 

 

 

In general Visual Studio >= 2012 do the best to infer a type from a static analysis of the code. However, very often static analysis is not able to infer types in a dynamic language like JavaScript.

However, we may use a couple of tricks to “pass” to Visual studio the information on the types contained in a variable or parameter.

The first trick may be applied to the parameters of a function: immediately after the parameters declaration we may place a param Xml comment:

function (operation) {
        /// <param name = "operation" value = "new simpleOperation()"/>

The value attribute may contain any JavaScript expression, but typically we put, a creation operation, a farm function, a simple value (such as an integer, or a string), an array, an object, or nested arrays and objects. Below, a suitable value to get help on objects that are elements of an array:

paramsIntellisense1

 

Notwithstanding some syntax error…we get our intellisense!

We might obtain a similar result also with:

function (operation) {
    /// <param name = "operation" value = "[{mult: function(x, y){}}]"/>

 

 

Now we are able to get help on each function parameter…but often knowing the type of the function parameters is not enough to infer the type of each variable that is local to that function, or the type of an object manipulated by the function…(for instance because they were not passed as a parameter, but it is part of the function closure). Moreover, sometimes JavaScript functions accept parameters that may take several different types.

Now, we may call a method or to read/set a property of an object in a given place of a JavaScript function only if we know that in that part of code a member or variable must necessarily contain a given type, because we must be sure the property or method we are referring to actually exists! Thus, let suppose that we know that in some part of our code the type of the variable operation, or the type of the member mayObject.operation must be SimpleOperation, then we may enclose  that part of our code in a function:

 

 

(function (..., operation, ...) {
    /// <param name = "operation" value = "new simpleOperation()"/>
    // now we may get intellisense
    ...
    ...
    ...
})(..., myObject.operation, ...);

 

 

in case we can’t enclose the code inside a function we may use this other trick:

 

myObject.operation = myObject.operation || new simpleOperation();

 

Since we supposed we are sure myObject.operation contains a simpleOperation,  the second operand of || will never be evaluated, so our instruction do simply…nothing but helping VisualStudio to infer the type of myObject.operation .

Needless to say the second operand of the above || may contain the same kind of expressions of the value attribute of the param Xml attribute.

The above tricks enable us to get intellisense in any situation! Thus the main nightmare of JavaScript coding has been “mitigated”!

 

That’s all for now!

In the next post a deeper analysis of JavaScript intensive Web techniques.

 

Stay tuned!

Francesco

Tags: , , , , ,