블로그 이미지
Sunny's

calendar

1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31

Notice

2010. 9. 3. 14:28 JQUERY

Create Vimeo-like top navigation

vimeo

I really like the top navigation implemented on Vimeo.com. First time I saw it I wanted to recreate it. And this is exactly what I am going to do in this tutorial.

What I like the most is the menu that drops down when you hover search box. It offers you different search options that you can choose and narrow your search.

Download source View demo

The base for this tutorial is simple CSS drop down menu based on unordered list. The structure is visually described in the image below:

sample1

As you can see we have UL with four items. The first one is logo with short submenu. Then comes login link, Help link with submenu and search item with submenu. Each submenu is being shown when hover corresponding link.

So this is the base structure that we’ll use here:

<ul id="menu">
    <li class="logo">
        <img style="float:left;" alt="" src="menu_left.png"/>
        <ul id="main">
            <li>Welcome to <b>Create Vimeo-like top navigation</b> tutorial!</li>
        </ul>
    </li>
    <li><a href="#">Login</a>
    </li>
    <li><a href="#">Help</a>
        <ul id="help">
            <li><a href="#">General help</a></li>
            <li><a href="#">Posts</a></li>
            <li><a href="#">Pages</a></li>
        </ul>
    </li>
    <li class="searchContainer">
        <div>
        <input type="text" id="searchField" />
        <img src="magnifier.png" alt="Search" onclick="alert('You clicked on search button')" /></div>
        <ul id="search">
            <li><input id="cbxAll" type="checkbox" />All</li>
            <li><input id="Articles" type="checkbox" />Articles</li>
            <li><input id="Tutorials" type="checkbox" />Tutorials</li>
            <li><input id="Reviews" type="checkbox" />Reviews</li>
            <li><input id="Resources" type="checkbox" />Resources</li>
        </ul>
    </li>
</ul>
<img style="float:left;" alt="" src="menu_right.png"/>

And CSS styles:

/* menu */
#menu{ margin:0px; padding:0px; list-style:none; color:#fff; line-height:45px; display:inline-block;
    float:left; z-index:1000; }
#menu a { color:#fff; text-decoration:none; }
#menu > li {background:#172322 none repeat scroll 0 0; cursor:pointer; float:left; position:relative;
    padding:0px 10px;}
#menu > li a:hover {color:#B0D730;}
#menu .logo {background:transparent none repeat scroll 0% 0%; padding:0px;
    background-color:Transparent;}
/* sub-menus*/
#menu ul { padding:0px; margin:0px; display:block; display:inline;}
#menu li ul { position:absolute; left:-10px; top:0px; margin-top:45px; width:150px; line-height:16px;
    background-color:#172322; color:#0395CC; /* for IE */ display:none; }
#menu li:hover ul { display:block;}
#menu li ul li{ display:block; margin:5px 20px; padding: 5px 0px;  border-top: dotted 1px #606060;
    list-style-type:none; }
#menu li ul li:first-child { border-top: none; }
#menu li ul li a { display:block; color:#0395CC; }
#menu li ul li a:hover { color:#7FCDFE; }
/* main submenu */
#menu #main { left:0px; top:-20px; padding-top:20px; background-color:#7cb7e3; color:#fff;
    z-index:999;}
/* search */
.searchContainer div { background-color:#fff; display:inline; padding:5px;}
.searchContainer input[type="text"] {border:none;}
.searchContainer img { vertical-align:middle;}

But as you can see this is far away from the good looking Vimeo navigation. It is functional, of course, but we need that pretty rounded corners everywhere. The solution is actually simple and it is described in the image below:

sample2

Now that looks fine. What we actually did can be seen in the code below. Let’s take Help submenu for the example:

<li><a href="#">Help</a>
    <ul id="help">
        <li>
            <img class="corner_inset_left" alt="" src="corner_inset_left.png"/>
            <a href="#">General help</a>
            <img class="corner_inset_right" alt="" src="corner_inset_right.png"/>
        </li>
        <li><a href="#">Posts</a></li>
        <li><a href="#">Pages</a></li>
        <li class="last">
            <img class="corner_left" alt="" src="corner_left.png"/>
            <img class="middle" alt="" src="dot.gif"/>
            <img class="corner_right" alt="" src="corner_right.png"/>
        </li>
    </ul>
</li>

We added two absolutely positioned images inside the first LI that will create “shoulders”. Also, we added one more LI to the end of the list that contains two absolutely positioned corners and one 1x1px stretched image to fill the empty space. And this is the additional styles that you need:

/* corners*/
#menu .corner_inset_left { position:absolute; top:0px; left:-12px;}
#menu .corner_inset_right { position:absolute; top:0px; left:150px;}
#menu .last { background:transparent none repeat scroll 0% 0%; margin:0px; padding:0px;
    border:none; position:relative; border:none; height:0px;}
