Best jquery questions in May 2012

Why "$().ready(handler)" is not recommended?

57 votes

From the jQuery API docs site for ready

All three of the following syntaxes are equivalent:

  • $(document).ready(handler)
  • $().ready(handler) (this is not recommended)
  • $(handler)

After doing homework - reading and playing with the source code, I have no idea why

$().ready(handler) 

is not recommended. The first and third ways, are exactly the same, the third option calls the ready function on a cached jQuery object with document:

rootjQuery = jQuery(document);
...
...

// HANDLE: $(function)
// Shortcut for document ready
} else if ( jQuery.isFunction( selector ) ) {
    return rootjQuery.ready( selector );
}

But the ready function has no interaction with the selector of the selected node elements, The ready source code:

ready: function( fn ) {
    // Attach the listeners
    jQuery.bindReady();
        // Add the callback
    readyList.add( fn );
        return this;
},

As you can see, it justs add the callback to an internal queue( readyList) and doesn't change or use the elements in the set. This lets you call the ready function on every jQuery object.

Like:

  • regular selector: $('a').ready(handler) DEMO
  • Nonsense selector: $('fdhjhjkdafdsjkjriohfjdnfj').ready(handler) DEMO
  • Undefined selector:$().ready(handler) DEMO

Finally... to my question: Why $().ready(handler) is not recommended?

I got an official answer from one of the jQuery developers:

$().ready(fn) only works because $() used to be a shortcut to $(document) (jQuery <1.4)
So $().ready(fn) was a readable code.

But people used to do things like $().mouseover() and all sorts of other madness.
and people had to do $([]) to get an empty jQuery object

So in 1.4 we changed it so $() gives an empty jQuery and we just made $().ready(fn) work so as not to break a lot of code

$().ready(fn) is literally now just patched in core to make it work properly for the legacy case.

The best place for the ready function is $.ready(fn), but it's a really old design decision and that is what we have now.


I asked him:

Do you $(fn) is more readable than $().ready(fn) ?!

His answer was:

I always do $(document).ready(fn) in actual apps and typically there's only one doc ready block in the app it's not exactly like a maintenance thing.

I think $(fn) is pretty unreadable too, it's just A Thing That You Have To Know Works™...

What is the cost of '$(this)'?

35 votes

People here often suggest to cache the jQuery object created from a DOM element, like with this code:

$('#container input').each(function() {
    $(this).addClass('fooClass');
    $(this).attr('data-bar', "bar");
    $(this).css('background-color', 'red');
});
  • Does caching the jQuery object really improve the performance of our code?
  • What happens "behind the scenes" when you pass a DOM element to the jQuery constructor?

Inspired by this question on meta, I'll answer my question.

In the jQuery tag info this warning appears:

The jQuery function $() is expensive. Calling it repeatedly is extremely inefficient.

Well... that is true only for strings selectors, which get parsed with regex to find out what are they:

quickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/

Then if the string is a selector(other than id) jQuery traverse the DOM to find a match with it's expensive find function:

} else if ( !context || context.jquery ) {
    return ( context || rootjQuery ).find( selector );
}

So yes it's expensive, but that is only true for selectors!
If we pass a DOMElement the only action jQuery does is saving the DOMElement parameter as the context of the new just created jQuery object and setting the length of the context to 1:

// Handle $(DOMElement)
if ( selector.nodeType ) {
    this.context = this[0] = selector; // Selector here is a DOMElement
    this.length = 1;
    return this;
}

I did some tests with jsPerf, and I found that indeed caching the jQuery object has only a little effect:

enter image description here

In Chrome it's only 7% slower. (In IE it's a little bit more significant- 12%)

Does this code need to be in a document.ready?

28 votes

The document.ready is used to execute code after the DOM is fully loaded. This can be used to attach event handlers to elements on the page e.g

$(function(){ 
    $('#somediv').click(function(){ 

    }); 
}) 

<div id="somediv"> </div> 

Internally jQuery hooks up to DOMContentLoaded in browsers such as Firefox/Opera. In IE's case some extra logic is implemented to check when the DOM is ready1.

I have a few questions, my first one being, when binding event handlers to the document itself, is it necessary to put that code in a document.ready ? I have always been writing the code below without wrapping it in a document.ready

$(document).keydown(function(e){
    if (e.which == 39) { 
       alert( "right arrow pressed" );
       return false;
    }
});

And as you can see, it works. My understanding is, since this code doesn't hook up to any elements within the document, but the document itself, there's no need to wrap it in a document.ready handler. Another reason i don't wrap it is because i used to do the same in vanilla javascript the equivalent would be the code below, which also works.

document.onkeydown= function(){
var keyCode = event.keyCode || event.which;   
    if (keyCode == 39) { 
       alert( "right arrow pressed" );
       return false;
    }
}

I've seen numerous posts where people wrap it in a document.ready, is there any downside of not wrapping this code in document.ready ?

Also i think this question stems from my lack of clarity of what happens during this time when the DOM is being constructed, so if someone can explain what happens during the period right before the DOM is ready. To me the document is ready when the html has been parsed and converted into a DOM tree, or is there more to it ?

