Best jquery questions in June 2011

IE6: Background-Image Load Event

18 votes

I am displaying a bunch of thumbnail images and the latency can be very high (over a VPN) so I send all the thumbnails in a single file (like a sprite) and set the CSS background-image and background-position properties of a div to show the thumbnails. The problem I'm having is with IE6 and figuring out when the image has loaded... I'm using the BackgroundImageCache hack:

document.execCommand("BackgroundImageCache",false,true);

To check when the image is loaded I use this code:

$('<img>').attr('src', 'ThumbSpriteTest.png').load(function() {
    $('.Thumbnails').css('background-image', 'url(ThumbSpriteTest.png)');
});

This works in every browser I've tried except IE6... even with the cache hack it is loading the image, firing the event, setting the background-image property and downloading the image again (and my .Thumbnail elements are blank while it re-downloads).

It seems to me that the cache hack is only changing the behavior of the CSS references and not the img tag. How can I tell when the background image is loaded without downloading it twice? Is it possible in IE6?

EDIT: Using: document.execCommand("BackgroundImageCache",true,true); seems to work (with both parameters as 'true'). I'm having trouble finding any documentation on the BackgroundImageCache command and it's parameters (I've found plenty of examples of using it to fix the CSS problem, but they all use false,true as parameters and don't explain them)... the bounty is still good for anyone with good information/documentation on the BackgroundImageCache command and it's parameters!

(I'm not sure why I'm excited to find something that works after wasting so many hours due to IE's shortcoming)

This is definitely poorly documented, as it is considered a hotfix for ie6, and will stay that way, seeing this is already fixed in ie8. Anyway, here is what is dug up bout it.

execCommand method: http://msdn.microsoft.com/en-us/library/ms536419(v=vs.85).aspx

 bSuccess = object.execCommand(sCommand [, bUserInterface] [, vValue]);
 //sCommand is the name of command to execute
 //[bUse...] is to give permission to display a dialog window (if applicable)
 //[vValue] value to pass as parameter to the command

[bUserInterface]: is just a Boolean indicator for a dialog box, that is not used by all the possible command. But is used for example to save files / create link / etc... Eg: http://man.ddvip.com/web/dhtml/constants/createlink.html

So you may want to check if this value works when set to false, it should work in theory... But hotfixes can break for funny reasons.

About the hotfix: http://support.microsoft.com/kb/823727

Anyway, this feature only appear as a patch to IE6. So dun assume it will work for all ie6 browser. While it was introduced to prevent multiple loading + leakages, and not "caching" the way you are using it, it still does what the name suggests (hopefully). So dun be surprised it hiccups on the way on unpatched versions (auto update should fix this though)

With that warning, please catch the execution for the success or fail Boolean values, if you have features dependent on it. And I guess make the best with what you have (to be sad enough to be forced to support ie6)

How does the bre.ad (http://bre.ad) background work?

14 votes

Bre.ad has this background where it keeps moving and there is an illusion of a baker's truck moving on the road. I was wondering how that was done and can it be done so that the image is moving vertically instead of horizontally?

The entire background is this long png file, and the city scapes and clouds are transparent background pngs that are layered over it in multiple divs.

Background (Town):

Background

CityScape:

Cityscape

The relevant HTML from the page source:

<div id="bread-world">
    <div id="puffyclouds" style="background-position: 0 -75px"></div>
    <div id="cityscape" style="background-position: 0 105px;"></div>
    <div id="ocean"></div>
    <div id="town" style="background-position: 0 0;"></div>
    <div id="truck"></div>
</div>

and the relevant CSS from all.css

#town{
    background:url('//bread-images.s3.amazonaws.com/invite/town.png?1308363721') 
    repeat-x 542px 0px;
    width:5806px;
    left:0;
    bottom:0;
    height:599px;
    position:absolute
    }

and similarly for the other divs. The repeat-x property is used to repeat the background so as to mimic the effect of continuous scrolling. Also, the left end of the image and the right end line up, so as to give a smooth transition.

The animation is done by homepage.js which slowly shifts the background-position linearly. The relevant lines are:

function r(){
    m.css({backgroundPosition:"0 -75px"}).animate({backgroundPosition:q+"px -75px"},{duration:n,easing:"linear"}),
    k.css({backgroundPosition:"0 0"}).animate({backgroundPosition:o+"px 0"},{duration:n,easing:"linear"}),
    l.css({backgroundPosition:"0 105px"}).animate({backgroundPosition:p+"px 105px"},{duration:n,easing:"linear",complete:r})
}

How to know the reason of blur?

12 votes

How can I know which event caused a blur event in jQuery?

Blur event triggered using click or tab etc. How can I know this blur event is due to click or tab?

If you are trying to do two different things depending on which method was used, bind handlers to listen for .click() and .keyup(), then check for the keycode

var k = (window.event) ? event.keyCode : e.keyCode;

Or something on the order of this if you need

$(document).bind("click keyup", function(){
   //check keycode
   var e = (window.event);
   var k = (e)?event.keyCode:e.keyCode;
   if(k==9){
      //tab code
   }else if(e.type=='click'){
      //click code
   }

});

problem in file upload

11 votes

I have the following markup:

  <select multiple="multiple" id="targetFilesList"  style="width:200px;height:110px;">
   </select>
   <input type="button" value="Get" id="btnGet" />

and following javascript:

    $(function()
    {
        $('#btnGet').click(function()
        {
            var fileupload = $("<input type='file' name='filetoupload' style='visibility:hidden;'/>");
            $('body').append(fileupload);

            fileupload[0].onchange = function()
            {
                $('#targetFilesList').append('<option >' + fileupload.val() + '</option>');
                return false;
            }
            fileupload.click();
        });
    });

Scenario is that i have to upload multiple files and once user has chosen the file to be uploaded i have to show the file name to user.Then,on submitting the form i will upload all the files.For this,on clicking the get button i am adding a fileupload control dynamically and initialise onchange event of the fileupload control just added. The problem in chrome 12 on clicking get button fileupload control does not get opened but in firefox4 and ie8 it is working. Any idea why?

To get it working on Chrome 12, you can just add it into a window timeout of 0, like this:

window.setTimeout(function(){
   fileupload.click();   
},0);

Why exactly it behaves like this, I am not sure. The first time I encountered the problem I tried it with a longer interval, reducing it all the time to see how low you could get it, until I noticed it doesn't even need a delay. The obvious answer would be that it isn't actually ready in DOM by the time you trigger the click (element is there, but is the appropriate events for it?).

example: http://jsfiddle.net/HgEga/

jQuery .change() event is triggered with .click() in newer versions?

11 votes

I'm currently upgrading my application to use jQuery 1.6.1 (previously using 1.4.4) and found that now the .click() event automatically triggers a .change() event as well.

I created a simple example here: http://jsfiddle.net/wDKPN/

Notice if you include 1.4.4 the .change() function will not fire when the .click() event is triggered. But when switching to 1.6, the .change() event is fired when .click() is triggered.

Two questions:

  1. Is this a bug? It seems that programmatically triggering .click() shouldn't also fire other events (for example, it would seem wrong to also automatically fire .blur() and .focus(), to help "mimic" a user's click).

  2. What is the proper way for me to bind a change() event and then trigger both a click() and change() event for that element? Do I simply call .click(), and rely on the fact that .change() will also fire?

    $('#myelement').change(function() {
         // do some stuff
    });
    
    $('#myelement').click(); // both click and change will fire, yay!
    