#menu .corner_left { position:absolute; left:0px; top:0px;}
#menu .corner_right { position:absolute; left:132px; top:0px;}
#menu .middle { position:absolute; left:18px; height: 20px; width: 115px; top:0px;}

Now we have functional AND good looking top navigation. This might be optimized, so if you have free time or you need it for your projects, step on it. Or you can use this one as is :)

Did you implement something similar in any project? Do you find this one useful for some of your future projects?

posted by Sunny's
2010. 7. 14. 10:06 ASP.NET
 

 

Introduction

There are a lot of articles out there that show you how to integrate with the jQuery jqGrid Plugin from a listing, paging, sorting approach, but I haven’t seen many that show the integration with the add/edit/delete features that jqGrid offers.

It turns out that it isn’t very difficult to do, but it took quite a bit of digging in the jqGrid API documentation for me to find all the things I needed.

The following article will show how to customize the add/edit/delete modal experience inside of the jqGrid with ASP.NET MVC.

Contact ViewModel

First, you start off with your ViewModel. In this case the following is really bare bones. I haven’t annotated the properties with metadata because I actually do that manually in the jqGrid columns. That isn’t optimal, but it would be nice to have these automatically mapped. That sounds like another blog post ;)

 
01.public class ContactViewModel
02.{
03.    public System.Guid ContactId { get; set; }
04.  
05.    public string Name { get; set; }
06.  
07.    public string Email { get; set; }
08.  
09.    public string PhoneNumber { get; set; }
10.  
11.    public DateTime DateOfBirth { get; set; }
12.  
13.    public bool IsMarried { get; set; }
14.}

Contact View

The following code setups up the jqGrid to support add, edit, and delete.

The first function you’ll see is a custom validator that checks to see if the phone number has a length of 14. Yes, it isn’t bullet-proof validation by any stretch of the imagination, but its more of an example of what can be done.

Next you’ll see the updateDialog object literal defining the look and behavior of the add, edit, and delete dialog windows. The main property to define is the URL where the AJAX requests will post the data. You can also control whether the dialog closes immediately, if it’s a modal dialog, etc…

The next important thing to notice is the “key: true” property of the ContactId column. If you don’t set this property then the POST for the delete command  only send the relative ID that jqGrid generates, not the ContactId that you need. So, this is important ;)