In summary, here are my questions

  1. When binding event handlers to the document itself, is it necessary to put that code in a document.ready.
  2. Are there any downsides to not wrapping the code in the document.ready ?
  3. What sequence of events take place when the document is being constructed, right before the document.ready is fired ?

If you are binding to the document itself, you don't need to wait until it is ready. There shouldn't be any downsides to not wrapping it in document.ready in this case.

document.ready gets fired when the DOMReady event is triggered by the browser, or when a specific test is successful for versions of browsers that don't support the DOMReady event.

Additional information. (5/22)

Most modern browsers implement the DOMContentLoaded event which fires when all elements defined on the document are ready to be manipulated by javascript. Other browsers either rely on a setTimeout loop that continuously checks the readystate of the document or binds directly to the onreadystatechanged method of the document (taken from jquery core). The document itself is ready to be manipulated before javascript is ever executed, therefore you never need to wait when binding directly to the document.

The only gotcha here is that if the code interacts with elements other than the document, there is a chance that the event could be triggered on the document before those elements exist. It is very unlikely for that to happen, but it can happen. If that is something that can happen with your code, then it makes sense to place it inside of $(document).ready() to prevent that scenario. Your sample doesn't warrant being placed inside of $(document).ready().

What's the difference in the :not() selector between jQuery and CSS?

19 votes

I have this layout:

<div id="sectors">
    <h1>Sectors</h1>
    <div id="s7-1103" class="alpha"></div>
    <div id="s8-1104" class="alpha"></div>
    <div id="s1-7605" class="beta"></div>
    <div id="s0-7479"></div>
    <div id="s2-6528" class="gamma"></div>
    <div id="s0-4444"></div>
</div>

With these style rules:

#sectors {
    width: 584px;
    background-color: #ffd;
    margin: 1.5em;
    border: 4px dashed #000;
    padding: 16px;
    overflow: auto;
}

#sectors h1 {
    font-size: 2em;
    font-weight: bold;
    text-align: center;
}

#sectors div {
    float: left;
    position: relative;
    width: 180px;
    height: 240px;
    margin: 16px 0 0 16px;
    border-style: solid;
    border-width: 2px;
}

#sectors div:nth-of-type(3n+1) {
    margin-left: 0;
}

#sectors div::after {
    display: block;
    position: absolute;
    width: 100%;
    bottom: 0;
    font-weight: bold;
    text-align: center;
    text-transform: capitalize;
    background-color: rgba(255, 255, 255, 0.8);
    border-top-style: solid;
    border-top-width: 2px;
    content: attr(id) ' - ' attr(class);
}

#sectors div.alpha { color: #b00; background-color: #ffe0d9; }
#sectors div.beta  { color: #05b; background-color: #c0edff; }
#sectors div.gamma { color: #362; background-color: #d4f6c3; }

#sectors div.unassigned {
    color: #808080;
    background-color: #e9e9e9;
    opacity: 0.5;
}

#sectors div.unassigned::after {
    content: attr(id) ' - Unassigned';
}

#sectors div.unassigned:hover {
    opacity: 1.0;
}

I use jQuery to add the unassigned class to sectors that don't otherwise have one of the classes alpha, beta or gamma:

$('#sectors div:not(.alpha, .beta, .gamma)').addClass('unassigned');

And everything works flawlessly in modern browsers.

Interactive jsFiddle preview

But seeing as the :not() selector in jQuery is based on :not() in CSS3, I thought I could place it directly in my stylesheet so I wouldn't have to rely on an extra class added using jQuery. Besides, I'm not really interested in supporting older versions of IE, and other browsers have excellent support for the :not() selector.

So I try doing this (knowing I will only have sectors Α, Β and Γ in my layout):

#sectors div:not(.alpha, .beta, .gamma) {
    color: #808080;
    background-color: #e9e9e9;
    opacity: 0.5;
}

#sectors div:not(.alpha, .beta, .gamma)::after {
    content: attr(id) ' - Unassigned';
}

#sectors div:not(.alpha, .beta, .gamma):hover {
    opacity: 1.0;
}

But then it suddenly stops working — in all browsers! My unassigned sectors aren't grayed out, faded out or labeled 'Unassigned' anymore.

Updated but not so interactive jsFiddle preview

Why is the selector failing here? Shouldn't :not() work identically in both jQuery and CSS since jQuery borrows from the CSS3 standard, or is there something I'm missing? Is there even a workaround for this if I really want to avoid relying on a script?

Why is the selector failing here? Shouldn't :not() work identically in both jQuery and CSS since jQuery borrows from the CSS3 standard, or is there something I'm missing?

Perhaps it should, but it turns out that it doesn't. jQuery extends the :not() selector such that you can pass any selector to it, no matter how complex it may be, and I suspect that this is for parity with the .not() method, which also accepts any arbitrarily complex selector and filters accordingly. It does in a way maintain a CSS-like syntax, but it extends from what's defined in the standard.

