Best jquery questions in January 2011

When to use Vanilla Javascript vs. jQuery?

39 votes

I have noticed while monitoring/attempting to answer common jQuery questions, that there are certain practices using javascript, instead of jQuery, that actually enable you to write less and do ... well the same amount. And may also yield performance benefits.

A specific example

$(this) vs this

Inside a click event referencing the clicked objects id

jQuery

$(this).attr("id");

Javascript

this.id;

Are there any other common practices like this? Where certain Javascript operations could be accomplished easier, without bringing jQuery into the mix. Or is this a rare case? (of a jQuery "shortcut" actually requiring more code)

EDIT : While I appreciate the answers regarding jQuery vs. plain javascript performance, I am actually looking for much more quantitative answers. While using jQuery, instances where one would actually be better off (readability/compactness) to use plain javascript instead of using $(). In addition to the example I gave in my original question.

  • this.id (as you know)
  • this.value (on most input types. only issues I know are IE when a <select> doesn't have value properties set on its <option> elements, or radio inputs in Safari.)
  • this.className to get or set an entire "class" property
  • this.selectedIndex against a <select> to get the selected index
  • this.options against a <select> to get a list of <option> elements
  • this.text against an <option> to get its text content
  • this.rows against a <table> to get a collection of <tr> elements
  • this.cells against a <tr> to get its cells (td & th)
  • this.parentNode to get a direct parent
  • this.checked to get the checked state of a checkbox Thanks @Tim Down
  • this.selected to get the selected state of an option Thanks @Tim Down
  • this.disabled to get the disabled state of an input Thanks @Tim Down
  • this.readOnly to get the readOnly state of an input Thanks @Tim Down
  • this.href against an <a> element to get its href
  • this.hostname against an <a> element to get the domain of its href
  • this.pathname against an <a> element to get the path of its href
  • this.search against an <a> element to get the querystring of its href
  • this.src against an element where it is valid to have a src

...I think you get the idea.

There will be times when performance is crucial. Like if you're performing something in a loop many times over, you may want to ditch jQuery.

In general you can replace:

$(el).attr('someName');

with:

Above was poorly worded. getAttribute is not a replacement, but it does retrieve the value of an attribute sent from the server, and its corresponding setAttribute will set it. Necessary in some cases.

The sentences below sort of covered it. See this answer for a better treatment.

el.getAttribute('someName');

...in order to access an attribute directly. Note that attributes are not the same as properties (though they mirror each other sometimes). Of course there's setAttribute too.

Say you had a situation where received a page where you need to unwrap all tags of a certain type. It is short and easy with jQuery:

$('span').unwrap();  // unwrap all span elements

But if there are many, you may want to do a little native DOM API:

var spans = document.getElementsByTagName('span');

while( spans[0] ) {
    var parent = spans[0].parentNode;
    while( spans[0].firstChild ) {
        parent.insertBefore( spans[0].firstChild, spans[0]);
    }
    parent.removeChild( spans[0] );
}

This code is pretty short, it performs better than the jQuery version, and can easily be made into a reusable function in your personal library.

It may seem like I have an infinite loop with the outer while because of while(span[0]), but because we're dealing with a "live list" it gets updated when we do the parent.removeChild(span[0]);. This is a pretty nifty feature that we miss out on when working with an Array (or Array-like object) instead.

Most appropriate way to get this: $($(".answer")[0])

27 votes

Suppose I want to get the first element amongst all the elements of the class ".answer"

$($(".answer")[0])

I can do the above, but what is the best balance between elegance and speed?

*changed the question to reflect the current discussion

The following are all equivalent in functionality (though not speed):

Which is the best?
It has been hypothesized that the selector versions should be faster than the method versions (and the logic makes some sense) but I have not yet found a reliable cross-browser, multi-document benchmark that proves this to be true.

And in some cases you cannot use the selector, as you have a jQuery object resulting from chained results and must later pare it down.

Edit: Based on the excellent information from @yc's tests below, following are the current (2011-Feb-4) test results summarized and compared against a baseline of .answer:first:

          :first  :eq(0)  .first()  .eq(0)  $($('...')[0])
Chrome 8+   100%     92%      224%    266%       367%
   FF 3.6   100%    100%      277%    270%       309%
  FF 4.0b   100%    103%      537%    521%       643%
 Safari 5   100%     93%      349%    352%       467%
 Opera 11   100%    103%      373%    374%       465%
     IE 8   100%    101%     1130%   1246%      1767%
 iPhone 4   100%     95%      269%    316%       403%
=====================================================
 Weighted   100%     92%      286%    295%       405%
    Major   100%     95%      258%    280%       366%
  • The Weighted line shows the performance weighted by the number of tests per browser; popular browsers (among those testing) are counted more strongly.
  • The Major line shows the same, only including non-beta releases of the major desktop browsers.

In summary: the hypothesis is (currently) wrong. The methods are significantly faster than the Sizzle selectors, and with almost exception the OP's code $($('.answer')[0]) is the fastest of them all!

Best JavaScript solution for client-side form validation and interaction?

18 votes

Our web forms are really complex. What's a great solution for extensible form validation, preferably one that works with jQuery?

Background:

Our site has a bit of Ajax, but the real focus is on user experience through about 20 multi-page forms or "wizards." These forms are complicated.

  • Presentation: Some fields are floats or ints. Validation means stripping non-decimal characters, but we also want to make sure that, if a user enters 5 into a price field, the field is updated to 5.00.
  • Side effects: Some fields have side effects when updated. E.g., updating the price or quantity of an item needs to update a subtotal field.
  • Widget-driven elements: Some fields are hidden and have values populated by widgets. E.g., a map widget lets you point to a location and a hidden field is updated with latitude-longitude coordinates, but the location must be within a certain region.
  • Groups: Some fields are groups, like address/city/state/zip, and should only be validated when all of the fields have bee populated.
  • Server-side validation: Validation of some fields requires back-end checking via Ajax requests
  • Multiple forms per page: Sometimes a user needs to fill out one form before a dialog opens with another form. A framework has to be more versatile than binding to onSubmit — we sometimes post multiple forms in order from the same page using Ajax. (E.g., we let users sign up and create a widget in one swoop but, due to legacy systems, that flow requires two POST requests.)
  • Customizable error display: Sometimes errors appear above fields, sometimes the field style changes, and our new designs call for tooltip-like popups (ala qTip) for some errors.
  • Snappiness: User experience is key and tactile feedback is important. Any solution
  • Submit buttons: Clicking the submit button needs to validate everything and then show a response — but since some of the validation happens asynchronously.

We're currently using the jQuery Validation library but our forms appear to be outgrowing its capability. I've been looking at things like <angular/>, Knockout and Backbone.js, but I'm worried that they're too heavyweight or that they would require us to rewrite our frontend.

(This should be a community wiki.)

Answering this myself since someone on our team noticed Validator from jQuery Tools !

  • Presentation - Supports HTML5 input fields. pattern fields make sure the user can only input test in a certain pattern.
  • Side effects - Triggers events on the form and on individual fields: onFail and onSuccess
  • Widget-driven elements - "Custom input types" are encouraged. The basic demo even includes a natural numbers-old "age" field.
  • Groups - Write a "function matcher" whose sole purpose is to filter which fields are to be validated.
  • Server-side validation - Does it and does it intelligently — depends on your validator calling a callback (so it's async-friendly) instead of a return value.
  • Multiple forms per page - jQuery Tools seems to be very well built and this shouldn't be a problem.
  • Customizable error display - Errors next to fields? All in one place? No problem. Still not good enough? Bind events on failure. Even uses tooltips by default.
  • Snappiness - Demos are very snappy
  • Submit buttons - No problem.

Update: Yep, just reimplemented a chunk of our site with jQuery Tools' validator tooltips. Fantastic!

JavaScript: Invert color on all elements of a page

13 votes

I want to be able to invert the color of all the elements on a page with a JavaScript bookmarklet. I know that to invert a color you subtract each of the RGB hex values from 255(xFF), but beyond that I am unsure of how to proceed.

How can I accomplish this?

Using jQuery is acceptable, and it only needs to work on Chrome, although if it worked in Firefox that'd be a plus.

EDIT: This is excluding images - background, text and links colors should all be inverted. Basically anything that gets its color from CSS.

UPDATE Here is an updated bookmarklet that fixes the nested element issue and will work on a lot of different sites (including this one):

javascript: function load_script(src, callback) {    var s = document.createElement('script');    s.src = src;    s.onload = callback;    document.getElementsByTagName('head')[0].appendChild(s);}function invertElement() {    var colorProperties = ['color', 'background-color'];    var color = null;    for (var prop in colorProperties) {        prop = colorProperties[prop];        if (!$(this).css(prop)) continue;        if ($(this).data(prop) != $(this).css(prop)) continue;        color = new RGBColor($(this).css(prop));        if (color.ok) {            $(this).css(prop, 'rgb(' + (255 - color.r) + ',' + (255 - color.g) + ',' + (255 - color.b) + ')');        }        color = null;    }}function invertColors() {    $('body').find('*').andSelf().each(function(){        var colorProperties = ['color', 'background-color'];        for (var prop in colorProperties){           prop = colorProperties[prop];    console.log(prop,$(this),$(this).data(prop),$(this).css(prop));            $(this).data(prop,$(this).css(prop));        }    });    $('body').find('*').andSelf().each(invertElement);    $('iframe').each(function () {        $(this).contents().find('*').each(invertElement);    });}load_script('http://www.phpied.com/files/rgbcolor/rgbcolor.js', function () {    if (!window.jQuery) load_script('https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js', invertColors);    else invertColors();});

Still needs work on a number of different sites.

First things first, grab the awesome RGBColor class here.

Here goes:

jsFiddle example

//set up color properties to iterate through
var colorProperties = ['color', 'background-color'];

//iterate through every element
$('*').each(function() {
    var color = null;

    for (var prop in colorProperties) {
        prop = colorProperties[prop];

        //if we can't find this property or it's null, continue
        if (!$(this).css(prop)) continue; 

        //create RGBColor object
        color = new RGBColor($(this).css(prop));

        if (color.ok) { 
            //good to go, let's build up this RGB baby!
            //subtract each color component from 255
            $(this).css(prop, 'rgb(' + (255 - color.r) + ', ' + (255 - color.g) + ', ' + (255 - color.b) + ')');
        }
        color = null; //some cleanup
    }
});

Screenshot:

alt text

EDIT: Here's a bookmarklet you can now copy-paste into your browser (http://jsfiddle.net/F7HqS/1/)

javascript:function load_script(src,callback){var s=document.createElement('script');s.src=src;s.onload=callback;document.getElementsByTagName('head')[0].appendChild(s);}function invertColors(){var colorProperties=['color','background-color'];$('*').each(function(){var color=null;for(var prop in colorProperties){prop=colorProperties[prop];if(!$(this).css(prop))continue;color=new RGBColor($(this).css(prop));if(color.ok){$(this).css(prop,'rgb('+(255-color.r)+','+(255-color.g)+','+(255-color.b)+')');}color=null;}});}load_script('http://www.phpied.com/files/rgbcolor/rgbcolor.js',function(){if(!window.jQuery)load_script('https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js',invertColors);else invertColors();});

Iterating Through N Level Children

10 votes

This seems like something neat that might be "built into" jQuery but I think it's still worth asking.

I have a problem where that can easily be solved by iterating through all the children of a element. I've recently discovered I need to account for the cases where I would need to do a level or two deeper than the "1 level" (just calling .children() once) I am currently doing.

jQuery.each(divToLookAt.children(), function(index, element)
    {
        //do stuff
    }
    );  

This is what I'm current doing. To go a second layer deep, I run another loop after doing stuff code for each element.

jQuery.each(divToLookAt.children(), function(index, element)
{
     //do stuff
    jQuery.each(jQuery(element).children(), function(indexLevelTwo, elementLevelTwo)
    {
        //do stuff
    }
    );  
}
);

If I want to go yet another level deep, I have to do this all over again.

This is clearly not good. I'd love to declare a "level" variable and then have it all take care of. Anyone have any ideas for a clean efficient jQueryish solution?

Thanks!

This is an awesome question because of the levels deep catch. Check out the fiddle.

Converted this to a plugin.

Activate

$('#div').goDeep(3, function(deep){ // $.fn.goDeep(levels, callback)
    // do stuff on `this`
});

Plugin

$.fn.goDeep = function(levels, func){
    var iterateChildren = function(current, levelsDeep){
        func.call(current, levelsDeep);

        if(levelsDeep > 0)
            $.each(current.children(), function(index, element){
                iterateChildren($(element), levelsDeep-1);
            });
    };

    return this.each(function(){
        iterateChildren($(this), levels);
    });
};

How to make this JavaScript much faster?

9 votes

Still trying to answer this question, and I think I finally found a solution, but it runs too slow.

var $div = $('<div>')
    .css({ 'border': '1px solid red', 'position': 'absolute', 'z-index': '65535' })
    .appendTo('body');

$('body *').live('mousemove', function(e) {
    var topElement = null;
    $('body *').each(function() {
        if(this == $div[0]) return true;
        var $elem = $(this);
        var pos = $elem.offset();
        var width = $elem.width();
        var height = $elem.height();
        if(e.pageX > pos.left && e.pageY > pos.top
            && e.pageX < (pos.left + width) && e.pageY < (pos.top + height)) {
            var zIndex = document.defaultView.getComputedStyle(this, null).getPropertyValue('z-index');
            if(zIndex == 'auto') zIndex = $elem.parents().length;
            if(topElement == null || zIndex > topElement.zIndex) {
                topElement = {
                    'node': $elem,
                    'zIndex': zIndex
                };
            }

        }
    });
    if(topElement != null ) {
        var $elem = topElement.node;
        $div.offset($elem.offset()).width($elem.width()).height($elem.height());
    }
});

It basically loops through all the elements on the page and finds the top-most element beneath the cursor.

Is there maybe some way I could use a quad-tree or something and segment the page so the loop runs faster?

Is there maybe some way I could use a quad-tree or something and segment the page so the loop runs faster?

Just step back a bit, realize how small the problem is, and that the harder your try the more complicated answer you will use.

Now what you need to do is to create 4 elements for the highlighting. They will form an empty square, and so your mouse events are free to fire. This is similar to this overlay example I've made.

The difference is that you only need the four elements (no resize markers), and that the size and position of the 4 boxes are a bit different (to mimick the red border). Then you can use event.target in your event handler, because it gets the real topmost element by default.

Another approach is to hide the exra element, get elementFromPoint, calculate then put it back.

They're faster than light, I can tell you. Even Einstein would agree :)

1.) The easy & nice - [Demo1] (overlay or borders) FF needs v3.0+

var box = $("<div class='outer' />").css({
  display: "none", position: "absolute", 
  zIndex: 65000, background:"rgba(255, 0, 0, .3)"
}) .appendTo("body");

var last = +new Date;
$("body").mousemove(function(e){
    var offset, el = e.target;
    var now = +new Date;
    if (now-last < 25) 
      return;
    last = now;
    if (el === document.body) {
        box.hide(); 
        return;
    } else if (el.className === "outer") {
        box.hide();
        el = document.elementFromPoint(e.clientX, e.clientY);
    }
    el = $(el);
    offset = el.offset();
    box.css({
        width:  el.outerWidth()  - 1, 
        height: el.outerHeight() - 1, 
        left:   offset.left, 
        top:    offset.top 
    });
    box.show();   
});​

2.) The fast & robust - [Demo2] (only supports borders)