Note: You’ll see some code below setting global properties for the jqGrid such as the title of the dialogs, buttons, etc. If you don’t do this then you’ll get generic titles. I figured these customizations made the user experience a little nicer, but things will work just find without them.

 
01.function isValidPhone(value, name) {
02.    console.log('isValidPhone');
03.    var errorMessage = name + ': Invalid Format';
04.    var success = value.length === 14;
05.    return [success, success ? '' : errorMessage];
06.}  
07.  
08.$(document).ready(function () {
09.    var updateDialog = {
10.        url: '<%= Url.Action("Update", "Contact") %>'
11.        , closeAfterAdd: true
12.        , closeAfterEdit: true
13.        , afterShowForm: function (formId) {
14.            $("#PhoneNumber").mask("(999) 999-9999");
15.            $("#DateOfBirth").datepicker();
16.        }
17.        , afterclickPgButtons: function (whichbutton, formid, rowid) {
18.            $("#PhoneNumber").mask("(999) 999-9999");
19.        }
20.        , modal: true
21.        , width: "400"
22.    };
23.  
24.    $.jgrid.nav.addtext = "Add";
25.    $.jgrid.nav.edittext = "Edit";
26.    $.jgrid.nav.deltext = "Delete";
27.    $.jgrid.edit.addCaption = "Add Contact";
28.    $.jgrid.edit.editCaption = "Edit Contact";
29.    $.jgrid.del.caption = "Delete Contact";
30.    $.jgrid.del.msg = "Delete selected Contact?";
31.  
32.    $("#list").jqGrid({
33.        url: '<%= Url.Action("List", "Contact") %>',
34.        datatype: 'json',
35.        mtype: 'GET',
36.        colNames: ['ContactId', 'Name', 'Date of Birth', 'E-mail', 'Phone Number', 'Married'],
37.        colModel: [
38.            { name: 'ContactId', index: 'ContactId', width: 40, align: 'left', key: true, editable: true, editrules: { edithidden: false }, hidedlg: true, hidden: true },
39.            { name: 'Name', index: 'Name', width: 300, align: 'left', editable: true, edittype: 'text', editrules: { required: true }, formoptions: { elmsuffix: ' *'} },
40.            { name: 'DateOfBirth', index: 'DateOfBirth', width: 200, align: 'left', formatter: 'date', datefmt: 'm/d/Y', editable: true, edittype: 'text', editrules: { required: true, date: true }, formoptions: { elmsuffix: ' *'} },
41.            { name: 'Email', index: 'Email', width: 200, align: 'left', formatter: 'mail', editable: true, edittype: 'text', editrules: { required: true, email: true }, formoptions: { elmsuffix: ' *'} },
42.            { name: 'PhoneNumber', index: 'PhoneNumber', width: 200, align: 'left', editable: true, edittype: 'text', editrules: { required: true, custom: true, custom_func: isValidPhone }, formoptions: { elmsuffix: ' *'} },
43.            { name: 'IsMarried', index: 'IsMarried', width: 200, align: 'left', editable: true, edittype: 'checkbox', editoptions: { value: "True:False" }, editrules: { required: true}}],
44.        pager: $('#listPager'),
45.        rowNum: 1000,
46.        rowList: [1000],
47.        sortname: 'ContactId',
48.        sortorder: "desc",
49.        viewrecords: true,
50.        imgpath: '/Content/Themes/Redmond/Images',
51.        caption: 'Contact List',
52.        autowidth: true,
53.        ondblClickRow: function (rowid, iRow, iCol, e) {
54.            $("#list").editGridRow(rowid, prmGridDialog);
55.        }
56.    }).navGrid('#listPager',
57.        {
58.            edit: true, add: true, del: true, search: false, refresh: true
59.        },
60.        updateDialog,
61.        updateDialog,
62.        updateDialog
63.    );
64.});

Contact Controller Update Action

The add/update/delete feature takes one URL where you can change the logic based on the operation type. The MVC Modal Binder will map the fields into your ViewModel in most cases. The exception is the “id” that is passed on the delete operation, but there is a way to get around that later in this post ;)

 
01.public ActionResult Update(ContactViewModel viewModel, FormCollection formCollection)
02.{
03.    var operation = formCollection["oper"];
04.    if (operation.Equals("add") || operation.Equals("edit"))
05.    {
06.        repository.SaveOrUpdate(new ContactViewModel
07.        {
08.            ContactId = viewModel.ContactId,
09.            DateOfBirth = viewModel.DateOfBirth,
10.            Email = viewModel.Email,
11.            IsMarried = viewModel.IsMarried,
12.            Name = viewModel.Name,
13.            PhoneNumber = viewModel.PhoneNumber
14.        });
15.    }
16.    else if (operation.Equals("del"))
17.    {
18.        repository.Delete(new ContactViewModel
19.        {
20.            ContactId = new Guid(formCollection["id"])
21.        });
22.    }
23.  
24.    return Content(repository.HasErrors.ToString().ToLower()); 
25.}

What About Using Complex Keys?

Instead of having ContactId (“key: true”) as your key to delete, you might have a more complex key to identify which item to delete. As it turns out, you can bind to the onclickSubmit event of the add/edit/delete dialog and change what data is POST’ed to the controller.

A nice side effect of this is that you name your property such that the MVC Modal Binder works.