As another example, this works just fine (I know it's an incredibly ludicrous example compared to what's given in the question, but it's just for illustrative purposes):

/* 
 * Select any section
 * that's neither a child of body with a class
 * nor a child of body having a descendant with a class.
 */
$('section:not(body > [class], body > :has([class]))')

jsFiddle preview

Remember that passing a comma-separated list of selectors to :not() means filtering elements that don't match any of the listed selectors.

Now the :not() pseudo-class in CSS3, on the other hand, is very limited by itself. You can only pass a single simple selector as an argument to :not(). This means you can pass only any one of these at a time:

  • Universal selector (*), optionally with a namespace

  • Type selector (a, div, span, ul, li, etc), optionally with a namespace

  • Attribute selector ([att], [att=val], etc), optionally with a namespace

  • Class selector (.class)

  • ID selector (.id)

  • Pseudo-class (:pseudo-class)

So, here are the differences between jQuery's :not() selector and CSS3's :not() selector:

  1. First and foremost, to answer the question directly: you can't pass a comma-separated selector list.1 For example, while the given selector works in jQuery as demonstrated in the fiddle, it isn't valid CSS3:

    /* If it's not in the Α, Β or Γ sectors, it's unassigned */
    #sectors div:not(.alpha, .beta, .gamma)
    

    Is there even a workaround for this if I really want to avoid relying on a script?

    Thankfully, in this case, there is. You simply have to chain multiple :not() selectors, one after another, in order to make it valid CSS3:

    #sectors div:not(.alpha):not(.beta):not(.gamma)
    

    It doesn't make the selector that much longer, but the inconsistency and inconvenience remain evident.

    Updated interactive jsFiddle preview

  2. You can't combine simple selectors into compound selectors for use with :not(). This works in jQuery, but is invalid CSS3:

    /* Do not find divs that have all three classes together */
    div:not(.foo.bar.baz)
    

    You'll need to split it up into multiple negations (not just chain them!) to make it valid CSS3:

    div:not(.foo), div:not(.bar), div:not(.baz)
    

    As you can see, this is even more inconvenient than point 1.

  3. You can't use combinators. This works in jQuery, but not CSS:

    /* 
     * Grab everything that is neither #foo itself nor within #foo.
     * Notice the descendant combinator (the space) between #foo and *.
     */
    :not(#foo, #foo *)
    

    This one is particularly nasty, primarily because it has no proper workaround. There are some loose workarounds (1 and 2), but they usually depend on the HTML structure and are therefore very limited in utility.

It's worth noting that the CSS4 Selectors spec enhances the :not() selector to allow a comma-separated list of compound selectors. Compound selectors are, quite simply, simple selectors combined (compounded) together, without combinators separating them. This means that the jQuery selectors shown in points 1 and 2 above will probably become equivalent and valid CSS4 as well, which will make the pseudo-class much, much more useful when CSS parsers start to support it in the coming years.

Unfortunately, it still does not allow combinators as shown in point 3, at least not as of this writing, so jQuery still has kind of the upper hand here. That shouldn't be much of a problem though, IMO, as you should rarely ever need to use combinators within the :not() selector (but that's just my take on it).2


1 Although this article says that you can pass a comma-separated list of selectors to :not() in Firefox 3, you're not supposed to be able to. It worked because of a bug in Firefox 3 for which I can't find the ticket anymore, but it shouldn't work until future browsers implement future standards. Seeing how often that article is cited to date, I've left a comment to this effect, but seeing also how old the article is and how infrequently the site is being updated, I'm really not counting on the author coming back to fix it.

2 On the other hand, I have no personal objections to using the .not() method with complex selectors and combinators myself. As a matter of fact, the documentation for jQuery's :not() selector states: "The .not() method will end up providing you with more readable selections than pushing complex selectors or variables into a :not() selector filter. In most cases, it is a better choice."

jqGrid does not render correctly in Chrome/Chrome Frame

18 votes

Currently using Chrome v19.0.1084.46 (Official Build 135956) beta-m jqGrid 4.3.2 (latest release)

The problem is that no matter the size of my grid, columns, or containing div, a small fraction of my last column gets pushed beyond the edge of the grid, causing horizontal scroll bars to appear, which should not happen. See below:

grid

I've been fiddling with the following attributes on jqGrid to try and fix this:

  • width
  • autowidth
  • height
  • shrinkToFit
  • scrollOffset - Had the best luck with this one, but nothing repeatable.

I've also stripped down to the basic grid css only, thinking it might have been a rule I put in place...with no luck.

Has anyone else experienced this and/or found a solution to this? Help is much appreciated.

I updated today my Chrome to version 19, have reproduced the problem and made the corresponding quick&dirty fix:

I suggest to change the line of jqGrid code

isSafari = $.browser.webkit || $.browser.safari ? true : false;

to the following

isSafari = ($.browser.webkit || $.browser.safari) &&
    parseFloat($.browser.version)<536.5 ? true : false; // Chrome < version 19

The demo use the fix. The fixed version of jquery.jqGrid.src.js which I used in the demo you can get here.

I tested it in IE9 (v9.0.8112.16421), IE8 (8.0.6001.18702CO), Chrome 18.0.125.168, Chrome 19.0.1084.46, Safari 5.1.7 (7534.57.2), Firefox 12, Opera 11.62. In all the web browsers the demo has no horizontal scrollbars and it looks as following:

enter image description here

In the future it would be better to change the calculation of width of the grid more deep to have no direct dependency from any version number or web browser. I hope it will be possible if one would use more jQuery methods $.width and $.outerWidth in some places of jqGrid. In any way I hope that the above described fix would be already helpful for many jqGrid users.

UPDATED: I posted my suggestion to trirand as the bug report.

UPDATED 2: To be exactly there are three places in the code where are used the same $.browser.webkit || $.browser.safari construct as described above: inside setGridWidth, inside of getOffset, inside of calculation of the width of multiselect column, inside showHideCol and inside setGridWidth. The first three places uses isSafari variable. The last two places uses $.browser.webkit || $.browser.safari directly. One should replace in all the places the code

$.browser.webkit||$.browser.safari

to

($.browser.webkit || $.browser.safari) && parseFloat($.browser.version)<536.5

So one should do this in three places:

  1. at the definition of the isSafari (see me original post)
  2. inside of showHideCol
  3. inside of setGridWidth

You can download the fixed version of the jquery.jqGrid.src with all the fixes here. You can make the same changes in the code of jquery.jqGrid.src yourself if you have to use old version of jqGrid. To created minimized version for the production you can use any minimizer which you good know. I use for example Microsoft Ajax Minifier 4.0. Just install it and execute

AjaxMin.exe jquery.jqGrid.src-fixed3.js -o jquery.jqGrid.min-fixed3.js

As the result you will get jquery.jqGrid.min-fixed3.js which will be even smaller as original jquery.jqGrid.min.js. Even if you add the comment header to the file (see modified file) the file will be still smaller as original version of jquery.jqGrid.min.js.

After some iterations of my bug report and the improvements there are one more version of the fix where the method cellWidth was introduced:

cellWidth : function () {
    var $testDiv = $("<div class='ui-jqgrid' style='left:10000px'><table class='ui-jqgrid-btable' style='width:5px;'><tr class='jqgrow'><td style='width:5px;'></td></tr></table></div>"),
        testCell = $testDiv.appendTo("body")
            .find("td")
            .width();
        $testDiv.remove();
        return testCell !== 5;
}

See here. If you prefer to follow the way you can do this also. In the case in all places where isSafari or $.browser.webkit || $.browser.safari (in showHideCol and setGridWidth) are used you can use $.jgrid.cellWidth() instead.

UPDATED 3: Today was published jqGrid 4.3.3 which contains the fix which I described above (the cellWidth method). So I recommend all to use the new version.

In jQuery, how do I select elements between elements with certain classes?

18 votes

I have an unordered list.

<ul>
    <li class="foo">Baz</li>
    <li>Select Me!</li>
    <li>Select Me!</li>
    <li>Select Me!</li>
    <li class="bar">Baz</li>
    <li>Don't Select Me</li>
    <li>Red Herring List Item</li>
</ul>

How do I select the list items in between the list items with classes foo and bar using jQuery? I do not know the contents of any list items. I also do not know how many list items are there to be selected so I cannot depend on a count.

$('li.foo').nextUntil('li.bar')

http://jsfiddle.net/zZRDB/1/

Find out if HTML height is set by style or by content

17 votes

I have 2 divs:

<div id="div1"></div>
<div id="div2">div2</div>​

in my css:

#div1{ height:20px}​

Both divs have 20px height, check demo
How can I find out if the div have it's height due to content or have been set in css or inline style?
This helps me find out the dimensions have been set by the developer or just calculated by the browser.

I found a way to achieve it :)