var box = new Overlay();

$("body").mouseover(function(e){
  var el = $(e.target);
  var offset = el.offset();
  box.render(el.outerWidth(), el.outerHeight(), offset.left, offset.top);
});​

/**
 * This object encapsulates the elements and actions of the overlay.
 */
function Overlay(width, height, left, top) {

    this.width = this.height = this.left = this.top = 0;

    // outer parent
    var outer = $("<div class='outer' />").appendTo("body");

    // red lines (boxes)
    var topbox    = $("<div />").css("height", 1).appendTo(outer);
    var bottombox = $("<div />").css("height", 1).appendTo(outer);  
    var leftbox   = $("<div />").css("width",  1).appendTo(outer);
    var rightbox  = $("<div />").css("width",  1).appendTo(outer);

    // don't count it as a real element
    outer.mouseover(function(){ 
        outer.hide(); 
    });    

    /**
     * Public interface
     */

    this.resize = function resize(width, height, left, top) {
      if (width != null)
        this.width = width;
      if (height != null)
        this.height = height;
      if (left != null)
        this.left = left;
      if (top != null)
        this.top = top;      
    };

    this.show = function show() {
       outer.show();
    };

    this.hide = function hide() {
       outer.hide();
    };     

    this.render = function render(width, height, left, top) {

        this.resize(width, height, left, top);

        topbox.css({
          top:   this.top,
          left:  this.left,
          width: this.width
        });
        bottombox.css({
          top:   this.top + this.height - 1,
          left:  this.left,
          width: this.width
        });
        leftbox.css({
          top:    this.top, 
          left:   this.left, 
          height: this.height
        });
        rightbox.css({
          top:    this.top, 
          left:   this.left + this.width - 1, 
          height: this.height  
        });

        this.show();
    };      

    // initial rendering [optional]
    // this.render(width, height, left, top);
}

