Barlow Tucker
Barlow Tucker

Reputation: 6529

Filtering elements out of a jQuery selector

I have a page that selects all the elements in a form and serializes them like this:

var filter = 'form :not([name^=ww],[id$=IDF] *,.tools *)';
var serialized = $(filter).serialize();

This works, unless the form gets around 600+ elements. Then the user gets s javascript error saying that the script is running slow and may make their browsers unresponsive. It then gives them the option to stop running the script.

I have tried running the filters separately, I have tried using .not on the selectors, then serializing them, but I run into one of two problems. Either it runs faster without the error, but also does not filter the elements, or it does filter the elements and gives me the slow script error.

Any ideas?

Upvotes: 2

Views: 400

Answers (3)

James
James

Reputation: 112000

With 600+ elements this is going to be dead slow. You need to offer Sizzle (jQuery's selector engine) some opportunities for optimisation.

First, consider the fact that jQuery can use the natively-supported querySelectorAll method (in modern browsers) if your selector complies with the CSS3 spec (or at least to the extent of what's currently supported in browsers).

With your case, that would mean passing only one simple selector to :not instead of 3 (1 simple, 2 complex).

form :not([name^=ww])

That would be quite fast... although you're not being kind to browsers that don't support querySelectorAll.

Look at your selector and think about how much Sizzle has to do with each element. First it needs to get ALL elements within the page (you're not pre-qualifying the :not selector with a tag/class/id). Then, on each element it does the following:

(assume that it exits if a result of a check is false)

  1. Check that the parent has an ancestor with the nodeName.toLowerCase() of form.
  2. Check that it does not have a name attribute starting with ww (basic indexOf operation).
  3. Check that it does not have an ancestor with an id attribute ending in IDF. (expensive operation)
  4. Check that it does not have an ancestor with a class attribute containing tools.

The last two operations are slow.

It may be best to manually construct a filter function, like so:

var jq = $([1]);
$('form :input').filter(function(){

    // Re-order conditions so that
    // most likely to fail is at the top!

    jq[0] = this; // faster than constructing a new jQ obj

    return (

        !jq.closest('[id$=IDF]')[0]
            // this can be improved. Maybe pre-qualify
            // attribute selector with a tag name

        && !jq.closest('.tools')[0]

        && this.name.indexOf('ww') !== 0

    );

});

Note: that function is untested. Hopefully you get the idea...

Upvotes: 5

Gabriele Petrioli
Gabriele Petrioli

Reputation: 196306

use the :input selector to only select applicable elements..

Upvotes: 0

rfunduk
rfunduk

Reputation: 30452

Could you maybe just serialize the whole form and do your filtering on the backend? Also, why-oh-why is the form growing to 600+ fields?

Upvotes: 1

Related Questions