function getRealHeight(element){
    var height=0;
    if (element.children().length>0){
        var temp = $('<div></div>');
        temp.append(element.children());
        height = element.height();
        element.append(temp.children());
    } else {
        var html=element.html();
        element.html('');
        height = element.height();
        element.html(html);
    }
    return height;
}

DEMO

What JavaScript should be included in the <head> and what included in the <body>?

17 votes

I am confused about which JavaScript should be included where?

For instance:

  • Where should one include the jQuery libraries? In the <head> or before the closing </body> element?

  • If the JavaScript is defined at the bottom in the <body>, can it be used inline in the body?

  • If it blocks parallel downloads, then why is it never said to include your CSS at the bottom?

The Place of the <script> Element

The script elements block progressive page downloads.
Browsers download several components at a time, but when they encounter an external script, they stop further downloads until the script file is downloaded, parsed, and executed.
This hurts the overall page time, especially if it happens several times during a page load.
To minimize the blocking effect, you can place the script element toward the end of the page, right before the closing tag.
This way there will be no other resources for the script to block. The rest of the page components will be downloaded and already engaging the user.
The worst antipattern is to use separate files in the head of the document:

<!doctype html>
<html>
<head>
    <title>My App</title>
    <!-- ANTIPATTERN -->
    <script src="jquery.js"></script>
    <script src="jquery.quickselect.js"></script>
    <script src="jquery.lightbox.js"></script>
    <script src="myapp.js"></script>