Most efficient way to use selectors in jQuery?

9 votes

is it more efficient to use $('.active') or $('div.active') ? I have always avoided including "div" because it's extra text in the javascript file I don't want the user to have to download.

Older versions of IE will benefit from the inclusion of div because they don't support getElementsByClassName().

Because of that, every element on the page needs to be selected with:

document.getElementsByTagName('*');

...and manually tested to see if it has the active class.

If you include div, then it is able to narrow it down a bit, since it can do:

document.getElementsByTagName('div');

...then test only those elements.

When I say older versions, I mean IE6 and IE7 since IE8+ supports querySelectorAll.


EDIT:

Browser suppport:

Jquery hide() and show() runs too slow in google chrome.

9 votes

Hello,

I have a web application that doesn't run correctly in chrome. Works perfectly in Firefox. I have a page with a large numbered of list items, 316 to be exact. Each list item contains a large amount of HTML. My problem is when I want to hide or show these list items.

I have a test page on jsFiddle to show the problem I'm having. I stripped down the HTML page to one unordered list to hold all 316 list items. I have two buttons that simply call jQuery hide or show when clicked. Again this runs fast in Firefox, Opera, even IE, pretty well in Safari but in Google Chrome it can take over 30 seconds which brings up the dialog window asking if you want to kill the page because a script is running to long.

