6 January 2012

jQuery Event handler Attachments live, delegate, on

JQuery has powerful event handlers, from 1.0 jquery has a bind function to handle the events of the selectors.

For example
<script type = "text/javascript" >
 $('div.#help').bind('click', function () {
  alert('clicked the Help');
 });
</script>

Above click event is bind to the selector (i.e div element with ID 'Help'), so when a user clicked on the div element the event triggered and alert shown.

With new version new functions for the event handler is also introduced. From 1.3 live function is introduced, this function will attach event handler to document and calls the handler when event occurs on all elements that match the selectors. As with ajax, dynamic content can be added to the page at any time, the bind function will attach events handlers to only existing elements, for those elements added through the ajax, we need to call the bind function once again. This is repeating of same function calling. For this .live came to help, Live will attach event handler to the document and calls the event handler when the event occur on the selector, so the selector may exist or may added in future.

$(selector).live(events, data, handler); // jQuery 1.3+

As the event handler is attached to the document, the events bubble, or propagate, from the deepest, innermost element (the event target) in the document where they occur all the way up to the body and the document element. This is slowest one so in next version i.e 1.4 a new function .delegate is introduced.

.delgate function will attach a handler to one or more events for all elements that match the selector, now or in the future, based on a specific set of root elements. here the improvement is the event handler is not attached to document but to the set of root elements.

$(document).delegate(selector, events, data, handler); // jQuery 1.4.3+

Here is a example
$("table").delegate("td", "click", function() {
  $(this).toggleClass("chosen");
});

Above snippet attach a handler to click event to the selector "table", but calls the handler only when event occurs on "td", which is a selector passed as first argument, therefore td shall exist while this function executed or may be added to the table in future.

One important note from jQuery Documentation
Since the .live() method handles events once they have propagated to the top of the document, it is not possible to stop propagation of live events. Similarly, events handled by .delegate() will propagate to the elements to which they are delegated; event handlers bound on any elements below it in the DOM tree will already have been executed by the time the delegated event handler is called. These handlers, therefore, may prevent the delegated handler from triggering by calling event.stopPropagation() or returning false.

Now in the latest version 1.7 .live and .delegate is replaced with .on which perform the action of the above said functions.

The syntax for the function
$(document).on(events, selector, data, handler); // jQuery 1.7+

If selector (the second argument) is not passed then the event handler attached the document and handler is called when the event occurs on the document(root element). If the selector is passed then the event handler called only event occur on the selector.

Here is a example
$("body").on("click", "p", function(){
      $(this).after("<p>Paragraph Clicked! </p>");
    });

Performance
The event like click are occur rarely, so it will not have a impact on performance. But event like mousemove will occur many time per second. so we must be carefull when we use the events like mousemove, we must cache, so that the calculation will not need to happen on every call.

jQuery can process simple selectors of the form tag#id.class very quickly when they are used to filter delegated events. So, "#myForm", "a.external", and "button" are all fast selectors. Delegated events that use more complex selectors, particularly hierarchical ones, can be several times slower--although they are still fast enough for most applications. Hierarchical selectors can often be avoided simply by attaching the handler to a more appropriate point in the document. For example, instead of $("body").on("click", "#commentForm .addNew", addComment) use $("#commentForm").on("click", ".addNew", addComment).

15 November 2011

Drupal use two different jquery version with noconflict

While developing a website using drupal, we had a requirement, this requirement can be achieved using simple function available on recent release of jQuery, but in drupal 6 core has jQuery 1.2.6 and also if we update the jQuery with drupal module jQuery_update, we shall have only 1.3.2. So next, we can add recent release of jQuery1.7 through theme. Our new requirement will work now fine, hey we appreciate ourselves. But after a few minutes, we will come to know that many other jQuery function stopped working. After debugging, we will know that both version of jQuery is loaded in the same page, so version conflict.

What is the solution?

After digging the net and with reference to the jQuery documentation, I came to know that jQuery has a feature Using jQuery with Other Libraries i.e jQuery can be used with other libraries like mootools,  prototype etc. in a single webpage. To enable this feature jQuery has a function called noConflict.

How to use this function.
<html>
 <head>
   <script src="prototype.js"></script>
   <script src="jquery.js"></script>
   <script>
     jQuery.noConflict();
     
     // Use jQuery via jQuery(...)
     jQuery(document).ready(function(){
       jQuery("div").hide();
     });
     
     // Use Prototype with $(...), etc.
     $('someid').hide();
   </script>
 </head>
 <body></body>
 </html>

Above example demonstrates how jquery can be used with other library. $ is used in both libraries so because of conflict javascript will stop execution.  jQuery.noConflict() line will release the $ variable from jQuery, so we have to write using jquery instead of $ in the jQuery program, this makes the prototype to use $ and execute the code. this way the both libraries run smoothly.

In the same way, we can use the two different version of jQuery in a single page (Drupal). By default drupal core will add jQuery 1.2.6 So in your code you add the latest jQuery and call the noConflict function like the below sample code. Below sample code use a shortcut $j, so from here instead of $ you may use the
$j to access the functions from jQuery 1.7.
<script src="jquery-latest.js"></script>
   <script>
     var $j = jQuery.noConflict();
     
     // Use jQuery via $j(...)
     $j(document).ready(function(){
       // isNumeric function introduced in latest version 1.7
       alert($j.isNumeric(12));
     });
     
     // Use $ for 1.2.6 version $(...), etc.
     $('#someid').hide();
   </script>


If you are using a plugin which is depends on 1.7 then use as below