</head>
<body>
...
</body>
</html>

A better option is to combine all the files:

<!doctype html>
<html>
<head>
    <title>My App</title>
    <script src="all_20100426.js"></script>
</head>
<body>
    ...
</body>
</html>

And the best option is to put the combined script at the very end of the page:

<!doctype html>
<html>
<head>
    <title>My App</title>
</head>
<body>
    ...
    <script src="all_20100426.js"></script>
</body>

“JavaScript Patterns, by Stoyan Stefanov (O’Reilly). Copyright 2010 Yahoo!, Inc., 9780596806750.”

jquery $('<div>') vs $('<div />')

15 votes

Possible Duplicate:
$('<element>') vs $('<element />') in jQuery

Which one of these two are the correct way to do it:

$('<div>') 

or

$('<div />')

They both seem to work. Is one way more right than the other, or do they both always work?

They produce identical results in jQuery.

15 votes

I read somewhere that jQuery is a monad and this answer shows that chain function in underscore.js library is not a monad (but comonad). And answer to this which is similar, shows that is monoid.

So, is jQuery a monad?

Most APIs do not satisify the monad laws. jQuery is a large API, so statistically, it is unlikely to be "accidentally" monadic. As a result I am pretty skeptical that the jQuery API as a whole could satisfy the monad laws (i.e. that "jQuery is a monad").

This doesn't mean that a given (very restricted) subset might not satisfy them, but the API as a whole is likely to contain "unsafe" operations that would violate the laws when used, breaking the abstraction.

Since no one seems to have offered evidence that the API in whole or part satisifies the laws, I suggest we should assume it does not, until evidence is provided.

It must be shown:

  • what jQuery operation corresponds to return (lifting a value into the jQuery monad)?
  • what jQuery operation corresponds to bind, for gluing computations together?
  • how do the left-, right- and associativity laws hold over those operations?

And then, what law violations are possible given the rest of the jQuery API? Can I, for example, break the bind by calling one of the other API functions?

References:

Animating a changing ranking table

14 votes

I have a ranking table which changes every second. I want to animate the table rows smoothly (not necessarily every second; maybe every 5 seconds).

A quick search revealed this jQuery plugin, based on this animated table sort. For my purposes, it looks a bit too much like a sports ranking, and the code is outdated and unmaintained.

Are there alternative plugins/libraries to animate changing ranking tables?

There is an interesting post on stackoverflow on your same subject: Using jquery, how to I animate adding a new list item to a list?

Of course it should be changed a little bit, because maybe you want to add more than one item to the list.

But what you can do is to refresh it every X seconds, and for each of the list item add the item in an animated way.

Is IE The Only Browser (or version) That Does Not Allow Flash Object Manipulation?

12 votes

I've tried multiple ways to edit Flash Objects / Embeds via Javascript and it seems to work in everything but IE, so I'm thinking about just throwing IE out the window for this application unless there are older + used version of other browsers that also do not allow you to edit objects. An example of this would be:

document.getElementById(divID).innerHTML = '<object ...><embed ...><\/embed><\/object>';

or in jquery

var params = '<param name="allowFullScreen" value="true" />' +
             '<param name="allowScriptAccess" value="always" />' +
             '<param name="allowNetworking" value="all" />' +
             '<param name="movie" value="player.swf" />' +
$("#objectPlayer").html(params);

If all the rest of the modern browsers and the most used versions of them do support this kind of editing then I'll just scrap IE. And before I get floods of the SWFObject JS Framework, I'm not going to include a huge framework for a browser that I do not believe is going to contain my demographic.

JSFiddle

Here's a link to a JSFiddle I created. It works in all browsers but IE8

I believe the <param>part of your code is for <object>.

You have to pass the name/value pairs for embed too.

$("#objectPlayer embed").attr({
    "src": "fileName.swf",
    "name": "fileName",
    "allowFullScreen": "true",
    "width": 200,
    "height": 100,
    "type": "application/x-shockwave-flash"

    //and so on...
    });

But I would use SWFObject anyway, it is the industry standard, it's quite robust and it is the best way of embedding flash on the website.

How is $('h1') logging to the web console as an array in jQuery?

12 votes

If you do console.log($('some selector')) in the browser, it returns what looks like an array (first line):

picture from latest version of chrome web console on Github project page

But notice that it's not an instanceof Array, but it's actually the jQuery object.

When you do console.dir($('h1')), it shows it's actually the jQuery object.

The question is, how are they making it look like it's an array in the web console? I noticed in the jQuery source here they add reference to a few Array and Object methods, and here they add toArray (and slice and others) to the jQuery object. Is the web console somehow checking for these methods and if it finds one (toArray, indexOf, slice, etc.), it prints it as an Array? I would like to get this behavior out of any custom object, such as the Ember.ArrayProxy. Currently when you log the Ember.ArrayProxy it shows > Object or whatever, but it would be nice to show it as an array.

Any ideas?

You make your object inherit Array using the prototype, like so:

function SomeType() {
    this.push(16);
}