In my old code I'm using this pattern to initialize some checkboxes (and their checked states and values) after an ajax call:

    $('#myelement').change(function() {
         // do some stuff including ajax work
    }).click().change();

But in 1.6.1 my logic fires twice (once for .click() and once for .change()). Can I rely on just removing the .change() trigger and hope that jQuery continues to behave this way in future versions?

Thanks for any feedback!

Best way to do this is:

$('#myelement').bind('initCheckboxes change', function() {
     // do some stuff including ajax work
}).trigger('initCheckboxes');

To do your initialization stuff you just bind to it a custom event, which you trigger it the first time the page loads. This, no one will take away from you on any versions.

Whereas change event, I believe, will continue to be there on all versions, because it has been for so long, and it just works nicely that way.

In the end, this is a happy ending story, because the custom event initCheckboxes will fire just once on page load and change event will always listen and fire on change state.

Reason for .get() without index in jQuery API?

10 votes

Let's say that I've got a page which extracts some image sources like so:

<div id="d">
  <img src="foo.gif"/>
  <img src="bar.gif"/>
  <img src="gah.gif"/>
</div>
<script type="text/javascript">
  var srcs = $('div#d > img').map(function(){return this.src});
  // srcs => ['foo.gif', 'bar.gif', 'gah.gif']
</script>

Note that srcs is not a JavaScript Array but an array-like object; we know this because of the fact that we can make jQuery API calls on objects returned by the selector and the fact that srcs.constructor != Array.

The jQuery API provides a .get() method which, when given no argument, returns a "standard" Array. Is there a compelling reason to use a standard Array instead of an array-like object or is this method just included for completeness?

[Edit]

To put it another way - what are the differences between a JavaScript Array and the array-like object returned by a jQuery selector?

It allows you to use standard array methods which jQuery doesn't have, such as push.

In particular, jQuery objects are intended to be immutable, whereas arrays are not.

Chrome AJAX on page-load causes "busy cursor" to remain

10 votes

In Google Chrome, AJAX called within $(function(){....}); seems to keep the page loading.

I have a site with a few pages with tabs. Because I'm using cheap godaddy hosting, I want the page to load as fast as possible. I thus want to load a page on 1 tab and then in the background use AJAX to load the other tabs. When I run AJAX from

$(function(){
    /*AJAX CODE HERE */
});

