Sunday, July 14, 2013

Listen/Watch for object or array changes in Javascript with Watch.JS

I was assigned to project in which it was desired to migrate from a Backbone project to plain jQuery/Javascript project. As you may know, Backbone is a Javascript framework which embodies your application in a MVC platform. The nice thing about a backbone model is that it is an object literal with an array of attributes which you get either with model.attributes or model.get("attribute's name"):
var AppModel = Backbone.Model.extend({

    // Model instance members go here ...

    defaults: {
        //Default model attributes
    },

    initialize: function() {
        // This line will watch for changes in model object and will call the callback
        // i.e. The killer famous line!
        this.listenTo(this, "change", callback);
    }
});

Whenever the model in your backbone application changes you can handle the "change" event in a pretty neat way like this:

object.listenTo(other, event, callback)

As you see the model.listenTo has three arguments: First is the model object, second is the type of event to be captured and finally the callback function which will be fired in case that event will happen. 

So the idea here is to implement the same model.listenTo "change" method on the object literal or the model. I started looking at different stackoverflow discussions and finally made my decision. The solution (well, at least one of best ones to be fair) exists in a well-written library called Watch.JS. The weird thing about this case is that browser have different approaches regarding this. For example there is a sweat property on the Object prototype called Watch. I guess the idea behind Watch.JS is actually coming from there. 

The steps needs to be taken are quite simple. First, add the source of Watch.js, Second create an object literal and third, enable watch for the object/array and attach a callback function to it, like the following chunk of code:
 
   var defaultModelAttributes = {
      personName: "Amir Rahnama"
   };

   //defining a 'watcher' for an attribute of your object literal / array
   watch(defaultModelAttributes, "personName", function() {
     alert("personName value changed!");
   });

   //when changing the attribute its watcher will be invoked
   defaultModelAttributes.personName = "A stupid guy";

You can also look for all changes in the same object literal by changing line 11 with the followings:
watch(defaultModelAttributes, function() { ... });

You can also set how deep you would like your changes to be watched, just pass in a depth token to the watch function after you declare the callback function, as in the following:

var defaultModelAttributes = {
    person: {
        personId: "870718-5768",
        personName: {
            firstName: "Amir",
            lastName: "Rahnama"
        }           
    }
    };

    watch(defaultModelAttributes, function(){
        alert("defaultModelAttributes is changed");
    }, 2);

    defaultModelAttributes.person.personName.lastName = "Akhavan";

UPDATE: I tried to use the library with RequireJS, but I believe that there should be a compatibility issues, there. I do not know the reason yet, but in case you are interested here is the link to issue on WatchJS Github page: Setting an object literal attribute with RequireJS does not trigger the passed callback function.

Friday, July 12, 2013

var that=this in Javascript

If you have ever saw or read any open-source library in Javascript, I can assure you at least in one part of the code, you will see something like following:
var that = this;
You may wonder why is that so? Well, in short answer it is because of how Javascipt defined its scope. In many modern programming languages the type of scope is a block scope. In block scope, everything which is wrapped inside a curly brace will not be visible outside of the braces. In Javascript, it is functions scope. What does that mean? It means that a scope unit in defined within function, and all variables which are defined within the function are not accessible outside of that function. In Javascript it is very common that you define a function inside a function, whether that is a function of an object literal, or closures. Actually the case with our case mainly happens within such case.

Ok, So let us consider a very common case in Javascript programming. Let us say that you have created an object literal:

var person = {
 id : 1
}; 

Now let us say that you need to augment that object literal. Here, we are trying to do this:

person.augmentInfo = function () {
   var setNewId = function () {
    
   // this here does not refer to the person context, but rather to setNewId function
   // therefore the following line cannot set the new Id 
           
   this.id = 3;
 }

 setNewId();
};

Now if you check whether new id has been set or not, you see that it has not! Check the following lines yourself:
myObject.augmentInfo();
console.log(myObject.id); //undefined is logged

So basically the reason why we use that notation is when going inside a new scope zone, you can save the value of this in the outter scope to be able to access variables and methods in the outter context from the inside context.


person.augmentInfo = function ()
{
        var that = this;
        
        var setNewId = function () {
    
            // this here does not refer to the person context, but rather to setNewId function
            // therefore the following line cannot set the new Id 
           
            that.id = 3;
        }

        setNewId();
};

Now if you verify it, you can see that right now, the newId is being set corrently.

myObject.augmentInfo();
console.log(myObject.id); //3 is logged, correctly

Monday, July 8, 2013

Load jQuery UI with requireJS

RequireJS is one popular script loading framework out on the web. At the same time, most of the web applications and websites are now using jQuery and there are quiet a lot of them that use jQuery UI as well. You may know that jQuery UI is dependent on jQuery, meaning that in order for jQuery UI to load correctly, jQuery should be loaded first.

In older version of RequireJS, it was a lot more harder (and ugglier you may say) to include jQuery UI since the jQuery UI library (unlike jQuery) is not following an  Asynchronous Module Definition  (AMD) style. Then you need to include AMD-enabled scripts which were built within communities and especially James Burke. However, in the last versions of RequireJS, a lot of features were added regarding this.

Remark: If you are not familiar with Asynchronous Module Definition (AMD) and interested to know more, read this article Why AMD?

So let's get on with it. I presume that you are following a folder structure like this:




Here is how you minimal index.html file should look like:


    sample_app
    




One of the scripts that handles a lot of key information is the one attributed with data-main (i.e. main which stands for main.js). In this script you can define your library paths and a tag called shim which handles dependencies and non-AMD module loading. After that there is the code on how application will continue its initialisation process. This looks something like:


require.config({
    paths: {
        "jQuery": "../libs/jQuery//jquery-1.9.1",
        "jQueryUI": "../libs/jQueryUI/jquery-ui-1.10.3.custom"
    },
    shim: {
        "jQueryUI": {
            export:"$" ,
            deps: ['jQuery']
        }
    }
});

require(["app"], function(App)
{
    App.initialize();
});

As you can see with the paths you are declaring a key-value pair of library conventions and paths and with shim, you are flagging the non-AMD modules which in this case is also dependes on jQuery. In the last step, add the following to your app.js file:

define(["jQuery", "jQueryUI", "guiFunctions"], function ()
{
   var initialize = function ()
   {
      //jQuery, jQuery UI are added here now ...
   };
  
   return {
      initialize : initialize
   };
});
And that is it!

Monday, July 1, 2013

How to migrate from live() method in jQuery 1.9?

As jQuery documentation says it here, the famous live() method has been completely removed in jQuery 1.9, so you have to migrate from it, anyhow.

It is actually quiet simple. The jQuery Library has introduced a method called on() which is even more complete in what live() method was doing. The following is its signature:

.on( events [, selector ] [, data ], handler(eventObject) )

where events is of type String  and it is one or more space-separated event types and optional namespaces, such as "click" or "change", selector is also of type String and it is the selector string to filter the descendants of the selected elements that trigger the event. If the selector is null or omitted, the event is always triggered when it reaches the selected element. Data can be of any type and it is passed to the handler in event.data when an event is triggered, and lastly, handler is of type Function (to execute when the event is triggered).

There exist a rough formula to change your methods from live() to use on(), instead. Have a look at my example:
// This is the old live() method
$("#element-id").live('change', function(){ 
  // Event handler code goes here ...
});

//This is its equivalent in jQuery 1.9
$(document).on('change', "#element-id", function(){
  // Event handler code goes here ...
});
Were you able to find the formula? It is quiet easy: Change the place of first argument of live method to the third one in on(). Add the root DOM element to the first parameter of on() method and keep the event type. That's it!