SomeType.prototype = [];
SomeType.prototype.constructor = SomeType; // Make sure there are no unexpected results

console.log(new SomeType()); // Displays in console as [16]

And, of course, all jQuery objects are instances of the jQuery function/constructor, so that's how jQuery does it. As a bonus, because of the inheritance, you get all the methods from Array, and the indexing that comes with it too!

jquery .val() += idiom

9 votes

What's the clearest commonly used idiom for this jQuery snippet?

$('#someTextarea').val( $('#someTextarea').val() + someString );

It feels clunky to wrap the original code in a one-line function

EDIT: So I can pass a function, which is cool... but my real intentions are for jsfiddles, where I currently do stuff like this:

function lazylog (str) { 
    $('#ta').val( $('#ta').val() + str + '\n' );
}
// or
function lazylogPlain (str) {
    document.getElementById('ta').value += str + '\n';
}

// view results of little experiments
lazylog( test1() );
lazylog( test2() );
lazylog( test3() );
// etc...

Don't know if that context would produce different answers or just make me seem really lazy for wanting to type even less than that. console.log doesn't count, I want the textarea.

Just don't use jQuery.

document.getElementById('someTextarea').value += someString;

will be clearer, faster, and works as well as the jQuery snippet. If you really want to use the $ selector, with only one element you can also

$('#someTextarea')[0].value += someString; // least to type

Other possibilities are the .val() method with a function

$('#someTextarea').val(function(index, oldValue) { return oldValue + someString; })

or a variant with .each() (which is [nearly] equivalent to what val() does internally for text inputs):

$('#someTextarea').each(function(){ this.value += someString; })

These both need a one-line function expression you didn't like, but they have the advantage of working for more than one selected elements and they also return the jQuery object to preserve the chainability feature.

Download pdf asynchronously

8 votes

When a user clicks on a links in my Ruby on Rails app, a PDF file is generated in background.

The app is polling the server to know when the PDF file is ready, and then it should ask the user to download it as if he clicked on a PDF link that already existed.

We do this with an hidden iframe and change the src attribute when the PDF file is ready.

While it works on Firefox (there's a native pop up for downloading the file), it does not on safari/chrome. How should I do this? I've seen there's a Content-Disposition HTTP header, but the PDF file is stored on S3, so I don't think I can use that method.

You do need to use the Content-Disposition = 'attachment'; response header.

I'm not totally up to the play with S3 so let me know if this answer isn't quite right but it seems you are able to set the content headers in the request URL now, see example here.

Don't trigger hover event on children

8 votes

I have a container with tiles (grass, water, etc) and in some of them I have items (border-sprites, trees, and general items). Due to the nature of the sprites, all items are 64x64 while tiles are only 32x32.

My problem is that I want to trigger a hover event on tiles, but they are sometimes shadowed by another tiles' items.

The image below shows the problem. The thick green area is the tile that really gets hovered when I want to hover the tree-tile.

the problem

The CSS:

#map_canvas .tile{
    height: 32px;
    position: absolute;
    width: 32px;
}
#map_canvas .tile .item{
    background-position: bottom right;
    background-repeat: no-repeat;
    bottom: 0;
    display: inline-block;
    height: 64px;
    margin: 0;
    padding: 0;
    position: absolute;
    right: 0;
}

The HTML, simplified:

<div class="tile" style="background-image: url(grass.png);"></div>
<div class="tile" style="background-image: url(grass.png);"></div>
<div class="tile" style="background-image: url(grass.png);">
    <div class="item" style="background-image(top-left-border.png);"></div>
</div>

Here's the live demo http://sleavely.com/tiles/

I don't even know how to phrase the question, but here goes:

Is it possible to only trigger the event on the parent element (.tile) so that overflowing children (.item) do not obfuscate which tile I really hover?

EDIT: Thanks to @Brilliand I implemented the following

function figureOutTile(e){
    var $source = jQuery(e.srcElement);
    if($source.hasClass("item")){
        var $parent = $source.parent();
        var posx = $parent.attr("col");
        var posy = $parent.attr("row");
        if(e.offsetY <= 32){
            if(e.offsetX <= 32){
                return jQuery(".tile[col="+ (posx-1) +"][row="+ (posy-1) +"]");
            }else{
                return jQuery(".tile[col="+ posx +"][row="+ (posy-1) +"]");
            }
        }else{
            if(e.offsetX <= 32){
                return jQuery(".tile[col="+ (posx-1) +"][row="+ posy +"]");
            }else{
                return $parent;
            }
        }
    }else{
        return $source;
    }
}
jQuery("#map_viewport").on({
    mouseenter: function(e) {
        var $target = figureOutTile(e);
        $target.addClass('hovered');
    },
    mouseleave: function() {
        jQuery(".tile.hovered").removeClass('hovered');
    }
}, '.tile');​

As far as your browser is concerned, hovering over something sticking out of a tile is the same as hovering over the tile that it's sticking out of, not hovering over whatever is being covered up. To work around this in your specific situation, I suggest putting your hover function on #map_canvas, and working out in that function which tile is being hovered over. For tiles in a rectangular grid, this is simple arithmetic.