Here is the link to jsFiddle

http://jsfiddle.net/oumichaelm/UZCZc/3/embedded/result/

thanks for any input. jmm

Looks like this has nothing to do with jQuery and just is a problem with Chrome hiding an parent element that has a HUGE number of children elements.

This just uses basic javascript to hide the element on document ready:

document.getElementById('sortable-lines').style.display="none";

And it still takes forever after the document is ready.

http://jsfiddle.net/petersendidit/UZCZc/10/embedded/result/

Opened a Chrome bug for this: http://code.google.com/p/chromium/issues/detail?id=71305

get word click in paragraphs

8 votes

I have an HTML document with about 30,000 words in it.

I'd like to be able to do something when a user clicks any word. For simplicity/concept right now, I'd just like to alert() that word.

For example, in the paragraph about, if I were to click on "have" it should run alert("have").

I'm using jQuery.

var p = $('p');

p
 .html(function(index, oldHtml) {
    return oldHtml.replace(/\b(\w+?)\b/g, '<span class="word">$1</span>')
 })
 .click(function(event) { alert(event.target.innerHTML) });

I took Pablo Fernandez's suggestions into account.

See it on jsFiddle.

Update

So, will this be performant (e.g., it won't freeze up a slow user's browser?) Also, could you elaborate about how event.target works?

It may very well slow the performance of a page with 30,000 words. I'd argue that is excessive and probably would benefit from being paginated, but I don't know your exact circumstances.

event.target property holds the element that started the event - the event bubbles up / propagates to its parent, which then handles the event, so you don't have 30,000 events on separate span elements.

Circular dock/menu in css or jquery

8 votes