<script src="jquery-latest.js"></script>
   <script>
     jQuery.noConflict();
     
     // Use jQuery via $j(...)
     jQuery(document).ready(function($){
       // we may use usual code here
       alert($.isNumeric(12));
     });
     
     // Use $ for 1.2.6 version $(...), etc.
     $('#someid').hide();
   </script>



11 August 2011

Drupal: How to add css file to specific drupal page.

We all know in Drupal, we can add css files in theme folder via info file, through the declaration [stylsheets][all][] = style.css.

We can go on add as many css files. All CSS files added through info file will be available through out the site.

If we are working to develop a small website, this will be a right solution, where we won't worry about the performance / maintainability etc.

But when we work for large scale web portals, we would plan for each minor aspects of the web portal. In this case we would have many pages, so we would have a large / heavy CSS file.

Now, we want to split the CSS file in theme folder and we want to add them only on required pages.

So if we have our module, Hook_init is the right place to add the css, we can add the css file, by calling drupal_add_css function.

Hook_init will be called on every page callback, but it will not called when the page is cached. Don't worry cached page already will have your css.

In module also, if we have page callback, then we can call the drupal_add_css inside the callback function, which makes sure, only when the callback function is called the css will add to the page.

Don't try to use the drupal_add_css in page tpl's which won't work, because already variables are generated in preprocess function.

Here i will explain you to add css file in hook_init for multiple pages.

The code will look like

<?php
  // declare an array to list the pages we need to add css, 
//This will be easy to add pages in future. $pages = array ( 'node/add/page', 'node/%/edit', 'home', 'home/*', ); // convert the array to string, append a newline to every array element. $pages = implode(chr(10),$pages); // this drupal_get_path_alias
// will return the alias path if found or the original one which is passed. $path = drupal_get_path_alias($_GET['q']); // Compare with the internal and path alias (if any). $page_match = drupal_match_path($path, $block->pages); if ($path != $_GET['q']) { $page_match = $page_match || drupal_match_path($_GET['q'], $block->pages); } if ($page_match) { drupal_add_css(drupal_get_path('xyz','module'),'module'); } ?>

Place this snippet inside the hook_init, now your css will be added only on above listed pages in $pages array.

28 July 2011

How to theme Unordered (item) list with unique id or class assigned to all LI in Drupal

Drupal has many built in theme function to construct HTML elements, One of the frequently used is 'Item_list'. This theme function used to build a HTML ordered / unordered list.
<?php
$data = array('List 1','List 2', 'List 3');
$output = theme('item_list', $data);
?>
The Above use of theme function will output the <UL> and <LI> without any class or id.
For Example:
<ul >
<li > List 1 </li>
<li > List 2 </li>
<li > List 3 </li>
</ul>


If we need to have the output as below.
For Example:
<h3> Title </h3>
<ul class="my-list">
<li clase="list" id="list-1"> List 1 </li>
<li clase="list" id="list-2"> List 2 </li>
<li clase="list" id="list-3"> List 3 </li>
</ul>


Then our code will look like.

<?php
$items = array(
array('data' => 'List 1', 'Class' => 'list', 'id' => 'list-1'),
array('data' => 'List 2', 'Class' => 'list', 'id' => 'list-2'),
array('data' => 'List 3', 'Class' => 'list', 'id' => 'list-3')
);
$title = 'Title';
$output = theme('item_list', $items, $title, 'ul', array('class' => 'my-list'));
?>

In $items array for each item we defined an array with key data, class and id, this will be transformed to HTML.
Title parameter will be printed prefix to the UL tag, with header tag.
And 'ul' parameter decides the type ordered / unordered tag to be printed. defualt is UL
Last a class attribute to UL tag, you may add id or any HTML attribute to UL / OL tag, defining inside the array as key => value.
Refer this in Drupal API

27 July 2011

A journey with Drupal as a developer

Drupal - The word I heard in my office four years back(2007). From then with my company (Unimity Solutions Pvt. Ltd.), I started adopting the Drupal in my profession.

The early days when we started developing drupal 5 projects, it was very hard to understand.

For instance if we think about the form. A form in php is very simple, define the Form HTML with action attribute pointing to a PHP page, and the php page will manage all the server side functionality. But in Drupal you have to define the form in a array and you need to follow the hook system of drupal to handle the form server side validation and submission. To understand the Drupal form you must have knowledge about drupal hook system then you need to understand form api(which is a separate tutorial). First of all we are not able to relate any way the approach of PHP(or any platform) form submission and the drupal form.

Next if you talk about theme, Drupal has separated the logic and HTML. You will have a theme function or template file to put your HTML. Which is also very new to me. I use to put all HTML and PHP in the same page.

You will understand from my above views, that at early stage how pour I'm, I don't have proper knowledge about MVC also.

But as time move, I slowly started learning Drupal, at the same time I also started to understand the MVC concept, Web standards, Re-usablity, Scalability, Performance, Cache, Security, etc.As all these are properties of Drupal.

Now I'm capable to doing anything as required, by following all above said concepts, features and best practices. Drupal teach me all those concepts and features. Now I can  even build a framework. Thanks to Drupal.

If I praise Drupal, then I must not forgot the community, which is working for the development of Drupal framework. All my praise to Drupal is directly linked to the community.  Now I thought of giving back the community. For that as a first step I donated to Drupal Association and became individual member. The Second thing is now I started writing tutorials about Drupal. This Blog is the first step to the tutorial. In coming days I will write about Drupal, Web2.0, Jquery and Mobile technology.

Thanks to Drupal and its community.
My Drupal Profile