Of course, for this to work you will need to include a mousemove event (to detect when the mouse moves from one tile to another), and you should probably include code to exit the function if the user is still hovering over the same tile.

EDIT: Although this answer has already been accepted, here's a solution based on my comment:

$(".tile").append($("<div/>", {
    css: {
        position: "absolute",
        top: 0,
        left: 0,
        right: 0,
        bottom: 0,
        "z-index": 50
    }
}));

This seems to fix the problem for all of the tiles with items on them, though it screws up your :empty declarations. I mention it mainly because it comes closer to answering your question as asked.

How to compare two HTML elements

7 votes

How can we compare two HTML elements whether they are identical or not ?

I tried this thing but no luck

<div class="a"> Hi this is sachin tendulkar </div>
<div class="a"> Hi this is sachin tendulkar </div>

And then on button click, I call a function check()

var divs = $(".a");
alert(divs.length);    // Shows 2 here which is correct
if (divs.get(0) == divs.get(1)) alert("Same");

But this is not working. Everything is same in two divs. Apart from this How can we compare whether two HTML elements are completely idential or not. Including their innerHTML, className, Id, and their attributes.

Is this doable ?

Actually, I have two HTML documents and I want to remove the identical content from both of them So two elements can have same id.

PS: Updating after Crowder's valuable comments. If we compare two elements as strings, we would not get a match as their order of attributes may vary So the only option is to iterate through each child attribute and match. I still have to figure out completely working implementation strategy.

(See below for a complete, largely-untested, and certainly un-refactored off-the-cuff solution. But first, the bits and pieces of it.)

Comparing their innerHTML is easy:

if (divs[0].innerHTML === divs[1].innerHTML)
// or if you prefer using jQuery
if (divs.html() === $(divs[1]).html()) // The first one will just be the HTML from div 0

...although you have to ask yourself whether these two elements are equivalent according to your criteria:

<div><span class="foo" data-x="bar">x</span></div>
<div><span data-x="bar" class="foo">x</span></div>

...because their innerHTML will be different (at least on Chrome, and I suspect on most if not all browsers). (More on that below.)

Then you need to compare all of their attributes. As far as I know, jQuery doesn't give you a means of enumerating the attributes, but the DOM does:

function getAttributeNames(node) {
  var index, rv, attrs;

  rv = [];
  attrs = node.attributes;
  for (index = 0; index < attrs.length; ++index) {
    rv.push(attrs[index].nodeName);
  }
  rv.sort();
  return rv;
}

Then

var names = [getAttributeNames(div[0]), getAttributeNames(div[1])];
if (names[0].length === names[1].length) {
    // Same number, loop through and compare names and values
    ...
}

Note that by sorting the arrays above, I'm assuming the order of their attributes is not significant in your definition of "equivalent." I hope that's the case, because it doesn't seem to be preserved, as I get different results from different browsers when running this test. That being the case, we have to come back to the innerHTML question, because if the order of attributes on the elements themselves is not significant, then presumably the order of attributes on descendant elements shouldn't be significant. If that's the case, you'll need a recursive function that checks the descendants according to your definition of equivalent, and not use innerHTML at all.

But you should be able to put something together from the pieces above to compare two elements according to your criteria.

More to explore:


The question interested me strangely, so I kicked around at it for a while, and came up with the following. It's mostly untested, could use some refactoring, etc., but it should get you most of the way there. I do, again, assume the order of attributes is not significant. The below assumes even the slightest difference in the text is significant.

function getAttributeNames(node) {
  var index, rv, attrs;

  rv = [];
  attrs = node.attributes;
  for (index = 0; index < attrs.length; ++index) {
    rv.push(attrs[index].nodeName);
  }
  rv.sort();
  return rv;
}

function equivElms(elm1, elm2) {
  var attrs1, attrs2, name, node1, node2;

  // Compare attributes without order sensitivity
  attrs1 = getAttributeNames(elm1);
  attrs2 = getAttributeNames(elm2);
  if (attrs1.join(",") !== attrs2.join(",")) {
    display("Found nodes with different sets of attributes; not equiv");
    return false;
  }

  // ...and values
  // unless you want to compare DOM0 event handlers
  // (onclick="...")
  for (index = 0; index < attrs1.length; ++index) {
    name = attrs1[index];
    if (elm1.getAttribute(name) !== elm2.getAttribute(name)) {
      display("Found nodes with mis-matched values for attribute '" + name + "'; not equiv");
      return false;
    }
  }

  // Walk the children
  for (node1 = elm1.firstChild, node2 = elm2.firstChild;
       node1 && node2;
       node1 = node1.nextSibling, node2 = node2.nextSibling) {
     if (node1.nodeType !== node2.nodeType) {
       display("Found nodes of different types; not equiv");
       return false;
     }
     if (node1.nodeType === 1) { // Element
       if (!equivElms(node1, node2)) {
         return false;
       }
     }
     else if (node1.nodeValue !== node2.nodeValue) {
       display("Found nodes with mis-matched nodeValues; not equiv");
       return false;
     }
  }
  if (node1 || node2) {
    // One of the elements had more nodes than the other
    display("Found more children of one element than the other; not equivalent");
    return false;
  }

  // Seem the same
  return true;
}

