JavaScript first-class function limitation

Yesterday I needed to use a specific Object Oriented pattern to program a JavaScript module. My module was kind of a big object that contains other objects (sub-module).

The object literal notation

var bigModule = {

        subModule1: {
                method1: function () { },
                method2: function () { }
        },

        subModule2: {
                method1: function () { },
                method2: function () { }
        }

};

Because I needed to use closures for the module and it’s sub-modules, so I can keep the state of my system within the proper module, I didn’t want to use the object literal notation to code my module.

Instead I used functions to return my module properties, so I can declare variables just above the return statement of the module, so every properties can access them EVEN WHEN the function will return, e.g. until the program is loaded in memory.

The real way I did it

var bigModule = function () {
        var foo;

        return {

                subModule1: function () {
                        var bar;

                        return {
                                method1: function () { },
                                method2: function () { }
                        };
                }(),

                subModule2: function () {
                        var bar;

                        return {
                                method1: function () { },
                                method2: function () { }
                        };
                }()

        };

}();

I realized that it was not possible to refer to the properties of the precedent subModules within a subModule closure section (above the return statement), since the subModules are not an object literal, but a function that return an object.

I was astonished that I cannot access the bigModule properties, but deeper from within another function:

var bigModule = undefined; // used for the debugging
                           // purpose of this article
                           // to make sure it has never
                           // already returned the object.
var bigModule = function () {
        var foo;

        return {

                subModule1: function () {
                        var bar;

                        return {
                                method1: function () {
                                        alert("subModule1.method1() called");
                                },
                                method2: function () { }
                        };
                }(),

                subModule2: function () {
                        // Error: bigModule has no properties //
                        bigModule.subModule1.method1();

                        return {
                                method1: function () {
                                        // OK!, bigModule has already returned here //
                                        bigModule.subModule1.method1();
                                },
                                method2: function () { }
                        };
                }()

        };

}();

Even if I can do some hacks (some ugly, some ok, depending of what I want to achieve) to make it possible to access the bigModule variable once returned, before the return statement of the subModule2 property, I’m still confused and wonder if that pattern of programmation is really powerful or is limited (e.g. nested function literals).

I’m going to study it and understand that behavior. It seems that a function literal won’t be executed until it stops stacking deeper function literals.

Any explications?

Filed under: JavaScript | Comments (0)

The jQuery later “plugin”

You can extend jQuery.fn by assigning a later function to it to avoid always defining a callback function just to use setTimeout. later returns the object that called the function, so it do not breaks the chainability magic in jQuery.

The later plugin for jQuery

[ Thanks to Douglas Crockford for his teaching ]

jQuery.fn.later = function(msec, method) {
    var that = this;
    var args = Array.prototype.slice.apply(arguments, [2]);
    if (typeof method === "string") {
        method = that[method];
    }
    setTimeout(function () {
        method.apply(that, args);
    }, msec);
    return that;
};

It was almost my first plugin, but that is too short to make it a plugin :-)

It is more likely a feature. Let’s see examples of how to use it.

Samples of use for the later function