The cursor shows the page as loading for a long time (http://jsfiddle.net/mazlix/7fDYE/9/)

I have figured out a way (in chrome atleast) to somewhat fix that using setTimeout(); (http://jsfiddle.net/mazlix/7fDYE/8/), but this only works if you correctly predict when the window finishes fully loading and obviously makes it take longer to load. I want a way to load content via AJAX immediately after the page loads, so no "busy-cursor" is displayed while waiting for the returned AJAX.

Google Chrome shows Loading Indicator as long as there are no new queries to servers. While the loading indicator is shown, all new requests are causing Chrome to extend the time the indicator is shown. Furthermore, when esc is pressed while the indicator is shown, all requests are aborted! These include AJAX requests and even Flash requests! Take a look at this question: i thought it was because of Youtube, but it turned to be Chrome's usual behavior.

The only way to avoid "extending" the time Loading indicator is shown, is making the requests after the loading indicator is hidden: i.e. when all queries to server are completed. JQuery's documentation on .load() says:

The load event is sent to an element when it and all sub-elements have been completely loaded. This event can be sent to any element associated with a URL: images, scripts, frames, iframes, and the window object.

So, if you're sure that there are only images, scripts and frames on your page, window.load() will be fired just when you need it. Adding setTimeout() to it will work as you like. Here is an example: http://jsfiddle.net/7fDYE/22/

If there are other requests being made before your request, you should wait for them to be completed! For example, you know that besides the images/scripts etc. you have 3 more AJAX requests before the page loads. You can have something like this:

var loaded=0,needsToBeLoaded=4; //3 AJAX + window
function onLoad(){
    loaded++;
    if(loaded==needsToBeLoaded){
         //do the AJAX request   
    }
}
window.load(onLoad);
// add onLoad() to all 3 AJAX request handlers

I'm not sure what you can do with Flash requests...

Observing Display Changes in jQuery

10 votes

Is it possible to add an observer to a DOM element that is triggered on changes to the visibility (i.e. calls to show() and hide())? Thanks!

If you want to observe any call to .show() or .hide() and have access to jQuery 1.5+ you could use jQuery.sub() to create a copy of the jQuery object to override the default .show() or .hide() actions.

var myjQuery = jQuery.sub();
myjQuery.fn.hide = function() {
    alert('hide');

    return jQuery.fn.hide.apply(this, arguments);
};
myjQuery.fn.show = function() {
    alert('show');
    return jQuery.fn.show.apply(this, arguments);
};

And then using the .sub() copy

(function($) {
    $(document).ready(function() {
        $(".click").click(function() {
            if ($("#hide").is(":visible")) {
                $("#hide").hide();
            }
            else {
                $("#hide").show();
            }
        });
    });
})(myjQuery);

Example on jsfiddle

jquery validation against dynamic fields

10 votes

I'm using jQuery's validation plugin and looking to validate many dynamically added text fields such that their summation is checked against a separate total field.

I've written my own validation methods in the past, but only simple ones that take on the basic regex structure that is easy to reproduce from the additional-methods.js file.

Specifically, the jQuery website gives a simple example of using the addMethod() function to do something quite similar:

jQuery.validator.addMethod("math", function(value, element, params) { 
 return this.optional(element) || value == params[0] + params[1]; 
}, jQuery.format("Please enter the correct value for {0} + {1}"));

The implementation of the params parameter is more-or-less poorly documented. I was able to find how to pass content into params in a seperate stackoverflow thread. However, the array passed into params in that example is static. The array I need to pass to params grows and shrinks based on dynamically added rows added at 'runtime'...

I've uploaded a completely stripped down version onto jsfiddle for your viewing. Note that the code has some comments embedded where I have questions, and also, I removed the Remove functionality, as it only adds clutter and doesn't help illustrate the point.

So how can I use the jQuery validation library to ensure that dynamically added fields add to a specific total? Thank you in advance!

Here is my version of your validator.

http://jsfiddle.net/linkabi9/shBxv/

You'll notice that instead of static numbers for parameters, I pass a selector. The one element in the array is a selector for the deposit fields. I gave every existing and new deposit input a class, "setamount1", you can use any class you want. The field you set this validator to will be the "Total Amount" field.

I also added a live "change" event to the deposit fields. This will run the validation on every change. I have to warn you, this runs validation on the whole form not just the deposit & total fields.

Now you can reuse this validator type multiple times in the same form/page!

I went ahead and put the validator code below. Plus, an example of the validator initialization.

jQuery.validator.addMethod("depositsSum", function(value, element, params)
{       
    var amnts = 0;
    $(params[0]).each(function() {
        amnts += parseFloat($(this).val());
    });

    return this.optional(element) || amnts == parseFloat(value);
}, jQuery.format("Individual deposits must add up to the total!"));

$("#depositForm").validate({
    rules: {
        fullAmount: {
            depositsSum: [".amountset1"]
        }
    }
});

jQuery .each() this and element

9 votes

Inside a .each() callback, is there any difference between this and the second argument of the callback function?

For example, in the following code:

$("example").each( function(index, element) {
    // body
});

is there any difference between this and element? Is the second argument just provided so you can choose a name?

Nope, there's no difference; the second argument is just for convenience.

Each time the callback runs, it is passed the current loop iteration, beginning from 0. More importantly, the callback is fired in the context of the current DOM element, so the keyword this refers to the element.

from http://api.jquery.com/each/

Most likely, the second argument is provided for consistency with jQuery.each.

Browser "Back" Button vs. jQuery-animated page

8 votes

I have a challenging problem I've been battling for some time now.

The Problem: when I go back to previous page using browser's back button, the page is displayed in its final state after all the animations had played. I want it to display in its initial state and replay the animations.

My site uses some basic jQuery animation. The initial state of each page has the main content hidden below the lower edge of the browser window, When the window loads, the main content animates up to appear in the browser. When a visitor clicks any menu link, the main content rolls up again and disappears above the upper edge of the browser window - and then the new page loads. The whole thing is achieved with these two bits of code:

//Animate the content up from below the browser window

$('#maincontent').animate({top: "15%"}, 2000);

and

//Animate the content up to hide above the browser window

$('#menu a').click(function(event) {
    event.preventDefault();
    var href = this.href;
    $('#maincontent').animate({
        top: '-300%'
    }, 500,
    function() {
        window.location = href;
    });
});

The Question: how do I make the page display in its initial state when the browser back button is clicked?

I browsed StackOverflow for some time. People asked about this issue a lot but no one seem to have arrived to a solution that really worked. Suggestions include blocking the page from being cached – (doesn't work, and even if it worked, wouldn't be very productive because some pages do need to be cached) – reloading the page (leads to some peculiar behaviors and ultimately doesn't work, either) - using cookies (no specific example of code is given anywhere) or using php (no specific example of code is given anywhere). I asked several questions about in on this site and received a number of suggestions but none of them worked in my situation. So after a couple of sleepless nights I want to ask if someone can really help with this.

If someone had dealt with that probelm before successfully, I would be grateful if you could share your expert knowledge and suggest a workable solution!

NEW EDIT: I think I may have found a solution, but I want someone's help with jQuery/JavaScript syntax. I want to try to modify the code to add one more action to it, but I'm not sure how to write it, so that the page reloads a moment before the location is changed to the new page So instead of the second snippet shown above, I want to write something like this:

//Animate the content up to hide above the browser window

$('#menu a').click(function(event) {
    event.preventDefault();
    var href = this.href;
    $('#maincontent').animate({
        top: '-300%'
    }, 500,
    function() {
    // a code that reloads the same page, something like
    //window.location = window.location; followed by
        window.location = href;
    });
});

-- but I just don't know how to write it correctly.

Alternatively, perhaps it's possible to reset the css values of the page to the the default ones from the css file and trigger JavaScript again?

Could someone advice the proper code please?

Disclaimer: The following isn't exactly a robust solution, but I found it amusing and thought I ought to share.

I had a similar requirement in the past, and strangely enough, the solution I ended up with was to downgrade to jQuery to take advantage of a bug in jQuery 1.3.

I only tested this on one version of Firefox, so YMMV, but try the following:

This was sufficient for my use-case since I was targeting a limited audience and only made minimal use of jQuery. That said, I'm eagerly watching this thread in a hope of finding a better solution.

Update

Following the trail of the above stated jquery bug, it looks like you can get the same effect by disabling the bfcache.

The simplest way to do would be to add an onunload attribute to body. (more details in link).

<body onunload=''>

Here's an example, which uses jquery 1.6. Again, not thoroughly tested so YMMV.

How can I tell when a CSS background image has loaded? Is an event fired?

8 votes

I have a sidebar widget that has an image background.

Over this is a search input form. I don't want the input to show before the image has loaded.

Is there a way to attach an load event handler to CSS background images like normal img elements/objects?

I know this could be done on a normal image, but I'd like to keep it as a CSS background because the image is part of a sprite. I am using jQuery, so solutions using jQuery or plain DOM JS are equally good.

You could load the same image using the DOM / a hidden image and bind to the load event on that. The browser's caching should take care of not loading the image twice, and if the image is already loaded the event should fire immediately... not tested, tough.

Using jQuery's .add method

8 votes

Either I am making a very silly mistake here, or there is a bug with jQuery's .add method. Most likely the former.

I am trying to implement a list of items that could be selected. Here's my code on jsfiddle.

The test case that is failing is the following:

  1. Click the first element to select it.
  2. Ctrl-click the second element to select it too.
  3. Then click the third element (without Ctrl).

Now, I'd expect the first and second to be de-selected, I believe the implementation also does this. But the second one does not get de-selected.

Digging a little, it seems that the .add is actually not adding my elements to the jQuery object set and for the life of me, I can't figure out why.

Any suggestions on this? Or is this not the way the .add method is supposed to be used?

Edit: I know jquery-ui has a control for this kind of thing, but I have already evaluated it and it does not work for me. Thanks.

.add returns a new jQuery object, so you need to grab the value returned.

prevSelections = prevSelections.add(...);

Here's some other cleanup applied:

var ps = $(),
    clazz = 'selected';
$('#list').delegate('li', 'click', function(e) {
    if (e.ctrlKey) {
        ps = ps.add($(this).toggleClass(clazz));
    } else {
        if (ps.length) {
            ps.removeClass(clazz);
        }
        ps = $(this).addClass(clazz);
    }
});

Demo: http://jsfiddle.net/mattball/mAPQA/

jquery selector suggestor

8 votes

We all know that there are many different selector combinations one can use to create a unique wrapped set of jQuery elements.

Does a tool (plugin, extension, etc) exist that allows the user to visually click on any section of the DOM (similar to Firebug's inspect feature) and auto-suggests relevant potential selectors that match that element?

The tool would have internal knowledge of jQuery selectors (CSS selectors fall short) and would take into account the surrounding elements + the DOM to provide 10-20 helpful selector suggestions.

Here is a start point to play around with what you need (i hope) or just to understand:

JSFIDDLE DEMO

$("body").click(function(event) { // if you are not interested on 'body' himself use: $("body>*")

    // QUESTIONS:
    var Q_qwer = 'Not a parent';
    var Q_children = 'Not a children';
    var Q_last = 'Not last';
    var Q_first = 'Not first';

    //#

    if ($(event.target).children().size() > 0) {
        myChildren = $(event.target).children();
        var Q_parent = myChildren[0].nodeName + ' (ID: ' + myChildren[0].id + ' || CLASS: ' + myChildren[0].className + ' )';
    }
    if ($(event.target).parent().size() > 0) {
        myParent = $(event.target).parent();
        var Q_children = myParent[0].nodeName + ' (ID: ' + myParent[0].id + ' || CLASS: ' + myParent[0].className + ' )';     
    }
    if ($(event.target).is(':last-child')) {
        Q_last = 'LAST!' ;      
    }
    if ($(event.target).is(':first-child')) { // or use: $(event.target).index() == 0
        Q_first = 'FIRST!' ;     
    }

    $("#log").html(' event.target: ' + event.target +
                   ' <br> nodeName: ' + event.target.nodeName +
                   ' , Tag: ' + event.target.tagName +
                   ' <br> ID: ' + event.target.id +
                   ' <br> Class: ' + event.target.className +
                   ' <br> Href: ' + event.target.href +
                   ' <br> Value: ' + event.target.value +
                   ' <br> Children of: ' + Q_children +
                   ' <br> Parent of: ' + Q_parent + ' (First children)' +
                   ' <br> Last children?: ' + Q_last +
                   ' <br> First children?: ' + Q_first +
                   ' <br> .index( ' + $(event.target).index() + ')' +
                   ' <br> .eq( ' + $(event.target).prevAll().length + ')' +
                   ' <br> <hr>' + $(event.target).html()

                  );
});

Hope this helps!

AJAX and jQuery with MVC

8 votes

How do you organise your controllers, methods, views when you use a MVC model with jQuery with lots of AJAX bits?

Question 1

Do you have a seperate controller just for AJAX calls, or do you mix the AJAX methods together with your usual non-AJAX methods in one single controller?

Question 2

If you were to mix AJAX and non-AJAX methods in a single controller, do you have seperate AJAX and non-AJAX methods, or do you combine them together (if possible) and pass in a value (NULL or AJAX) which determines whether a normal view or a AJAX view is passed back to the browser.

Question 3

If you have 50 different AJAX calls, and each call requires a method, which in turn requires a view, we end up with a controller with 50 methods and 50 views. Is this good MVC practice? I can think of all AJAX methods in the controller sharing a single view, where the view file contains case conditional statements and the view file is passed a parameter which determines which of the 50 cases will be used. Kind of like compressing 50 views into 1.

Question 4

Instead of having so many views (50 views), what do you think of echoing the output in in the controller method rather than in the view? This way we won't have so many views.

BTW, I'm using CodeIgniter PHP framework for my MVC model

Question 1

I mix the ajax and non-ajax code in to the same controller. That way your code is in a common place easy to find.

Question 2

I combine ajax and non-ajax method together. Makes it easier to use javascript Progressive Enhancement so that people without javascript will still post to the same controller

Question 3

You should not have 1 controller with 50 methods. You should have a controller per piece of functionality. So a User Controller, a Foo controller, a Bar controller - so you may end up with 10 contollers with 5 methods each. This way methods belong in classes specific to their function. I have seperate views and not one big view. You should NOT use LOGIC inside views to determine what is shown, this is the job of the controller. But some controller/methods can return the same view as other methods

Question 4

Or controller should NEVER output HTML. Use views for this that is the whole pupose of MVC to seperate out Code (controllers from) Views (rendering) concerns. Some times my views just return JSON or XML and then I use Javascript templates to update the DOM. Othertimes my views return HTML. For example a Save function on a form. Might just return a Boolean if sucessful. Then my Javascript would hide or show a DIV depending on the response.

Select numbers on a page with jQuery or Javascript

8 votes

I'm just wondering if there's a way to locate numbers on a page with jQuery or plain Javascript.

Here's what I want to do:

Say "June 23" is on the page. What I want to do is be able to prepend and append some <span> selectors to the number.

Using :contains() with jQuery selects the whole thing, not just the number.

These strings are being generated without any wrapping elements by a Wordpress theme I'm working on, and I only want to select the number.

Any help would be appreciated! Thanks for even thinking about it.
-George

You can walk through all the elements, looking at text nodes, and replacing them with updated content that has the number wrapped.

var regex = /(\d+)/,
    replacement = '<span>$1</span>';

function replaceText(el) {
    if (el.nodeType === 3) {
        if (regex.test(el.data)) {
            var temp_div = document.createElement('div');
            temp_div.innerHTML = el.data.replace(regex, replacement);
            var nodes = temp_div.childNodes;
            while (nodes[0]) {
                el.parentNode.insertBefore(nodes[0],el);
            }
            el.parentNode.removeChild(el);
        }
    } else if (el.nodeType === 1) {
        for (var i = 0; i < el.childNodes.length; i++) {
            replaceText(el.childNodes[i]);
        }
    }
}

replaceText(document.body);

Example: http://jsfiddle.net/JVsM4/

This doesn't do any damage to existing elements, and their associated jQuery data.


EDIT: You could shorten it a bit with a little jQuery:

var regex = /(\d+)/g,
    replacement = '<span>$1</span>';

function replaceText(i,el) {
    if (el.nodeType === 3) {
        if (regex.test(el.data)) {
            $(el).replaceWith(el.data.replace(regex, replacement));
        }
    } else {
        $(el).contents().each( replaceText );
    }
}

$('body').each( replaceText );

Example: http://jsfiddle.net/JVsM4/1/

Note that the regex requires the g global modifier.

Probably a little slower this way, so if the DOM is quite large, I'd use the non-jQuery version.

jQuery - Change css for all divs of a class except 'this'

7 votes

I need it so when I click on a div of class 'mydiv', all divs of that class have a z-index of 1, except for the div I clicked on which as a z-index of 2.

Clicking on the div again needs to change its z-index back to 1.

So far ive come up with the following:

    $('.mydiv').toggle(function() {
        $('.mydiv').css('z-index','1');
        $(this).css('z-index','2');
    }, function() {
        $(this).css('z-index','1');
    });

If you click on a div and then click on it again (returning the z-index to 1) before clicking on another one it works fine.

However if you click on a div, and then click another one without clicking the first one (to toggle it back to z-index 1), sometimes it works and sometimes it doesn't do anything. Im assuming the problem is in the first part of my code because this:

$('.mydiv').css('z-index','1');

Is not always run before this:

$(this).css('z-index','2');

Is that the problem and if so how can I fix this? Thanks

UPDATE - Sorry for not thinking of this initially, but ive simplified my question here, the actual page will need to have css positioning animations. So when you click on a div it moves with a smooth animation. I think that means I cant just change the css by toggling a class. Thanks

-

UPDATE 2 - I thought I had this working, and then I tested in IE8 and 7. IE9 is ok (along with every other browser I tested with) but IE7 and IE8 make all of the images jump around when you click on any of them. Here is the demo (all css and jQuery are within the page):

http://smartpeopletalkfast.co.uk/jquery/basicDemo12-bugfix-3.htm

And here is the jQuery:

    $(".image-div").click(function () {


        var divRefTwo = $(".image-div").not(this);
        $(".image-div").not(this).animate({
                width: '250px',
                left: '0px',
                marginRight: '0px',
                backgroundPosition: '-125px'
            }, 400, function() {
                $(divRefTwo).css('z-index','1');
            });

        if ($(this).css('z-index') == 1) {
            $(this).css('z-index','2');
            $(this).animate({
                width: '500px',
                left: '-125px',
                marginRight: '-250px',
                backgroundPosition: '0px'
            }, 500, function() {
                //
            });
        }
        else {
            var divRef = this;
            $(this).animate({
                width: '250px',
                left: '0px',
                marginRight: '0px',
                backgroundPosition: '-125px'
            }, 500, function() {
                $(divRef).css('z-index','1');
            });
        }

    });

I think whats happening is this: The background image position for div.image-div starts at -125px. When you click a div.image-div, jQuery animates the background position for all the other divs of the the same class to -125px. Only divs that are expanded should change, as the other divs already have background position of -125px.

For some reason IE resets the background position to 0, and then animates to -125px. So the animation ends up in the correct place, but animates to get their when it shouldn't.

Any ideas why this is happening? Is this a jQuery IE bug or a CSS hierarchy of selectors thing? Thanks

So now we changed everything again. Based on the OP edit, now the code would be:

$(".mydiv").click(function () {
    var $t = $(this);
    $t.siblings().css("z-index", 1).animate({
            "margin-top": 0
        }, "fast");
    if ($t.css("z-index") == 1)
        $t.css("z-index", 2).animate({
            "margin-top": -10
        });
    else
        $t.css("z-index", 1).animate({
            "margin-top": 0
        }, "fast");
});

Here is the again updated working sample.

Now let me explain the logic of the code.

// Since we'll use $(this) (the clicked div) in many places
// of the code, I started caching it in a var named $t.
var $t = $(this);

// Then I get all the siblings (The other divs that are beside this,
// or are children of the same parent). The I change back all this divs to
// z-index = 1 and animate their top down to 0.
$t.siblings().css("z-index", 1).animate({ "margin-top": 0 }, "fast");

// Next we have the if statement to check if the clicked div is with
// z-index = 1 (unclicked) or z-index = 2 (already clicked).
if ($t.css("z-index") == 1)

// Then we change the current div to z-index = 2 and animate it 10px upper.
$t.css("z-index", 2).animate({ "margin-top": -10 });

// Or else we change back the current div to z-index = 1 and animate it down.
$t.css("z-index", 1).animate({ "margin-top": 0 });

Possible collision of two ajax requests?!

7 votes

I'm having trouble with one of my sites on which two ajax requests are executed when the page loads. I'm using jQuery in combination with an PHP application based on the zend framework.

The relevant HTML (simplified) looks like:

<select id="first">
     <option value="1">First Option</option>
     <option value="2">Second Option</option>
</select>
<div class="first_block"></div>

<select id="second">
     <option value="1">First Option</option>
     <option value="2">Second Option</option>
</select>
<div class="second_block"></div>

Here is what my jQuery looks like:

$(document).ready(function(){

// function to update the first block
var updateFirstBlock = function(){
    var param = $(this).val();
    $.ajax('module/controller/action/param/' + param, {
        'success': function(data){
            $('.first_block').html(data);
        }
    });
};

// bind and trigger the first update function
$('select#first').bind('change', updateFirstBlock );
$('select#first').trigger('change');


// function to update the second block
var updateSecondBlock = function(){
    var param= $(this).val();
    $.ajax('module/controller/another-action/param/' + param, {
        'success': function(data){
            $('.second_block').html(data);
        }
    });
};

// bind and trigger the second update function
$('select#second').bind('change', updateSecondBlock );
$('select#second').trigger('change');

});

The PHP Application just returns some content dependent on which value is distributed.

Now what happens when the pages is loaded, is that in nine of ten cases one of the two requests gets no answer. The other one gets 200 OK and the failing one times out. There's no regularity, which request fails.

Is it possible that there's something wrong in the web-servers (Apache 2.2) configuration, so that two simultaneously fired requests constrain each other?

EDIT

If I set both requests to async: false, they are always executed properly. So there must be a collision, I think.

EDIT 2

A possible reason for this behavior, could be php's session lock. I will examine this further.

It seems your definitely on the right rack with the PHP session lock:

Session locking (concurrency) notes

The default PHP session model locks a session until the page has finished loading. So if you have two or three frames that load, and each one uses sessions, they will load one at a time. This is so that only one PHP execution context has write access to the session at any one time.

Some people work around this by calling session_write_close() as soon as they've finished writing any data to the $_SESSION - they can continue to read data even after they've called it. The disadvantage to session_write_close() is that your code still will lock on that first call to session_start() on any session'ed page, and that you have to sprinkle session_write_close() everywhere you use sessions, as soon as you can. This is still a very good method, but if your Session access follows some particular patterns, you may have another way which requires less modification of your code.

The idea is that if your session code mostly reads from sessions, and rarely writes to them, then you can allow concurrent access. To prevent completely corrupted session data, we will lock the session's backing store (tmp files usually) while we write to them. This means the session is only locked for the brief instant that we are writing to the backing store. However, this means that if you have two pages loading simultaneously, and both modify the session, the Last One Wins. Whichever one loads first will get its data overwritten by the one that loads second. If this is okay with you, you may continue - otherwise, use the session_write_close method, above.

If you have complicated bits of code that depend on some state in the session, and some state in a database or text file, or something else - again, you may not want to use this method. When you have two simultaneous pages running, you might find that one page runs halfway through, modifying your text file, then the second one runs all the way through, further modifying your text file, then the first one finishes - and your data might be mangled, or completely lost.

So if you're prepared to debug potentially very, very nasty race conditions, and your access patterns for your sessions is read-mostly and write-rarely (and not write-dearly), then you can try the following system.

Copy the example from session_set_save_handler() into your include file, above where you start your sessions. Modify the session write() method:

function write($id, $sess_data)
{
  global $sess_save_path, $sess_session_name;

  $sess_file = "$sess_save_path/sess_$id";
  if ($fp = @fopen($sess_file, "w")) {
   flock($fp,LOCK_EX);
   $results=fwrite($fp, $sess_data);
   flock($fp,LOCK_UN);
   return($results);
  } else {
   return(false);
  }

}

You will probably also want to add a GC (Garbage Collection) method for the sessions, as well.

And of course, take this advice with a grain of salt - We currently have it running on our testing server, and it seems to work OK there, but people have reported terrible problems with the Shared Memory session handler, and this method may be as unsafe as that.

You can also consider implementing your own locks for scary concurrency-sensitive bits of your code.

Ref: http://ch2.php.net/manual/en/ref.session.php#64525


It might be worthwhile implementing a database session handler. Using a database eliminates this problem and can actually improve performance slightly, if a good database structure is used.

How to avoid unnecessary buffering in jPlayer

6 votes

I have a jPlayer (HTML5 song player using jquery) and it starts to play a song from xx secs of a song.

But the problem is it has to first buffer the XX secs and then starts to play which is waste of bandwidth. Why doesnt it start its buffering from XX secs itself?

Here is the code i use:

$("#jquery_jplayer_1").jPlayer({
        ready: function () {
          $(this).jPlayer("setMedia", {
            mp3: playList[0],
            volume: CUR_VOL
          }).jPlayer("play", 251);
        },
        swfPath: "js",
        supplied: "mp3",
        errorAlerts: false
      });

EDIT

I wanted an answer for avoiding the buffering of first XX seconds.

It's the flash polyfill that needs to buffer. Older browsers that do not support HTML5 <audio> will suffer from this problem, where the jPlayer flash fallback used instead.

Your web server must support seeking a stream.

See this jPlayer Google Group question about buffering and Seeking through a streamed MP3 file with HTML5 <audio> tag & https://groups.google.com/forum/#!topic/jplayer/irSrmN0aUSU for a discussion on seeking and Accept-Ranges headers.

Edit: I've done some digging into this problem… although I'm sorry that I still do not have a final answer.

Firstly, the jPlayer Development Guide details the issues with .mp3 files and the Accept-Ranges header. If you use Chrome you can actually see the Accept-Ranges request and response header - if you press F12 and select the Network tab. Clicking on the .mp3 file, you can inspect the headers. The good news is that is does look like your server does support the Accept-Ranges header. However, it still does not explain why sometimes it needs to buffer the download first.

I think you should start with a simple demo, with no flash support and a single .mp3. Your playlist is randomly generated so it is difficult to determine if the problem is only for certain files. Also, I have used the jPlayer Inspector which can give detailed statistics for jPlayer which may help to diagnose the problem.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
    <title>Test</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js" type="text/javascript"></script>
    <script src="jQuery.jPlayer.2.0.0/jquery.jplayer.min.js" type="text/javascript"></script>
    <script src="jQuery.jPlayer.2.0.0/jquery.jplayer.inspector.js" type="text/javascript"></script>
    <script type="text/javascript">
        $(function(){
            $('#jplayer').jPlayer({
                ready: function () {
                    $(this).jPlayer('setMedia', {
                        mp3: 'mp3/example.mp3'
                    });
                },
                swfPath: 'not_a_valid_directory',
                solution: 'html, flash',
                supplied: 'mp3'
            });

            $('#jplayer_inspector').jPlayerInspector({jPlayer:$('#jplayer')});

            $('#seeker').click(function() {
                $('#jplayer').jPlayer('play', 20);
                return false;
            });
        });
    </script>
</head>
<body>
<div id="jplayer"></div>
<a href="#" id="seeker">Play 20s from start</a>
<div id="jplayer_inspector"></div>
</body>
</html>

You could also change the demo code above to include:

swfPath: 'jQuery.jPlayer.2.0.0',
solution: 'flash, html',

in the jPlayer constructor to force Flash to be the default player.

Map entity to JSON using JavaScriptSerializer

6 votes

My entities are like this:

class Address
{
     public string Number { get; set; }
     public string Street { get; set; }
     public string City { get; set; }
     public string Country { get; set; }
}

class Person
{
     public string Name { get; set; }
     public int Age { get; set; }
     public Address PostalAddress { get; set; }
}

Person newPerson = 
    new Person()
    {
       Name = "Kushan",
       Age = 25,
       PostalAddress = 
           new Address()
           {
               Number = "No 25",
               Street = "Main Street",
               City = "Matale",
               Country = "Sri Lanka"
           }
    };

Now I wanna map this newPerson object into JSON object like this,

{ 
     "PER_NAME" : "Kushan",
     "PER_AGE" : "25",
     "PER_ADDRESS" : {
                          "ADD_NUMBER" : "No 25",
                          "ADD_STREET" : "Main Street",
                          "ADD_CITY" : "Matale",
                          "ADD_COUNTRY" : "Sri Lanka"
                     }
}

Note: Above is just an example.

What I need is, I need to customize the Key at the serializing time. by default it is taking property name as the key. I can't change property names. How to do this?

Also, is it possible to change to order of appearing key-value pairs in JSON obj.?

You need to add DataContract attributes to your classes and DataMember to the properties. Set Name property of DataMemeber attribute to your custom property name and Order property to define the order.

[DataContract]
public class Person
{
    [DataMember(Name = "PER_NAME", Order = 1)]
    public string Name { get; set; }

    [DataMember(Name = "PER_AGE", Order = 2)]
    public int Age { get; set; }

    [DataMember(Name = "PER_ADDRESS", Order = 3)]
    public Address PostalAddress { get; set; }
}

Then you can do this:

var newPerson = new Person()
{
    Name = "Kushan",
    Age = 25,
    PostalAddress = new Address()
    {
        Number = "No 25",
        Street = "Main Street",
        City = "Matale",
        Country = "Sri Lanka"
    }
};

MemoryStream stream = new MemoryStream();
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(Person));
ser.WriteObject(stream, newPerson);

To check the result:

var result = Encoding.ASCII.GetString(stream.ToArray());

{"PER_NAME":"Kushan","PER_AGE":25,"PER_ADDRESS":{"ADD_NUMBER":"No 25","ADD_STREET":"Main Street","ADD_CITY":"Matale","ADD_COUNTRY":"Sri Lanka"}}