Is it possible to have a circular menu or dock using css or jquery.?
I have a set of images as the dock items that need to be displayed as a circular dock... however the number of items in the dock are not constant and may vary.... so i cannot tend to use constant values for positioning each item in a pre-defined manner. Ajax loads some images into this particular div and i need to use css or jquery to style this so that they get displayed as circular dock items. Any idea on how this can be implemented..?
I would like a browser in-specific implementation, but i also welcome if some one has some solutions specific to few browsers...

UPDATE
I don't think i exactly want a pie menu... it easily gets messed up as the number of dock items increase. I am looking for a spiral dock. and by spiral i mean that the menu items must be in the following alignment.. alt text

I got it I think! This is just a basic concept, so please tweak it yourself.

http://www.mathematische-basteleien.de/spiral.htm#Spirals%20by%20polar%20equations

See the following JSFiddle and the code below:

var items = 10;
var a = 20;
var b = 1; // updated an extra b, used for rate (see update section below)
var centerX = $('.content').innerWidth()/2; // and some adjustment of half its own size
var centerY = $('.content').innerHeight()/2;
for(var i = 0; i < items; i++)
{
    var yPos = a * i * Math.cos(b*i) + centerY;
    var xPos = a * i * Math.sin(b*i) + centerX;
    var item = '<div class="item" style="top:' + yPos   + 'px; left:' + xPos + 'px;" />';
    $('.content').append(item);
}

And some CSS for testing purposes:

.item
{
    width:10px;
    height:10px;
    position: absolute;
    background-color:red;
}

.content
{
    position:relative;
    height:300px;
    width:300px;
    background-color:green;
}

<div class="content">
</div>

Update: answer to the comment

The function for yPos and xPos are generating items to the outside, they start from the center point. By defining a different a and a an extra var b inside the Math.cos(b*i). It is possible to change the rate of the divs showing up and the spread of the total spiral. The spread of the spiral is defined by a, because it defines the amplitude. The rate that divs are showing up is defined by the new b.

So a smaller b means lower angles, means closer together on the spiral. A smaller a means lower amplitude, means closer together in x and y axes.

If the number of images is not predictable, it shouldn't matter, because of the spiral going out. Of course, this will give you problems when adding too much.

Another solution is just doing this in PHP, because it has nothing dynamic to do, so you can already do this in your backend. The could will be the same with the forloop and all, but then with printing statements in your PHP.

detecting line-breaks with jQuery?

8 votes

is it possible to have jQuery/javascript detect where a string is broken (in order to fit into CSS width constraints) so as to insert DOM elements before the beginning of a new line?

Here is one approach. Note: I do not see a ideal solution without using monospace fonts. The equal with characters make this task much easier.

  1. Equal width characters
  2. Calculate the size of one character
  3. Calculate the size of the container
  4. Find characters per row
  5. Find where the row will break (ie whitespace, dashes, etc)
  6. Get all breaking indexes.

Have a look at the jsfiddle for associated html. I have not completed this function. More checks need to be put in when calculating the breaking index. Right now it is using lastIndexOf(' '), but this ignores that the next index could be a space, or the current. Also I am not accounting for other line-breaking characters. However this should be a great starting point.

var text = $('#text').text(),                   // "lorem ipsum ... "
    len = text.length,                          // total chars
    width = $('#text').width(),                 // container width
    span = $('<span />').append('a').appendTo('#sandbox'),
    charWidth = span.width(),                  // add single character to span and test width
    charsPerRow = Math.floor(width/charWidth); // total characters that can fit in one row

var breakingIndexes = [], // will contain indexes of all soft-breaks
    gRowStart = 0,        // global row start index
    gRowEnd = charsPerRow;// global row end index

while(gRowEnd < len){
    var rowEnd = text.substring(gRowStart, gRowEnd).lastIndexOf(' '); // add more checks for break conditions here
    breakingIndexes.push(gRowStart + rowEnd); // add breaking index to array
    gRowStart = gRowStart + rowEnd + 1; // next start is the next char
    gRowEnd = gRowStart + charsPerRow;  // global end inxex is start + charsperrow
}

var text2 = $('#text2').text();           // "lorem ipsum ... " now not width bound
var start = 0, newText = '';
for(var i=0; i < breakingIndexes.length; i++){
    newText += text2.substring(start, breakingIndexes[i]) + '<br />'; // add hard breaks
    start = breakingIndexes[i]; // update start
}

$('#text2').html(newText); // output with breaks

http://jsfiddle.net/Y5Ftn/1/

HTML5 Local Storage fallback solutions

8 votes

I'm looking for javascript libraries and code that can simulate localStorage on browsers that do not have native support.

Basically, I'd like to code my site using localStorage to store data and know that it will still work on browsers that don't natively support it. This would mean a library would detect if window.localStorage exists and use it if it does. If it doesn't exist, then it would create some sort of fallback method of local storage, by creating its own implementation in the window.localStorage namespace.

So far, I've found these solutions:

  1. Simple sessionStorage implementation.
  2. An implementation that uses cookies (not thrilled with this idea).
  3. Dojo's dojox.storage, but it is it's own thing, not really a fallback.