// Show "Saved!" for 3 seconds
$(‘#myid’).before("Saved!")
.prev().later(3000, "hide");

// Show "Saved!" for 3 seconds, hiding slowly
$(‘#myid’).before("Saved!")
.prev().later(3000, "hide", "slow");

// Chaining later …
// Change the appearance of the list for 4 seconds,
//   show a "saved" notice before it
//   and fade it slowly 3 seconds after if appears
$(‘#list_id’)
.addClass("success")
.later(4000, "removeClass", "success")
.before("Saved!")
.prev()
.later(7000, "fadeOut", "slow");

When *not* to use it

  • If you want to call a jQuery function right after an effect has finished, use the jQuery callback instead
  • If you are unsure that the function called by later will be executed after the previous one has finished and that the order matters

When to use it

  • If you can’t or don’t want to use the jQuery callback function
  • You would use the jQuery callback function just to use the setTimeout function to join two actions that are not dependent
  • When you can control the exact sequence of execution and you are sure it will be executed in that order

I’ve post a small article on using the later method with your own object. Read it.

Filed under: JavaScript | Comments (0)

later is better

I really enjoy hanging out at the YUI theater sometimes. There are very good conferences given mainly by the Yahoo! staff. I particularly like those one from Douglas Crockford, a Yahoo! JavaScript architect teach us very good stuff. In his “Advanced JavaScript” talk, he gives us a more OO solution to the setTimeout function. Let’s look at the later function code

The later function

Object.prototype.later = function(msec, method) {
    var that = this;
    var args = Array.prototype.slice.apply(arguments, [2]);
    if (typeof method === "string") {
        method = that[method];
    }
    setTimeout(function () {
        method.apply(that, args);
    }, msec);
    return that;
};

Examples of use

var duck = {
    say: function(what) {
        alert(what);
    },
    shout: function(n, what) {
        for (var i = 0; i < n; i++) {
            this.say(what.toUpperCase());
        }
    }
};

duck.later(6000, "say", "Quack!").later(12000, "shout", 3, "Quack!");

Arguments [2..n] are the arguments to pass to the function

Since it extends Object itself, later will be available to every functions. That is a very bad idea to extend the Object prototype. Why? Because you don’t want to break code that is not yours, as with libraries or api. Looping over each properties of that Object is often the only way they have to accomplish their goal. We must never touch the Object prototype. I know, I b
reak my code using that later function with jQuery.

If you do not use any code that’s not yours, you can augment Object.prototype otherwise you’ll have to find another way not to break other’s code. In order to use later you could extend your own object depending on the pattern you use for programming JavaScript. The following is an example of how you could use it.

The later function in a simple pattern

function Animal() {}

Animal.prototype.later = function(msec, method) {
  var that = this,
      args = Array.prototype.slice.apply(arguments, [2]);
  if (typeof method === "string") {
    method = that[method];
  }
  setTimeout(function () {
    method.apply(that, args);
  }, msec);
  return that;
};

Animal.prototype.say = function(what) {
    alert(what);
};

Animal.prototype.shout = function(n, what) {
    for (var i = 0; i < n; i++) {
        this.say(what.toUpperCase());
    }
};

duck = new Animal();
duck.later(6000, "say", "Quack!").later(12000, "shout", 3, "Quack!");

Update: How to use the later function through chaining in jQuery? Read my post.

Filed under: JavaScript | Comments (0)

jQuery + Rails ( Part 1 )

This article is not really about jRails but about unobtrusive JavaScript in Rails using jQuery.

So I decided to switch to jQuery for my Ruby on Rails apps. I’m quite enthusiast and the whole thing about this turnover is that I figured out that it makes sense. There is few talks about it, some have made the move. There is even a plugin that will make almost all your helpers you wrote in ERB works without you need to do anything about it. Many of your RJS code will still work. You can look at which of those features will still work out-of-the-box here.

I’m speaking about replacing completely Prototype and Scriptaculous by jQuery here, got it?


In fact, the difference in sensibilities [between Prototype and jQuery] is very similar to the difference in sensibilities between Java and Ruby, so it’s ironic that the Rails community has embraced Prototype so completely

Why jQuery and Rails together makes sense?

  • jQuery has tons of plugins, just like Ruby on Rails
  • jQuery is completely unobtrusive (MVC is great, but for Web applications MVC + J is better)
  • javascript with jQuery is fun, Ruby is fun, Rails is fun
  • jQuery design philosophy rules
  • The community is big and active

Tutorial: An unobtrusive ajax sortable list updated live

Prerequisites to follow my example

1) You might want ot create a new rails application. We will need Rails 2, in order to use the new “js.erb” template (those aren’t RJS, see further in this article)

Tips: Do not use the rails binary from rails installed as a gem if you plan to upgrade to edge. In that case use the edge binary:

$ svn co http://dev.rubyonrails.com/svn/rails/trunk rails
$ ruby rails/railties/bin/rails foo
$ mv rails foo/vendor
$ cd foo

… and you’re on silly edge! :-)

2) Remove everything in public/javascripts except application.js and put the jQuery file there. Also we will u
se the Interface jQuery plugin. You can download only the UI components you need. Here we’ll need the Sortable modul
e. Put that downloaded file in your javascript folder too.

