jQuery

`$("input:enabled:invalid")`で「unsupported pseudo: invalid」というエラーが出る(jQuery 3.3.1)

環境

  • jQuery 3.3.1

以下のHTMLを使います。

<input type="text" required value="test"> <!-- valid -->
<input type="text" required> <!-- invalid(requiedなのにvalueがない) -->
<input type="text" required disabled> 

See the Pen $("input:enabled:invalid ")の確認 by yuji38kwmt (@yuji38kwmt) on CodePen.

問題

以下のJavaScriptをChromeで実行したところ、$("input:enabled:invalid").lengthでSyntax Errorが発生しました。

Console
$("input:enabled:invalid").length; //⇒Syntax Error ("1"を期待していた)
$("input:enabled").length; //⇒2
$("input:invalid").length; //⇒1
$("input.not-exists:enabled:invalid").length; //⇒0("input.not-exists"は存在しない要素)
console
Error: Syntax error, unrecognized expression: unsupported pseudo: invalid
    at Function.Sizzle.error (jquery-3.3.1.js:1541)
    at PSEUDO (jquery-3.3.1.js:1888)
    at matcherFromTokens (jquery-3.3.1.js:2437)
    at Sizzle.compile (jquery-3.3.1.js:2591)
    at Sizzle.select (jquery-3.3.1.js:2677)
    at Function.Sizzle [as find] (jquery-3.3.1.js:845)
    at jQuery.fn.init.find (jquery-3.3.1.js:2873)
    at new jQuery.fn.init (jquery-3.3.1.js:2983)
    at jQuery (jquery-3.3.1.js:139)
    at sample.html:36

他のブラウザで検証した結果

ブラウザ 結果
Google Chrome 65.0.3325.181 NG
Internet Explorer 11.309.16299.0 NG
Microsoft Edge 41.16299.248.0 OK
Firefox 59.0.1 OK

エラーの調査

jquery-3.3.1.js_(1881行-1916行)
        "PSEUDO": function( pseudo, argument ) {
            // pseudo-class names are case-insensitive
            // http://www.w3.org/TR/selectors/#pseudo-classes
            // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
            // Remember that setFilters inherits from pseudos
            var args,
                fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
                    Sizzle.error( "unsupported pseudo: " + pseudo );

            // The user may use createPseudo to indicate that
            // arguments are needed to create the filter function
            // just as Sizzle does
            if ( fn[ expando ] ) {
                return fn( argument );
            }

            // But maintain support for old signatures
            if ( fn.length > 1 ) {
                args = [ pseudo, pseudo, "", argument ];
                return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
                    markFunction(function( seed, matches ) {
                        var idx,
                            matched = fn( seed, argument ),
                            i = matched.length;
                        while ( i-- ) {
                            idx = indexOf( seed, matched[i] );
                            seed[ idx ] = !( matches[ idx ] = matched[i] );
                        }
                    }) :
                    function( elem ) {
                        return fn( elem, 0, args );
                    };
            }

            return fn;
        }

at PSEUDO (jquery-3.3.1.js:1888)は、以下の処理です。

jquery-3.3.1.js_(1886行-1888行)
            var args,
                fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
                    Sizzle.error( "unsupported pseudo: " + pseudo );

Expr.pseudos[ pseudo ] , Expr.setFilters[ pseudo.toLowerCase() ]がundefined or nullのため、Sizzle.errorが呼ばれたようです。

以下の場合、1888行目の処理を通りませんでした。

  • Firefoxで、$("input:enabled:invalid").lengthを実行したとき
  • Chromeで、$("input:invalid").lengthを実行したとき

これ以上のことは分かりませんでした。

【補足】document.querySelectorAllの場合

Chromeでエラーは発生しませんでした。

Console
document.querySelectorAll("input:enabled").length; //⇒2
document.querySelectorAll("input:invalid").length; //⇒1
document.querySelectorAll("input:enabled:invalid").length; //⇒1

【補足】 CSSの場合

期待通りの結果でした(CodePen参照)。

input:enabled {
  border-left-color: red;
}

input:invalid {
  border-right-color: red;
}

input:enabled:invalid {
  border-top-color: red;
}

そもそもやりたかったこと

Enabled/Disabledが切り替わるテキストボックスに対して、入力チェックをしたいです。
そのため、$("input:enabled:invalid")と記述しました。
しかし$("input:invalid")でDisabledのテキストボックスが除外されたので、$("input:invalid")で私のやりたいことは実現できました。

感想

GitHubにIssueを出して、回答をいただきました。
https://github.com/jquery/jquery/issues/4021

Thank you for opening an issue! However, the :invalid selector is not officially supported in jQuery. It works natively, but Sizzle doesn't trust native qSA with :enabled/:disabled due to a certain qSA bug in Chrome. There are a couple workarounds.

そもそもjQueryは:invalidをサポートしていませんでした。
確かに公式サイトに:invalidは掲載されていませんね。
https://api.jquery.com/category/selectors/

  • qSAdocument.querySelectorAllのことだと思います。

https://github.com/jquery/jquery/issues/3350

$("input").filter(":invalid")でも同様のエラーが発生します。