I understand that Flash and Silverlight can be used for local storage as well, but haven't found anything on using them as a fallback for standard HTML5 localStorage. Perhaps Google Gears has this capability too?

Please share any related libraries, resources, or code snippets that you've found! I'd be especially interested in pure javascript or jquery-based solutions, but am guessing that is unlikely.

I use PersistJS, which handles client-side storage seamlessly and transparently to your code. You use a single API and get support for the following backends:

  • flash: Flash 8 persistent storage.
  • gears: Google Gears-based persistent storage.
  • localstorage: HTML5 draft storage.
  • whatwg_db: HTML5 draft database storage.
  • globalstorage: HTML5 draft storage (old spec).
  • ie: Internet Explorer userdata behaviors.
  • cookie: Cookie-based persistent storage.

Any of those can be disabled—if, for example, you don't want to use cookies. With this library, you'll get native client-side storage support in IE 5.5+, Firefox 2.0+, Safari 3.1+, and Chrome; and plugin-assisted support if the browser has Flash or Gears. If you enable cookies, it will work in everything (but will be limited to 4 kB).

Enable JQuery In Aptana Studio 3

8 votes

Hi. How Can I Enable JQuery In Aptana Studi 3 (beta) ? i did not see any document for this version. Does Aptana Studi 3 (beta) Supporting JQuery?

In Studio 3 much of this sort of functionality is still coming as Aptana is going more of a TextMate bundle route for a great deal of their features, which I think is really cool.

That said, there is already a jQuery bundle. The jQuery bundle, if you don't have it installed yet, can be installed from Aptana via the Commands menu (Commands->Bundle Development->Install Bundle and then select jQuery from the list).

This support discussion has some details about jQuery code assist in Aptana: https://aptanastudio.tenderapp.com/discussions/problems/2006-studio-3-jquery-support-is-lacking