3) To simplify this example we will not protect ourself from forgery for now. I will give a solution to this in a further post. So in your app/controllers/application.rb, comment the following line

#protect_from_forgery # :secret => ‘e46918532966a85b851ddeeeec50207d’

4) Update your config/database.yml if needed, create the development DB then start your server and jump into a first example.

We won’t need jRails for now. I could have install it and use the sortable helper that do exactly what the one from Scriptaculous do, but we will later need to
update a list via Ajax and for that reason, we will use the Interface plugin to keep it updated live as new contacts get add by an Ajax form (look further post).

Setup

Let the scaffold generator generates everything we need for our contact resource

$ ./script/generate scaffold contact email:string position:integer
$ rake db:migrate

Point out your browser to http://localhost:3000/contacts to see if you don’t have any errors. Add up as many contacts as you want for testing purpose.

You now must add the needed JavaScripts files. Add those into app/views/layouts/contacts.html.erb. It should almost looks like this.

<%= javascript_include_tag ‘jquery.js’ %>
<%= javascript_include_tag ‘interface.js’ %>
<%= javascript_include_tag ‘application.js’ %>

Now open app/controllers/contacts_controller.rb and update the code in the index action to sort the contacts by their position.

@contacts = Contact.find(:all).sort_by { |t| t.position }

Create the list

Now we will create the list for the index template. Don’t remove the existing code so we can keep the links to our actions. Add the code just add the following at the end of the app/views/contacts/index.html.erb file:

<h1>Unobtrusive Ajax Sortable List</h1>
<ul id="this_id_is_just_needed">
  <% for contact in @contacts %>
<li id="contact_<%= contact.id %>" class="sortableitem">
      <%= contact.email %></li>
<% end %></ul>
 

Note: The “ul” element just need an id. Otherwise, some of the sortable functions won’t work.

Making the list sortable

It’s time to add behavior to our plain html. We will do this in public/javascripts/application.js. That is what we call unobtrusive JavaScript because we didn’t use any helper in our index templat
e that generate javascript. jQuery is especially nice doing that because it makes it easy to select elements and apply behaviors on them. The following is the code I use to make it. I’ve DRY it out to make it e
asier to maintain. It is fully commented, I let you read and I’ll explain after.

