Search code examples
javascriptjqueryjquery-selectorsknockout.jssizzle

jQuery 1.5.1 Sizzle 'cannot read property nodename' child '>' selector with knockoutjs


I'm using jQuery 1.5.1 and Knockoutjs 2.0.0. My situation's a little bit complicated, but as I understand it here's what's happening:

I have some elements bound to Knockoutjs that also have jQuery.live bindings. Some of these bindings contain the child (parent?) selector '>'. When I remove the element (using Knockout), I get this error:

Uncaught TypeError: Cannot read property 'nodeName' of null

thrown by the following code in jQuery:

">": function (checkSet, part) {
  ...    
    for (; i < l; i++) {
      elem = checkSet[i];

      if (elem) {
        var parent = elem.parentNode;
        checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false;
        //Uncaught TypeError: Cannot read property 'nodeName' of null
      }
    }
 ...

It seems Knockout is removing elements from the document before jQuery gets around to checking the live bindings, so when the element is finally checked its parent is null, and this error is thrown.

My question:

Where/how would people recommend I fix this? I was thinking something like this:

var parent = elem.parentNode;
checkSet[i] = parent && parent.nodeName.toLowerCase() === part ? parent : false;

Seems like the '>' selector should fail if the parent is null, but I could be wrong about that. What would you guys do?

UPDATE:

JSFiddle demonstrating the issue (try removing a table row):

This only happens when I use one of the selectors below for my .live binding. Using only one class in the :not selector causes the bug to disappear.

'.grid:not(.anything, .anythingelse) > tbody > tr'
'.grid:not(.anything, .anythingelse) tbody > tr'

Solution

  • The reason why the bug seems to disappear when you pass one class to :not() is because it then becomes a valid CSS3 selector, so it's being passed to querySelectorAll(), skipping Sizzle altogether. See this question for details.

    I'm not sure if the behavior you're seeing with > is a bug with Sizzle, and if so whether it has been addressed (as of jQuery 1.8), but since a CSS selector is guaranteed to work as close to the spec as a browser can promise then I can only suggest using the workaround that you have.