Live examples:

What does "return false;" do?

7 votes

I wrote a webpage where a user can enter a log entry that is stored on a database and then retrieved and printed on the page using ajax. I am still quite new to ajax and was wondering if somebody could please explain to me what does return false; do at the end of my code? and is it even necessary?

If I put the second ajax code after the return false the code does not work! can you please explain to me why?

//handles submitting the form without reloading page 
$('#FormSubmit').submit(function(e) {
    //stores the input of today's data
    var log_entry = $("#LogEntry").val();
    // prevent the form from submitting normally
    e.preventDefault();

    $.ajax({
        type: 'POST',
        url: 'behind_curtains.php',
        data: {
            logentry: log_entry
        },
        success: function() {
            alert(log_entry);
            //clears textbox after submission
            $('#LogEntry').val("");
            //presents successs text and then fades it out
            $("#entered-log-success").html("Your Entry has been entered.");
            $("#entered-log-success").show().fadeOut(3000);
        }
    });
    //prints new log entries on page upon submittion
    $.ajax({
        type: 'POST',
        url: '/wp-content/themes/childOfFanwood/traininglog_behind_curtains.php',
        data: {
            log_entries_loop: "true"
        },
        success: function(data) {
            alert(data);
            $("#log-entry-container").html("");
            $("#log-entry-container").html(data);
        }
    });
    return false;
});
​

What I'll write here is true for jQuery events,
For vanilla javascript events read @T.J. Crowder comment at the bottom of the answer


return false inside a callback prevents the default behaviour. For example, in a submit event, it doesn't submit the form.

return false also stops bubbling, so the parents of the element won't know the event occurred.

return false is equivalent to event.preventDefault() + event.stopPropagation()

And of course, all code that exists after the return xxx line won't be executed. (as with all programming languages I know)

Maybe you find this helpful:
Stop event bubbling - increases performance?


A "real" demo to explain the difference between return false and event.preventDefault():

Markup:

<div id="theDiv">
    <form id="theForm" >
        <input type="submit" value="submit"/> 
    </form>
</div>​

JavaScript:

$('#theDiv').submit(function() {
    alert('DIV!');
});
$('#theForm').submit(function(e) {
    alert('FORM!');
    e.preventDefault();
});​

Now... when the user submit the form, the first handler is the form submit, which preventDefault() -> the form won't be submitted, but the event bubbles to the div, triggering it's submit handler.

Live DEMO

Now, if the form submit's handler would cancel the bubbling with return false:

$('#theDiv').submit(function() {
    alert('DIV!');
});
$('#theForm').submit(function(event) {
    alert('FORM!');
    return false;   
    // Or:
    event.preventDefault(); 
    event.stopPropagation();
});​

The div wouldn't even know there were a form submittion.

Live DEMO


What does return false do in vanilla javascript events

return false from a DOM2 handler (addEventListener) does nothing at all (neither prevents the default nor stops bubbling; from a Microsoft DOM2-ish handler (attachEvent), it prevents the default but not bubbling; from a DOM0 handler (onclick="return ..."), it prevents the default (provided you include the return in the attribute) but not bubbling; from a jQuery event handler, it does both, because that's a jQuery thing. Details and live tests here – T.J. Crowder

Regular expression pattern matching for number,alphabetcic blocks

6 votes

Im having some strings like these

aa11b2s
abc1sff3
a1b1sdd2

etc.... i need to change these strings to these

aa 11 b 2 s
abc 1 sff 3
a 1 b 1 sdd 2

Simply saying..i need to add a space between each(number/alphabetic s) blocks

var str = 'aa11b2s';
console.log(str.replace(/([\d.]+)/g, ' $1 ').replace(/^ +| +$/g, ''));

AJAX IRCX Client and Server

5 votes

I am currently developing an IRCX AJAX Chat based system and have a few questions regarding the Server and Client implementation; Any suggestions are welcome:

Server

Should this be implemented as a Web Service, or a Windows Form application? I have experience in developing Windows Forms based servers, however I am wondering if this would be better implemented as a Web Service and if so, why?

Client

How are Web Based Clients implemented today and what is the preferred method to implement a Web Based Client?

My solution so far are

  • ASP.NET Web Forms with an AJAX Update Panel (This seems the most viable)
  • Using jQuery connecting to the web service with a JavaScript timeout

Polling

How frequently should the server be polled for new messages? 0.5 seconds seems a bit excessive and anything between 2 or 3 seconds seems sluggish.

Thanks for your input.

I believe using ASP.NET (Sockets and an Update Panel) seems to be the best approach. Using jQuery in this context now seems a bit invalid because it would not maintain a persistent state with the Chat Server which is required for Real Time Communication.

An alternative way I found would be using a Web Sockets and Backbone.JS to deal with the data returned from the server.

http://blog.fogcreek.com/the-trello-tech-stack/