/* Waiting for the DOM */
$(document).ready(function () {

    /*
     * The global object of the application.
     * It acts as a namespace to avoid collision
     * with any other code
     */

    if (typeof MYAPP == "undefined") {
        var MYAPP = {};
    }

    /*
     * This is our version of Interface Sortable.
     *
     * All Sortable options have predecedence
     * over the default set here.
     *
     * We don’t have to care about Ajax here other than
     * posting the serialized data to an url. Data have been
     * already serialized by Sortable before calling "onchange".
     *
     * Ajax events should hook the post request before it is sent
     * in order to set the correct header and datatype.
     *
     * @param {Array || Element}
     *                  selector  The css selector
     * @param {funct}   fn        The Sortable function
     * @param {object}  opt       The Sortable options
     * @param {String}  url       The url to post the data
     *
     * It returns the selector to keep chainability
     * and being consitent with the jQuery philosophy.
     */

    MYAPP.sortable = function (selector, fn, opt, url) {
        opt = $.extend({
            onchange: function (changes) {
               $.post(url, changes[0].hash);
            },
            opacity:   0.7,
            fit:  false,
            accept: ’sortableitem’,
            activeclass : ’sortableactive’,
            hoverclass : ’sortablehover’,
            helperclass : ’sortablehelper’
        }, opt);

        fn.call(selector, opt);
        return selector;
    };

    /*
     * Ajax event.
     * Called before sending any XHR.
     *
     * @params {Event}  evt       The event
     * @params {XHR}    request   The XmlHTTPRequest
     * @params {object} settings  Settings for the POST XHR
     */

    $(document).ajaxSend(function (evt, request, settings) {

        /*
         * If we want to keep the Rails convention where XHR should
         * respond to javascript request,
         * then we must change the header accordingly.
         *
         * The default header is XML.
         * Rails conventions for XML request are not for XHR.
         *
         */

        request.setRequestHeader("Accept", "text/javascript");

        /*
         * Expected server response can be one of the following values
         * => ‘xml’, ’script’, ‘json’ or null
         *
         * null means that we will handle the response ourselves.
         * It is the default option.
         *
         * Because the MVC convention in Rails,
         * it is in the Views that behaviors are defined, not here.
         * Though we cannot use ‘json’ nor ‘xml’, because the server
         * response should have instructions
         * and not contains only datas.
         *
         * The response will have to be evaluated as JavaScript.
         */

        settings.dataType = null;

    });

    /*
     * Ajax event.
     * Called when the server response is successful
     *
     * The server response is plain JavaScript that must be evaluated
     * because we set the dataType to null
     *
     * @params {Event}  evt       The event
     * @params {XHR}    request   The XmlHTTPRequest
     * @params {object} settings  Settings for the POST XHR
     */

    $(document).ajaxSuccess(function (evt, request, settings) {
        eval(request.responseText);

        /* The flash messages and code could be in the server response
         * and/or it could be here in the callback too, but the latter
         * is more generic.
         */

        $("#flash-notice").text("Success");
    });

    /*
     * Ajax event.
     * Called when the server response isn’t successful.
     *
     * It’s up to you to decide how to manage this.
     * In our case, the server error message is:
     *   ajaxOptions.responseText
     */

    $(document).ajaxError(function (XMLHttpRequest, ajaxOptions, thrownError) {
    });

    /*
     * This is where we make the list sortable.
     * Sortable options will overide the defaults.
     * We can chain that function call as we would do
     * with the jQuery object.
     *
     * That line could have been something like
     *    $("ul").Sortable({ … })
     * But I prefer that way, it’s more readable
     */

    MYAPP.sortable($("ul"), $.fn.Sortable, {opacity:   0.5},
        "/contacts/order");

});

Explications

You see that my functions are wrapped in the MYAPP global object. I always to that choosing a better name though. MYAPP.sortable (The last line of the previous code listing) is the function that will call the real jQuery.Sortable function. I’ve written it like that, so we don’t repeat some of the options, like onchange that won’t change. All of the options can be overwrite at the MYAPP.
sortable
call within the arguments. Check out the official Interface documentation for those options.

Hooking Ajax event

The good thing is that we can hook some Ajax events like ajaxSuccess or ajaxSend to define the behavior of our unobtrusive Ajax application. We have define it once we are done for all our Rails Ajax application. It’s completely unobtrusive and DRY.

Defining the order action

In our call on line 136 we set the post url for our list. The action order isn’t yet define in our controller, so we must do it.

#
# POST /contacts/order.js
#
def order

  # An array of ids of contact of their new order
  @ids = params.values.select { |v| v.is_a?(Array) }.first

  # To send to the view, to display the new order
  @order = @ids.join(", ")

  i = 1
  @ids.each do |id|
    # get the last longuest number ending a string
    # and take it as the contact id
    c = Contact.find(id.gsub(/^.*([0-9]+)$/, "\\1"))
    if c.position != i
      c.position = i;
      c.save
    end
    i += 1;
  end

  respond_to do |format|
    format.js
  end
end

Building the server response with POJS + ERB

