Binding Events The Right Way

March 19, 2012

On of the interesting new things that Javascript 1.8.5 introduced is something that we were doing for long time – binding functions to events while controlling the context of called method. If up until now we used tricks like closures to create this binding, now this is built into the language.

Binding Events

This is a task that any JS developer has done million times – registering to an event by providing some method. On jQuery it usually looks something like this:


$(".myclass").click( function(e){
    //do something
});

In this case we created an anonymous function that handle the event. The context of this function is the target element. For example, if this would be a handler for a click on a button then the “this” keyword will be the button element.

when writing in object oriented approach usually we have some class that handle specific logic in the page. If this class also needs to register to some events the previous implementation will need to be adopted to something like this:


function AppLogic(){
    this.init();
};
AppLogic.prototype = {
    init: function(){
        this._bind();
    },
    _bind: function(){
        var self = this;
        $("#button1").click(function(e){
            self._onButtonClick(e);
        }
    },
    _onButtonClick: function(e){
        //do something
    }
};

var app = new AppLogic();

In this example, we created a handler method called _onButtonClick and we called it from the anonymous function but making sure the context is the AppLogic instance using the self variable.

The bind Method

This implementation or variation of it has been done so many times, that i think it was decided to make our life easier and introduce the bind method.

The bind method is a method that can be invoked on functions in javascript as follow:

function.bind( context, [arg1[, arg2 ... ]] );

Lets the the previous example if the use of this method:


function AppLogic(){
    this.init();
};
AppLogic.prototype = {
    init: function(){
        this._bind();
    },
    _bind: function(){
        $("#button1").click( this._onButtonClick.bind(this) );
    },
    _onButtonClick: function(e){
        //do something
    }
};

var app = new AppLogic();

Now the code looks much cleaner and readable (at least to me).

Another thing that the bind method is supporting is additional arguments that are being prepend to the arguments of the called method. Lets check the following example:


<!--
To change this template, choose Tools | Templates
and open the template in the editor.
-->
<!DOCTYPE html>
<html>
  <head>
    <title>Bind Example</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  </head>
  <body>
      <span>Ask me a question: </span><input type="text" /><button>Get an answer 1</button><button>Get answer 2</button>
      <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.js"></script>
      <script>
          function App(){};
          App.prototype = {
              init: function(){
                  this._bind();
              },
              _bind: function(){
                  $(".answer1").click(this._onAnswer.bind(this,1));
                  $(".answer2").click(this._onAnswer.bind(this,2));
              },

              _onAnswer: function(id,e){
                  if( id === 1 ){
                      alert(" i don't know that!");
                  }
                  else{
                      window.location.href = "https://www.google.de/search?q="+$("input").val().replace(/ /g,"+");
                  }
              }
          };

          var app = new App();
          app.init();
      </script>
  </body>
</html>

You can check this code here.

In this example we are registering using bind to different elements but we add an argument of the button id to the bind method. This id is the first argument that we get in the callback. I agree that this is not the best use case for this, but i gives you an idea how you can utilize it.

Browser Support

This feature is currently supported by:

  • Firefox 4
  • Chrome 7
  • IE 9

But what if we want use it also in older browsers?

Bind Compatibility

In order to use the bind method in any browser you can add the following code to your project:


if (!Function.prototype.bind) {
  Function.prototype.bind = function(context) {
    var args = Array.prototype.slice.call(arguments, 1),  //we are saving all the arguments after the context.
        fToBind = this,
        fBound = function () {
          return fToBind.apply( context || window,
                                args.concat(Array.prototype.slice.call(arguments)));
        };
    return fBound;
  };
}

Frameworks Support

This binding mechanism is supported by several libraries out there. The one that i like the most is YUI. in YUI this feature is already built into the framework event mechanism. Everywhere you can register to events YUI gives you the option to provide a context to the callback. Lets see how it looks in jQuery and how it is in YUI


//binding in jQuery
$(".myclass").click(function(e){ self._onEvent(e) } );

//binding in YUI
Y.one(".myclass").on("click" , this._onEvent , this );

I use YUI a lot and i have to say that this is an amazing framework and i have a feeling that it is under appreciated in the industry.

Bookmark and Share

Loading Scripts – Sync or Async

March 12, 2012

In many programming languages we have the concept of including files/scripts in a project. This means that the compiler or the interpreter needs to fetch and read another file. This is one of the building blocks of modern programming.

In JavaScript we don’t have an actual include but we can add scripts to the DOM to make sure they are added to the page. Sometimes scripts can be depended, so one script is using some code which was defined in another. This could lead to some problems if we don’t understand how browsers loads scripts.

Static Scripts

First lets define two scripts which we will use in our examples.

script1.php


<?php
    sleep(3);
    echo "var obj1 = { a : '1' };";
?>

This script is defining an object called obj1. I’ve added a sleep of 3 seconds to make sure it will take some time for the page to download the script.

script2.js


alert( obj1.a );

This script is only trying to alert the object which was defined in script1.

In the static example we add these scripts in the right order in the head or in the body like so:


    <footer> some copyright .... </footer>
    <script src="script1.php"></script>
    <script src="script2.js"></script>
</body>
</html>

When the browser see this it will try to load all the script asynchronously but will execute them synchronously according to the order that they were defined.

So in our case the browser will download script2 before it loads script1, but will execute script2 only after script1 was loaded. This is exactly how we expect it to be. Things get a little different when we are using the dynamic scripts approach.

Dynamic Scripts

In this case we load the scripts using Javascript like so:


var body = document.getElementsByTagName("body")[0];
var s1 = document.createElement("script");
s1.src = "script1.php";
body.appendChild(s1);
var s2 = document.createElement("script");
s2.src = "script2.js";
body.appendChild(s2);           

In this case the same code will be executed differently on different browsers.

Firefox and Chrome will see that in the same CPU cycle we are adding two scripts to the DOM and they will keep the synchronous execution dependency between them. So in Firefox and Chrome executing this code will work, since the browser will execute them in the right order.

in IE (at least IE9) it is implemented differently. IE doesn’t keep this synchronously execution dependency between the two files and execute each file whenever it is loaded. This will cause an error in run time since script2 will be executed before script1 and the object was not defined yet.

To make the difference more clear lets break the CPU cycle like so:


var body = document.getElementsByTagName("body")[0];
var s1 = document.createElement("script");
s1.src = "script1.php";
body.appendChild(s1);
setTimeout( function(){
    var s2 = document.createElement("script");
    s2.src = "script2.js";
    body.appendChild(s2);  }, 1 );

Since the second script is being executed in a different CPU cycle Firefox and Chrome can’t keep the dependency between them anymore and each script is executed when it is loaded, which will result an error in run time.

HTML5 Async Attribute

One interesting feature HTML5 introduced is the ability to control how script will be executed by the browser. If we set this attribute to true on the script tag/element it will tell the browser to executed the script immediately when its loaded. This was introduced in order to allow developers to better control and optimize the loading of scripts. So if i know i need to load many scripts that are not depended on each other, it is better to set this flag to true to speed the loading of the page and improve the user experience.

Unfortunately this attribute is not supported by IE9.

For more information about this new feature you can read in IE test drive, or MDN

Summary

As long as you have static script loading you can control the dependency. If you want to optimize the loading using the async attribute you need to remember that its not being supported by all browser. If you are loading your script in a dynamic way and you have some dependencies in your script i would suggest the following:

  • Merge – if this is possible in your project, merge these files into one file and load them in one call. This is an optimization rule that you should try to do regardless to this problem.
  • Server side script building – if you need to add scripts dynamically according to some conditions, you could also do that on the server side using PHP for example.

 

Bookmark and Share

Comparing Javascript Objects

March 10, 2012

If you ever had the need to compare two javascript object you know that this is not an easy task. Javascript compare objects by reference, so only if it is the same object the javascript compare will return true.

The Problem

The simple solution to compare two object is to iterate on the properties and compare them. But then what if the object is nested?

Then we need to do that in a recursion until we get to a native literal. Sounds like we solve it. hmmm… not really, lets check the followings:


var obj1 = {a:1, b:2};
var obj2 = {a:1, b:2, c:3};

If we compare obj1 to obj2, which means we iterate on the obj1 properties and compare them to obj2 properties, then we will get that the objects are equal. But if we compare obj2 to obj1 we will get false, since obj1 doesn’t have the property ‘c’.

The Solution: Object-Helper

In order to solve this problem i created an helper file for object. at the moment it only implements isEqual to compare two objects, but maybe later i will add more object oriented tasks. The project is hosted in GitHub – Object-Helper

To solve the problem of asymmetric properties, I implemented an option to reverse the comparison. This means that the function will compare obj1 to obj2 and then will compare obj2 to obj1.

I had to develop it very quickly to solve a bug we had, so i didn’t took too much time to improve the efficiency of this method. That being said, while this solve the problem it introduce a new problem, efficiency. Since we are doing a reverse comparison and we have a recursions, it may result that the function will do more then one reverse to the same property.  This can increase the complexity to O(n*n) if not more.

This off course can be improved by checking which properties we have already reversed, or we can tell the function we don’t want the reverse to work. But if you don’t have huge JSON objects this should work fine.

 Exclude Me!

Another interesting feature that i implemented in this helper, is an exclude list that allows you to set which properties you don’t care about. Lets take to following example”


var obj1 = {a:1, b:2,created:1235433543};
var obj2 = {a:1, b:2, created:45343455443};

If we compere the two objects we will get false since created is not the same. But what if we don’t care when these objects were created? This is where you can use the exclude list like so:


isEqual( obj1, obj2, {
    exclude: { "created":true } } );

The exclude list is a map of properties names and a value must be set to true to indicate that this property needs to be excluded. The exclusion will be on any level in the Objects, so beware when using this feature.

Documentation

For the full documentation and code samples check the source on GitHub.

Bookmark and Share

BabaJS – Javascript Template Engine

April 26, 2011

What is BabaJS

BabaJS is an open source Javascript template engine/manager.

Read the full and updated documentation at github

The basic concept is: Template + Data = HTML

Here is a simple example:


<!-- user template -->
<div class="user">
    <span>< %=data.userName%></span>
	< %IF data.hasPic %>
	    <img src="<% return 'http://imgs.mydomain.com/'+ data.userPic; %/>" />
	< %ELSE%>
	    <span>Add User Pic</span>
	< %ENDIF%>
	<span>User Friends:</span>
	< % var myUserName = data.userName; %>
	< %LOOP for( var i=0; i< data.friends.length; i++ ) %>
	    <div class="friend">User < %=i%></div>
		< % return this.includeTemplate("friend", window.getFriend( data.friends[i] ) ); %>
	< %ENDLOOP%>
</div>

<!-- friend template -->
<div class="friend">< %=myUserName%> is friend with < %=data.userName%></div>

Javascript code to generate the HTML:


BabaJS.generateHTML({
    templateName:"user",
    requires:["friend"],
    ready: function(html){
        document.getElementById("test").innerHTML = html;
    },
    {userName:"me",
    hasPic: true,
    userPic: "me.jpg",
    friends:["amir","baba","daniel","mia","yael"]}
);

The template manager will fetch the template and its dependency templates and will call the ready callback when the HTML is ready.

or you can just do something even simpler like so:


var html = BabaJS.generateHTML("<div>< %=data.userName%></div>",{userName:"me"});
document.getElementById("test").innerHTML = html;

It is as simple as that. but you can do so much more with BabaJS – so in this case RTFM is worth it.

Why I Developed it?

While developing a social network at Crytek i did a research at the current javascript templating engines out there. While there were some good solutions, like PURE and EJS, non of them were good fit for my requirements, so i started developing something very simple by my own. I decided to make it an open source project since I wanted to share it with the developing community and thought that maybe there are others that may benefit from it and aren’t happy with the existing solutions.

Main Features

  • Sub Templating – you can include additional templates from other template as much as you like.
  • Dependency Management – BabaJS keep track about dependencies between templates and  JS and CSS files to make sure all are loaded when needed.
  • Fast – BabaJS compiles the templates in order to achive fast execution.
  • Template Stack Variables – BabaJS allows you to define variables in the template tags and access them from anywhere in the template or from included templates.
  • Text Based - BabaJS is doing text manipulation and doesn’t work on the DOM elements, thus allowing it to work on Node.JS as well.
  • Template Manager – BabaJS is not only a template engine, but also a manager that provides API to add/remove and create dependencies between templates.

Continue Reading »

Bookmark and Share

Implementing Autocomplete jQuery Plugin for Textarea

March 7, 2011

We all know the auto-complete feature. We use it in google search, when google tries to suggest our search term, and you probably saw it in many other sites which implemented the auto-complete for their own use. Most of the auto-complete out there are implemented in a text field, where the user has one line and usually its for a small amount of text.

But what do you do if you want to have auto-complete in a textarea?

This is where things get a little complicated and most websites decided not to implement this feature. Some sites, like Twitter has implemented a simple auto-complete feature for textarea. In this implementation they decided  to show the auto-completion outside of the textarea and without dynamic positioning, so the drop down menu is always at the bottom of the text area no matter where you type.

While this implementation does the job, i was hoping to see a more “sexy” auto-complete like i’m used to from windows apps, where the drop down menu appears right next to the current word that the user is typing.

I searched around and couldn’t find anything interesting implemented like i wanted, so i asked a few of my friends and they just said it can’t be done – can’t be done? i said – challenge accepted!

Basic Concept

I decided to implement a jquery plugin to allow auto-complete for textarea. In order to achieve this behavior i decided to create a clone of the textarea,  but instead of using a textarea i will use a div element, where for each line in the textarea i will replaced by a div element, where the line of the cursor will be used as a span so i could get the span width in order to understand where the cursor is. Here is a prototype i built in order to demonstrate the basic concept of the implementation:

While you are typing a text in the text area i’m building a clone of the textarea data on the left column.
Note: This demonstration doesn’t work on Internet explorer (but the plugin support IE in a basic way).

Challenges

When i started to design this concept i faced a few challenges in mind:

  • How to get the cursor position
  • How to clone the textarea taking into consideration all the styling that may apply to it
  • How to deal with line breaking an line wrapping.

Continue Reading »

Bookmark and Share
 
Powered by Wordpress and MySQL. Theme by openark.org