Updated Dialog Object Literal

 
01.var updateDialog = {
02.    url: '<%= Url.Action("Update", "Contact") %>'
03.    , closeAfterAdd: true
04.    , closeAfterEdit: true
05.    , afterShowForm: function (formId) {
06.        $("#PhoneNumber").mask("(999) 999-9999");
07.        $("#DateOfBirth").datepicker();
08.    }
09.    , afterclickPgButtons: function (whichbutton, formid, rowid) {
10.        $("#PhoneNumber").mask("(999) 999-9999");
11.    }
12.    , modal: true
13.    , onclickSubmit: function (params) {
14.        var ajaxData = {};
15.  
16.        var list = $("#list");
17.        var selectedRow = list.getGridParam("selrow");
18.        rowData = list.getRowData(selectedRow);
19.        ajaxData = { ContactId: rowData.ContactId };
20.  
21.        return ajaxData;
22.    }
23.    , width: "400"
24.};

Updated Contact Controller Update Action

 
01.public ActionResult Update(ContactViewModel viewModel, FormCollection formCollection)
02.{
03.    var operation = formCollection["oper"];
04.    if (operation.Equals("add") || operation.Equals("edit"))
05.    {
06.        repository.SaveOrUpdate(new ContactViewModel
07.        {
08.            ContactId = viewModel.ContactId,
09.            DateOfBirth = viewModel.DateOfBirth,
10.            Email = viewModel.Email,
11.            IsMarried = viewModel.IsMarried,
12.            Name = viewModel.Name,
13.            PhoneNumber = viewModel.PhoneNumber
14.        });
15.    }
16.    else if (operation.Equals("del"))
17.    {
18.        repository.Delete(new ContactViewModel
19.        {
20.            ContactId = viewModel.ContactId
21.        });
22.    }
23.  
24.    return Content(repository.HasErrors.ToString().ToLower()); 
25.}

Conclusion

I hope you found the above article of some use in your everyday coding. The jqGrid also provides an inline editing feature similar to what you might experience in an Excel grid. You might look into that if you are interested.

Please give me your feedback. Thanks!

posted by Sunny's
2010. 7. 5. 15:55 JQUERY

One of the biggest concerns I've heard mentioned from users of the Prototype library about jQuery is the lack of support for various array methods. The robust features Prototype provides for arrays is of great benefit to developers that do a lot of array manipulation in their JavaScript.

However, I find that after moving to jQuery, I do less array manipulation than I had done with Prototype. Perhaps jQuery has altered my development pattern so I no longer need array manipulation, or perhaps I have shifted most of my data manipulation to the server. Whatever the case, I have only on occasion missed the Prototype array methods.

While there is some overlap in the ways that jQuery and Prototype handle array manipulation, jQuery does a few things Prototype doesn't do, and Prototype does a number of things that jQuery doesn't. I began writing an article about these differences, but soon got side-tracked writing a jQuery plugin to mimic the array methods Prototype provides.

You can find the plugin at http://code.google.com/p/jquery-protify-js/

With this plugin, you can give a particular array all of the methods that Prototype adds to their Array and Enumerable objects. You can use the methods two different ways. The first does not extend the original array:

JavaScript:
  1. var arr = [1,2,3,4,5,6];
  2. var protArray = $.protify(arr);

This will return an array extended with the Prototype library's methods, but leave the original array untouched.

The second extends the original array by passing in true as the second parameter:

JavaScript:
  1. var arr = [1,2,3,4,5,6];
  2. $.protify(arr, true);

In either case, the JavaScript Array prototype is untouched. When you create new arrays, it will not have the new methods. This way of writing code adds the new methods when they are needed while leaving the underlying JavaScript prototypes untouched. The return value of the methods is an array with the extended methods so that they can be chained.

JavaScript:
  1. var arr = [1,null,2,3,4,5,6];
  2. var arr2 = $.protify(arr)
  3.               .compact()
  4.               .findAll(function(a) {
  5.                 return a>=3;
  6.               })
  7.               .first();  // 3

The above code first returns the arr array values in a new array with the Prototype methods, removes any null/undefined values (using compact), finds all the values in the array greater than or equal to 3 and returns an extended array of them (using findAll), and finally returns the first value of that array (using first). It does all of this without touching the prototype for all arrays.