POJS stands for Plain Old JavaScript. I told you that we won’t use RJS template. We could if we’ve wanted, install the jRails plugin and
use the RJS-style template to generate the JavaScript, just as if it were RJS, because jRails provide the JavaScript helpers needed to replace Prototype / Scriptaculous code by jQuery code. But we won’t write R
JS-like code. Instead of writing ruby code in a “.js.rjs” file, we will write JavaScript with embedded Ruby in a “.js.erb” file. Since Rails 2.0, you can do it. Before Rails 2.0, the minus_mor plugin were needed to do so.

So create the file app/views/contacts/order.js.erb and put the server response code in it:

$("ul")
.after("<span>New order is: <%= @order %></span>")
.next()
.fadeIn("slow", function() {
    var that = this;
    setTimeout(function () {
        $(that).hide("slow");
    }, 4000);
});

We are done! This code just append the new ordered list ids in the order they have been received by the server. It create a new element right after the list with some show and hide fade effects.

I’m quite new to Rails and jQuery and I will appreciate feedback on this.

Filed under: Ruby on Rails | Comments (1)

svndo to do less svn typing

I hack a very small ruby script that allow me to apply any command to my files that I use to manage with the Subversion status subcommand.

Let’s go with an example.
I have made an error deleting files under revision with the unix rm instead of using the svn rm command.

My status now looks like this:

$ svn st
!      db/migrate/015_create_tasks_and_their_relationships.rb
!      db/migrate/010_create_users.rb
!      db/migrate/020_create_categories_and_their_relationships.rb
!      vendor/plugins/exception_notification
!      README
$

Subversion ‘!’ status means that the file is missing, but is in revision. We need to do a svn rm on each of those files.

That’s where svndo come to the rescue. svndo takes as first argument the status reported by the svn st command (’!’ in our example). The arguments 2..n are the command which will be executed on the files matching the giving status.

Let’s try it

$ svndo ! svn rm
svn rm db/migrate/015_create_tasks_and_their_relationships.rb
svn rm db/migrate/010_create_users.rb
svn rm db/migrate/020_create_categories_and_their_relationships.rb
svn rm vendor/plugins/exception_notification
svn rm README
$

What do we got here? svndo shows us each files matching the ‘!’ status and the status is replace by the command that we pass as the last the arguments (2..n). Those commands are not executed until you pipe it to a shell interpreter.

Let’s try it!

$ svndo ! svn rm | sh
D         db/migrate/015_create_tasks_and_their_relationships.rb
D         db/migrate/010_create_users.rb
D         db/migrate/020_create_categories_and_their_relationships.rb
D         vendor/plugins/exception_notification
D         README
$

That’s it! Subversion has deleted your files from the current revision. I found it very useful to add new files and revert changes. You can use svndo to match every svn status code e.g. M ! ? ~ A D and so. You must escape those who will be interpreted by your shell.

I got now problem to use the special bash character ? and ! as the first argument. I only had to do an alias to match most effectively the ~ character, because it’s interpreted by the shell and cannot be pass as-is as an argument (You must escape it)

$ alias svndo~=’svndo ~’

So I can now only use

$ svndo~ some command

instead of

$ svndo \~ some command

*** Update: After Marc-André has posted a comment notifying me the script wasn’t working, I realize that I’ve messed up with regular expressions’ backslashes when posting the code. Thank you Marc-André for your refactoring, your code looks like Ruby code, while mine looks a bit like bash. So I’ve been inspired by you to post that new code. It do exactly what it was doing before, but now you can use the $ character in your command to be replace by the file name who the status is associated with.

It becomes now more flexible.

$ svndo ? mv $ /somewhereelse

That is the svndo script I was talking about.

#!/usr/bin/ruby -w

status, *cmd = ARGV

`svn st`.each do |line|
  if matches = /^#{Regexp.escape(status)}\s+(.*)$/.match(line)
    tmp = cmd.map {|c| c.gsub(/\$/,matches[1])}
    tmp << matches[1] if tmp == cmd
    puts tmp.join(‘ ‘)
  end
end

Refactor this code at: refactormycode.com

Filed under: tools | Comments (5)

Phil Rathe.com is powered by WordPress, theme: Clean Royal