In particular, it mentions adding a jquery vs doc file (http://code.jquery.com/jquery-1.4.1-vsdoc.js) to your project. This seems to be the key.

If you install the jQuery bundle and add the aforementioned JS file, you can get jQuery code hints in your Aptana editor(s). I just ran through this in one of my Rails projects and it does work (I'm on the latest beta of Studio 3 for Mac).

variable === undefined vs. typeof variable === "undefined"

8 votes

The jQuery Core Style Guidelines suggest two different ways to check whether a variable is defined.

  • Global Variables: typeof variable === "undefined"
  • Local Variables: variable === undefined
  • Properties: object.prop === undefined

Why does jQuery use one approach for global variables and another for locals and properties?

For undeclared variables, typeof foo will return undefined, whereas foo === undefined would trigger a foo is not defined error.

For local variables (which you know are declared somewhere), no such error would occur, hence the identity check.

Is there a bug with using InnerHTML inside a UIWebView within a native iPhone application?

7 votes

I have a fairly large HTML/JS/CSS application that works great when running as a web application with Safari on the iPhone.

When running this same application in an UIWebView within a native iPhone application calls within jQuery to create HTML fragments fail silently (ie: $("<div>HELLO WORLD</div>"); will not create the element.

I've tracked this down to the following equivalent code snippet in clean jQuery method:

var div = document.createElement(“div”); div.innerHTML = “<div>HELLO WORLD</div>”;

When I look at div.outerHTML I see <div>/<div>

div.innerHTML returns an empty string.

This does not appear to be a jQuery problem, nor does this happen 100% of the time. I haven’t been able to find a pattern, but in some cases it works 2-3 times in a row, sometimes if fails 5-6 times consecutively. This seems to only shows up when running the application inside a UIWebView in an Objective-C application. Also I’ve only seen this on an actual device running iOS 4.2, not the emulator.

Has anyone run into anything similar? Does anyone have a fix?

I had this problems too. It happens when the CPU of the phone is very busy (say 100%). Then the rendering engine sometimes forget about innerHTML settings.

The solution included in my unify project is to test if there is an element in childNodes, otherwise apply it again.

var target = document.createElement("div");
var text = "<div>Hello World</div>";
target.innerHTML = text;
var self = this;
self.__intervalHandle = window.setInterval(function() {
  target.innerHTML = text:
  if (target.firstChild) {
    window.clearInterval(self.__intervalHandle);
    self.__intervalHandle = null;
  }
}, 100);

This forces the rendering engine to apply the innerHTML to the DOM and gives the rendering engine some time (100 ms in this example, a good value in our tests) to handle it.

Detect browser character support in javascript?

7 votes

I'm working on a music related website, and frequently use the HTML special characters for sharps (♯) and flats(♭) to keep things pretty, e.g.:

&#9839;
&#9837;

However, I've noticed that in some browsers (IE6, Safari for PC) those characters aren't supported. I've created a conditional javascript that serves up plain, supported characters in place of the special ones ( G# for G♯ and Bb for B♭ ). But I'm having a hard time figuring out how to detect which browsers lack those characters.

I know I could test for the browser (e.g. ie6), but I was hoping to do things right and test for character support itself.

Does anyone know of a good way to do this using either javascript, jQuery, or rails? (The page is served by a rails app, so the request object and any other Rails magic is on the the table.

If you create two SPANs, one containing the character you want, and the other containing an unprintable character U+FFFD (�) is a good one, then you can test whether they have the same width.

<div style="visibility:hidden">
  <span id="char-to-check">&#9839;</span>
  <span id="not-renderable">&#xfffd;</span>
</div>
<script>
  alert(document.getElementById('char-to-check').offsetWidth ===
        document.getElementById('not-renderable').offsetWidth
        ? 'not supported' : 'supported');
</script>

You should make sure that the DIV is not styled using a fixed font.

Ajax Validation Using jquery?

6 votes

I using jquery validation plugin.

In my form i need to check whether the nick name is already in use or not.

For that they are providing remote key to make ajax call. For me the ajax call is working correctly and returning true or false. But its allowing even if the returned value is false, which should not happen.

My validation code looks like,

$(function() {
    $("#myform").validate({
        rules: {
            fullName: {
                required: true,
                minlength: 5
            },
            nickName: {
                required: true,
                minlength: 4,
                alphaNumeric: true,
                remote: {
                    url: "NickNameChecker",
                    type: "post",
                    data: {
                        nickName: function() {
                        return $("#nickName").val();
                    }},
                    success: function(data) {
                        return data;
                    }
                }
            }
        },
        messages: {
            fullName: {
                required: "Please Enter Your Full Name.",
                minlength: "Full Name should have minimum 5 letters."
            },
            nickName: {
                required: true,
                minlength: "Nick Name should contain minimum 4 letters.",
                remote: "This nickname is already in use."
            }
        }
    });
});

Any suggestions would be appreciative!!!

Thanks!

Solution:

The solution is in my code only.

I just removed the success part and tried. Its working great!

(Expanded explanation from comment above):

The success option is not valid for jQuery validate's remote validation. You should be able to just specify a URL to access for validation that returns true or a falsy value/error message:

The serverside resource is called via $.ajax (XMLHttpRequest) and gets a key/value pair, corresponding to the name of the validated element and its value as a GET parameter. The response is evaluated as JSON and must be true for valid elements, and can be any false, undefined or null for invalid elements, using the default message; or a string

See the documentation for remote for more information on how to use the option. Your code would probably look something like this:

$(function() {
    $("#myform").validate({
        rules: {
            fullName: {
                required: true,
                minlength: 5
            },
            nickName: {
                required: true,
                minlength: 4,
                alphaNumeric: true,
                remote: {
                    url: "NickNameChecker",
                    type: "post",
                    data: {
                        nickName: function() {
                        return $("#nickName").val();
                    }
                }
            }
        },
        messages: {
            fullName: {
                required: "Please Enter Your Full Name.",
                minlength: "Full Name should have minimum 5 letters."
            },
            nickName: {
                required: true,
                minlength: "Nick Name should contain minimum 4 letters.",
                remote: "This nickname is already in use."
            }
        }
    });
});

Background image covering browser window minus header and footer below the fold

6 votes

Title might be a bit confusing, I'll try my best to explain what I need to achieve. Basically I have the following elements to a particular webpage:

  1. Header - always visible above content
  2. Content - background image covers the entire content area - this is the key part
  3. Sub-footer - information about the content always visible below it
  4. Footer - standard company footer, visible if window height is a certain size, otherwise need to scroll down to see it

As I mention above, the content portion of the page is maybe the trickiest part. I need a big image to be in the background that covers the entire area. css-tricks has an excellent guide in the ways to do full page background images. So I'm hoping this can be achieved easily. The issue is how to make the sub-footer stay at the bottom if the window is <720px with the footer underneath it below the fold (needing you to scroll to it). A window >720px should show both the sub-footer and the footer with no scrollbars.

I won't even worry at this point about a minimum height the content needs to be (possibly necessitating scrollbars on the content <div> or making both the sub-footer and footer go below the fold).

Here are image mockups of what I'm trying to achieve:

First - a window <720px tall where the footer needs to be scrolled to: <720px tall window where the footer needs to be scrolled to

Second - a window <720px tall that has been scrolled down to see the footer: enter image description here

Finally - a tall window >720px that has no scrollbars because everything is visible: enter image description here

I'm using jQuery and don't care about IE6. Can I achieve this in CSS? Do I have to use jQuery to dynamically adjust things? Full page backgrounds are easily done with css3, I'm happy to use css3 or html5 to do what I need.

You definitely can not use CSS position: fixed because that is always relative to the viewport, not the parent element.

What you need to do is have the "subfooter" as a fixed positioned child element of "content". In order to do that, you're going to have to use Javascript.

Something like this should do what you need. Try changing the height variable in the CSS for #content so you can see how it behaves with various content heights:

<html>
<head>
<script src="http://code.jquery.com/jquery-1.4.4.min.js"></script>
<style>
    #header {
        height: 50px;
        background-color: #ccc;
        width: 100%;
        margin-bottom: 10px;
    }

    #content {
        position: relative;
        height: 1500px;
        width: 100%;
        background-color: #ccc;
    }

    #subfooter {
        height: 50px;
        width: 100%;
        background-color: #666;
        position: fixed;
    }

    #footer {
        height: 50px;
        width: 100%;
        margin-top: 10px;
        background-color: #ccc;
    }
</style>
<script>
    $(document).ready(function(){

        $(document).scroll(function() {
            position_subfooter();
        });

        var position_subfooter = function() {
            $("#subfooter").css("bottom", "20px");
            if(($("#subfooter").offset().top - $("#subfooter").height()) > ($("#content").scrollTop() + $("#content").height())) {
                $("#subfooter").css("bottom", ($("#subfooter").offset().top - ($("#content").scrollTop() + $("#content").height()) + 20));
            }
        }
        position_subfooter();
    });
</script>
</head>
<body>
    <div id="header">
        <h1>HEADER</h1>
    </div>
    <div id="content">

    </div>
    <div id="subfooter">
        <h2>SUB FOOTER</h1>
    </div>
    <div id="footer">
        <h1>FOOTER</h1>
    </div>
</body>
</html>

User interaction sometimes screws up jQuery ajax requests in UIWebView

4 votes

I'm building an iPhone app that displays a UIWebView pointing to a web application I've created.

The web application makes frequent web service calls for data items which are used to animate controls on a canvas. The calls for data use jQuery ajax, passing parameters via JSON and receiving an XML response.

I'm finding that while user interactions with the UIWebView are occurring, the javascript setTimeout method is blocked and doesn't seem to execute at all. Fair enough; there are ways around this.

But the major problem is that every now and then after user interactions (zooming, panning etc), the ajax web service calls will just fail all the time and I can't establish a reason why. Even if they are made repeatedly, for the next few minutes none of them will even get through to the web service. If you completely leave the UIWebView alone, they will never fail as long as the web service is up and connectivity is present.

Can anyone suggest why, and how to fix/work around this?

Quick update: according to the Safari mobile debugger, the 'response' object in the error function is undefined. (It works if, for example, I make the URL invalid. This can then be called from objective-c by [webView stringByEvaluatingJavascript:@"lastError"], but throws an exception for this 'touched the uiwebview' error):

    $.ajax({
    type: "POST",
    url: "WebService.asmx/GetValues",
    async: true,
    data: "{'pageVersionIndex': " + PageVersionIndex + " , 'timeStreamIndex': '" + TimeStream + "'}",
    contentType: "application/json; charset=utf-8",
    dataType: "xml",
    success: function (response) { UpdateControls(response); },
    error: function (response, status, errorthrown) {
        calling = false;
        lastError = response.statusText; //Throws exception
        connectionInterrupted = true;
        DataRoutine = window.setTimeout(DataService, dataFrequency); }
    });

I'm afraid you are toasted... in a way. In iOS Safari and in UIWebView respectively system processes have priority over browser and if there is a sudden demand for more CPU power or memory for native processes (like handling touch etc) it might happen that any running javascript will be stopped from executing to reduce the memory load or cpu usage. The worst part is that it won't throw any errors or anything... it just stops your code execution as if nothing happened.

Afraid that if it happens a lot in your app the only way would be to add some kind of timer that would listen if the request wasn't blocked if so - do it again until successful.

Ups and downs of iOS - they really like you to go native rather then web :)