Here are some useful Prototype array methods included in the plugin:

all()

returns true if every member of the array == true and returns false if even one member != true.

JavaScript:
  1. var arr = [1,2,3,4,5,6];
  2. $.protify(arr, true);
  3. arr.all();  // true

any()

returns true if even one member of the array == true and returns false if every member != true.

JavaScript:
  1. var arr = $.protify([1,2,3,4,5,6]);
  2. arr.any(); // true

map()

similiar to jQuery's $.map. It executes the function passed in on every of member of the array and returns an array of the results.

JavaScript:
  1. $.protify([1,2,3,4,5,6]).map(function(n) {
  2.   return n * 2;
  3. });  //  [2,4,6,8,10,12]

eachSlice(number)

slices the array into an array of arrays of the size passed in. There is an optional second parameter which is a function that acts on each array partition before placing it in the slice.

JavaScript:
  1. var arr = [1,2,3,4,5,6];
  2. $.protify(arr, true);
  3. arr.eachSlice(2);  // [[1,2],[3,4],[5,6]]
  4. arr.eachSlice(2, function (n) {
  5.   return n.map(function(item) {
  6.     return item * 2;
  7.   });
  8. }); // [[2,4],[6,8],[10,12]]

include(value)

returns true if the value is in the array (using == equality).

JavaScript:
  1. var arr = [1,2,3,4,5,6];
  2. $.protify(arr, true);
  3. arr.include(3); // true
  4. arr.include('pie'); // false

max()/min()

returns the maximum/minimum value of the array. Optional parameter is a function that can be used to define the comparison and what gets returned.

JavaScript:
  1. $.protify([{'name': 'frank', 'age': 10},{'name': 'joe', 'age': 12}])
  2.   .max(function(person) { return person.age });
  3. // returns 12

partition()

returns an array with two arrays in it. The first array contains the values that == true in the initial array, and the second all of the values != true. There is an optional parameter that is a function used to do the evaluation.

JavaScript:
  1. $.protify([1,2,3,4,5,6]).partition(function (n) {
  2.   return n <= 3;
  3. });
  4. // [[1,2,3],[4,5,6]]


pluck()

And finally, my favorite. The pluck() method iterates through every member of the array and returns an array of the value of the attribute name passed in.

JavaScript:
  1. var arr = [{'name': 'Frank', 'age': 10}, {'name': 'Joe', 'age': 12}];
  2. $.protify(arr).pluck('age'); // [10, 12]
  3. $.protify(arr).pluck('name'); // ['Frank, 'Joe']

For a full listing and description of all the methods, see the Prototype documentation on arrays and enumerables.

Arrays: http://prototypejs.org/api/array

Enumerables: http://prototypejs.org/api/enumerable

The toJSON method has not yet been implemented because it depends on object methods that Prototype provides. Can you guess what my next project is?

posted by Sunny's
2010. 7. 5. 15:42 JQUERY


Event delegation, as described in the first article of this series, is a way to take advantage of event bubbling to avoid binding an event listener more than once. jQuery 1.3 and the upcoming jQuery 1.4 have many features that make using event delegation in your web pages easier. The aim of this tutorial is to help you understand how these new features work.

From traditional event listening to event delegation

Since an event occurring on an element is propagated to all of its ancestors, an event listener can be bound to a single ancestor of numerous elements instead of being bound to all the elements individually.

Consider the following list items:

HTML:
  1. <ul class="myList">
  2.   <li class="red">The first item.</li>
  3.   <li class="green">The second item.</li>
  4.   <li class="yellow">The third item.</li>
  5.   <li class="blue">The fourth item.</li>
  6. </ul>
  7. <p>Class of the last clicked item: <span id="display"> </span>
  8. </p>

If we want to display the class of an item when it is clicked, a traditional event listener in jQuery would be written like this:

JavaScript:
  1. $("li").click( function( event ) {
  2.   $("#display").text(event.target.className);
  3. });

The event object passed to the handler has a target property which corresponds to the element that has been clicked.

The equivalent using event delegation would look like this:

JavaScript:
  1. $("ul").click( function( event ) {
  2.   $("#display").text(event.target.className);
  3. });

  • The first item.
  • The second item.
  • The third item.
  • The fourth item.

Class of the last clicked item: blue

Event delegation has two main advantages:

  1. setting a single event listener instead of multiple ones is obviously faster;
  2. any new element later added to the list will have the same behavior (as demonstrated in Working with Events, Part 1).

This translation to event delegation that we've just made is, however, slightly too simple, since our original aim was to display only the class of the list items. Using the previous snippet, the class of the unordered list itself can be displayed (by clicking to the left of a bullet-point). We thus have to make sure that the target of the click is a <li>.

JavaScript:
  1. $("ul").click( function( event ) {
  2.   if(event.target.nodeName == "LI") {
  3.     $("#display").text(event.target.className);
  4.   }
  5. });

  • The first item.
  • The second item.
  • The third item.
  • The fourth item.

Class of the last clicked item:

Scanning the ancestors of the event.target: the .closest() method

With such a simple document, event delegation is really that easy to achieve. But things can get more complex if the items have children elements:

HTML:
  1. <ul class="myList">
  2.   <li class="red"><b>The <i>first <u>item</u></i></b>.</li>
  3.  
  4.   <li class="green"><b>The <i>second <u>item</u></i></b>.</li>
  5.   <li class="yellow"><b>The <i>third <u>item</u></i></b>.</li>
  6.  
  7.   <li class="blue"><b>The <i>fourth <u>item</u></i></b>.</li>
  8. </ul>
  9.  
  10. <p>Class of the last clicked item: <span id="display"> </span>
  11. </p>

In this case, if the user clicks on one of the words item, the event.target will be a <u>. It is therefore necessary to loop through all of the ancestors of this original target to find the element that is "interesting" for us: the <li>

JavaScript:
  1. $("ul").click( function( event ) {
  2.   var elem = event.target;
  3.   while( elem.nodeName != "LI" && elem.parentNode) {
  4.     elem = elem.parentNode;
  5.   }
  6.   if(elem.nodeName == "LI") {
  7.     $("#display").text(event.target.className);
  8.   }
  9. });

Notice that if the user clicks outside of an <li>, we have to stop looping through the ancestors at some point; in this case when we find the root of the document (which has no parentNode).

jQuery 1.3 introduced the .closest() method, which replaces this loop by a single line of code:

JavaScript:
  1. $("ul").click( function( event ) {
  2.   var $elem = $(event.target).closest("li");
  3.   if($elem.length) {
  4.     $("#display").text($elem.attr("class"));
  5.   }
  6. });

  • The first item.
  • The second item.
  • The third item.
  • The fourth item.

Class of the last clicked item:

The parameter passed to the .closest() method is a CSS selector that will match the first interesting ancestor.

The context parameter

It can be noted that, when the click occurs outside of an <li>, we could stop looping through the ancestors before hitting the document root, but instead as soon as we hit the <ul>. jQuery 1.4 will introduce an optional context parameter to .closest() for this purpose:

JavaScript:
  1. $("ul").click( function( event ) {
  2.   $("#display").text($(event.target).closest("li", this).attr("class"));
  3. });

Here this is the <ul> element to which the event listener has been bound. This optional parameter improves the performance of event delegation as it prevents the wasted resources of searching for an ancestor which cannot exist.

Event delegation in a single line: the .live() method

jQuery 1.3 also introduces .live(), a method which binds the event listener and implicitly calls the .closest() method to determine whether your event handler should be executed or not.

JavaScript:
  1. $("li").live("click", function( event ) {
  2.   $("#display").text(
  3.     $(event.currentTarget).attr("class")
  4.   );
  5. });

Note how different the syntax using the .live() method is. It seems that we have switched back to a traditional event binding. However, a big difference is that the event listener will work for any existing and future element matching our original selector. There is, of course, nothing magic: behind the scenes .live() simply binds the event listener to the document root and filters any event.target using the .closest() method.

A notable difference with the traditional event binding syntax is that we are not using the target property of the event object inside our event handler, but rather the currentTarget. Indeed, the target of the event is possibly a child of one <li>, whereas the currentTarget property refers to the element that has been found by the implicit .closest().

As explained on the Event Object documentation, the currentTarget property is supposed to be the current DOM element within the event bubbling phase, i.e. the element on which the event has been detected by the event listener, which will always be the element on which the event listener was bound. When using .live(), the currentTarget would therefore always be the document root and you would need to use .closest() once again on the original target to find an interesting ancestor.

JavaScript:
  1. $("li").live("click", function( event ) {
  2.   $("#display").text(
  3.     $(event.target).closest("li").attr("class")
  4.   );
  5. });

This kind of code is required with jQuery 1.3, but as of jQuery 1.4, the currentTarget is modified internally and can thus be used to avoid the extra .closest() inside the event handler.

The context parameter

In jQuery 1.3 all live event listeners were effectively bound to the document root. This can hurt the performance of a web page since all events detected by an event listener will trigger the execution of an implicit .closest(), even though the event target might be totally out of interest.

In jQuery 1.4, .live() should be able to bind the event listener to a specific and more focused element of the document by taking advantage of the context of your jQuery object:

JavaScript:
  1. $("li", $("ul")[0]).live("click", function( event ) {
  2.   $("#display").text(
  3.     $(event.currentTarget).attr("class")
  4.   );
  5. });

The context is the second parameter used to build our jQuery object. To be useful for .live() it has to be set as a pure DOM element, hence the [0] after $("ul"). Brandon Aaron has a useful article explaining the context parameter in detail.

Unbind for .live(): the .die() method

Just like .bind() has its .unbind() counterpart that allows for event listeners to be unbound, .live() has its .die() counterpart.

Unlike .bind(), .live() does not allow for namespaced events to be used.

Dealing with events that don't bubble

There are some events for which event delegation is traditionally not possible, simply because they do not bubble. The promise of jQuery 1.4 is nevertheless to make those events compatible with .live(). How this is achieved will be covered in the upcoming fourth part of this tutorial.

Scripts included in this post:

출처 : http://www.learningjquery.com/2009/09/working-with-events-part-3-more-event-delegation-with-jquery?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+LearningJquery+%28Learning+jQuery%29

posted by Sunny's
2010. 7. 5. 11:37 JQUERY

jQuery 사이트에서도 볼 수 있는 내용이지만 한눈에 들어오고 가벼운거 같아 올려봐요 ^^



 


posted by Sunny's
2010. 7. 5. 11:34 JQUERY
jquery.cheatsheet.1.4.png


Future Colors는 발빠르게 jQuery 1.4 버전의 치트 시트를 배포했습니다. 메서드 단위로 API문서와 링크가 걸렸는 HTML과 PDF 버전 그리고 이미지로 제공하는 PNG 버전이 있습니다.
posted by Sunny's
2010. 7. 2. 11:04 JQUERY

Introduction

This article will cover the following elements:

Form Skinning

Frustrated with the form elements inconsistency among different browsers? With these jQuery plugins, you can unified the look and feel of all your form elements.

Form Validation

It's always good to have client side form validation. These jQuery plugin will save your times and works by reusing already made form validation.

Masking

Masking can help to avoid human mistake. I found these plugins are very helpful to guide users and decrease the chances of bad data.

File Uploader

These file uploader transform the orginal input file element into a more robust file uploader that able to upload multiple files and having a progress bar to indicate the upload progress.

Checkbox & Radio Button

Spice it up your checkbox and radio button with these jQuery plugins!

Spin Button & Slider

Spin button can be useful sometimes. The other alternative will be a slider.

Auto Complete

You must have seen the auto complete functionality from Apple.com, google.com and all the major websites. With the following plugins, we, too can implement it in our websites easily.

Calendar & Time picker

The old school method to let user select date and time are using drop down lists (day, month and year). Now, we can use a calendar, timepicker to replace the old way. Since it's picked from calendar, it decreases the chances of invalid date. I like them.

Drop Down Menu (Select Element)

Want to do more with drop down menu? These plugins able to add more capabilities to drop down menu.

Color Picker

If you are building some online tools that involves colours, I guess you will like the following plugins. jQuery based colour pickers!

Textarea