hope it helps, Tom

Is this the fastest way to parse my XML into JavaScript objects using jQuery?

4 votes

I have an XML file like this:

<content>
    <box>
        <var1>A1</var1>
        <var2>B1</var2>
        <var3>C1</var3>
        <var4>D1</var4>
    </box>
    <box>
        <var1>A2</var1>
        <var2>B2</var2>
        <var3>C2</var3>
        <var4>D2</var4>
    </box>
    <box>
        <var1>A3</var1>
        <var2>B3</var2>
        <var3>C3</var3>
        <var4>D3</var4>
    </box>
</content>

It has 500 box elements which I need to parse into JavaScript objects. I am using this code which works fine but I am a newbie and maybe I am missing something and would like to get suggestions if there is a better/faster way to do it:

var app = {
    //...
    box: [],

    init: function (file) {
        var that = this;

        $.ajax({
            type: "GET",
            url: file,
            dataType: "xml",
            success: function (xml) {
                $("box", xml).each(function (i) {
                    var e = $(this);
                    that.box[i] = new Box(i, {
                        var1: e.children("var1").text(),
                        var2: e.children("var2").text(),
                        var3: e.children("var3").text(),
                        var4: e.children("var4").text()
                    });
                });
            }
        });
    },
    //...
};

Thanks in advance.

Use JSON if at all possible. That way the browser will do the parsing for you and you won't have to do any post-processing.

JSON from the server

{"content":
  {"box": [
    {"var1": "A1",
     "var2": "B1",
     "var3": "C1",
     "var4": "D1"},
    {"var1": "A2",
     "var2": "B2",
     "var3": "C2",
     "var4": "D2"},
    {"var1": "A3",
     "var2": "B3",
     "var3": "C3",
     "var4": "D3"}]}}

Client JavaScript

var app = {
    //...
    box: [],

    init: function (file) {
        var that = this;

        $.ajax({
            type: "GET",
            url: file,
            dataType: "json",
            success: function(result) {
              that.box = $.map(result.content.box, function(box, i) {
                return new Box(i, box);
              });
            }
        });
    },
    //...
};