Sometimes, we get really annoyed when we have to type in message in such a small space (a textarea), and we have to scroll up and down, left and right (sometimes) to read the entire message. Say no more to scrolling! Add this autogrow/resizer capability to textarea to avoid that.

Conclusion

All the plugins are implemented using jQuery, there are still heaps of them out there. Of course, you might able to find other good stuff which are not made from jQuery. If you wrote jQuery plugin that enhances form, and you think it's really cool. Drop me a comment, I will add it in.

posted by Sunny's
2010. 6. 30. 10:11 JQUERY

참고 URL : http://www.malsup.com/jquery/form/#ajaxSubmit

The following code controls the HTML form beneath it. It uses ajaxSubmit to submit the form.

// prepare the form when the DOM is ready 
$(document).ready(function() { 
    var options = { 
        target:        '#output2',   // target element(s) to be updated with server response 
        beforeSubmit:  showRequest,  // pre-submit callback 
        success:       showResponse  // post-submit callback 
 
        // other available options: 
        //url:       url         // override for form's 'action' attribute 
        //type:      type        // 'get' or 'post', override for form's 'method' attribute 
        //dataType:  null        // 'xml', 'script', or 'json' (expected server response type) 
        //clearForm: true        // clear all form fields after successful submit 
        //resetForm: true        // reset the form after successful submit 
 
        // $.ajax options can be used here too, for example: 
        //timeout:   3000 
    }; 
 
    // bind to the form's submit event 
    $('#myForm2').submit(function() { 
        // inside event callbacks 'this' is the DOM element so we first 
        // wrap it in a jQuery object and then invoke ajaxSubmit 
        $(this).ajaxSubmit(options); 
 
        // !!! Important !!! 
        // always return false to prevent standard browser submit and page navigation 
        return false
    }); 
}); 
 
// pre-submit callback 
function showRequest(formData, jqForm, options) { 
    // formData is an array; here we use $.param to convert it to a string to display it 
    // but the form plugin does this for you automatically when it submits the data 
    var queryString = $.param(formData); 
 
    // jqForm is a jQuery object encapsulating the form element.  To access the 
    // DOM element for the form do this: 
    // var formElement = jqForm[0]; 
 
    alert('About to submit: \n\n' + queryString); 
 
    // here we could return false to prevent the form from being submitted; 
    // returning anything other than false will allow the form submit to continue 
    return true

 
// post-submit callback 
function showResponse(responseText, statusText, xhr, $form)  { 
    // for normal html responses, the first argument to the success callback 
    // is the XMLHttpRequest object's responseText property 
 
    // if the ajaxSubmit method was passed an Options Object with the dataType 
    // property set to 'xml' then the first argument to the success callback 
    // is the XMLHttpRequest object's responseXML property 
 
    // if the ajaxSubmit method was passed an Options Object with the dataType 
    // property set to 'json' then the first argument to the success callback 
    // is the json data object returned by the server 
 
    alert('status: ' + statusText + '\n\nresponseText: \n' + responseText + 
        '\n\nThe output div should have already been updated with the responseText.'); 


posted by Sunny's
2010. 6. 29. 11:31 JQUERY
posted by Sunny's
2010. 6. 16. 23:54 JQUERY

경량화 된 인기있는 자바스크립트 라이브러 jQuery를 이용하면 복잡한 AJAX 동작과 다이나믹한 HTML 조작을 상당히 쉽고 일관된
코딩스타일로 구현할 수 있습니다. 이제는 ASP.NET플랫폼의 기본 스크립트 라이브러리로 제공되는 jQuery와, 유용한 사용자
인터페이스의 모음인 jQueryUI를 이용해, 다이나믹한 ASP.NET 웹어플리케이션을 개발하는 방법들에 대해 알아봅니다.

 한진수, 넥슨
2010년 Visual C# MVP로 활동 중에 있으며, 아직 신입개발자 딱지를 떼지 못한 새내기 입니다. 생김새와는 달리 저의 지식이
조금이나마 다른분들에게 도움이 될 수 있다면 그것만으로도 충분히 행복을 느끼는 순진한 개발자 입니다.
 

출처 : http://www.techdays.co.kr/2010spring/remix10/session1_4.html
posted by Sunny's
prev 1 2 3 4 next