Como posso detectar se um seletor retorna nulo?

271

Qual é a melhor maneira de detectar se um seletor de jQuery retorna um objeto vazio. Se você fizer:

alert($('#notAnElement'));

você obtém [objeto Objeto], então a forma como faço agora é:

alert($('#notAnElement').get(0));

que escreverá "indefinido" e você poderá verificar isso. Mas parece muito ruim. Que outro caminho existe?

peirix
fonte

Respostas:

494

Meu favorito é estender o jQuery com essa pequena conveniência:

$.fn.exists = function () {
    return this.length !== 0;
}

Usado como:

$("#notAnElement").exists();

Mais explícito do que usar comprimento.

Magnar
fonte
2
Por que você colocou 'this' dentro de um $ ()? 'this' não apontaria realmente para o objeto jQuery?
Adham Atta 28/03
1
Acho que voltar thisé muito mais útil do que true. Veja minha resposta portando o presencemétodo Rails .
Marc-André Lafortune
5
Se você deseja manter a capacidade de encadear, se a função retornar true, ou se desejar usar esse método para atribuir thisa uma variável, eu recomendaria alterar a declaração de retorno para o que o CSharp possui.
21713 Hanna
1
Magnar, você pode explicar como essa função de "extensão" realmente funciona? Estou assumindo que é um conceito Javascript e não um conceito estritamente JQuery. Analisei a prototipagem, mas não tenho certeza se isso se aplica aqui e por que a sintaxe seria "$ .fn".
KyleM
3
@ Adam Sim. Mas, nesse caso, você deve simplesmente eliminar a verificação de existência, considerando o funcionamento do jQuery. Isso simplesmente não fará nada se não houver um elemento correspondente ao seletor.
Magnar
197
if ( $("#anid").length ) {
  alert("element(s) found")
} 
else {
  alert("nothing found")
}
duckyflip
fonte
67

O seletor retorna uma matriz de objetos jQuery. Se nenhum elemento correspondente for encontrado, ele retornará uma matriz vazia. Você pode verificar a .lengthcoleção retornada pelo seletor ou verificar se o primeiro elemento da matriz é 'indefinido'.

Você pode usar qualquer um dos seguintes exemplos dentro de uma instrução IF e todos eles produzem o mesmo resultado. Verdadeiro, se o seletor encontrou um elemento correspondente, falso caso contrário.

$('#notAnElement').length > 0
$('#notAnElement').get(0) !== undefined
$('#notAnElement')[0] !== undefined
Jose Basilio
fonte
1
Eu uso a .lengthmenos que o código esteja quente. É certamente o mais claro com intenção. Além disso, .size()está obsoleto e está há anos (desde 1,8). Vou apenas editar sua resposta e removê-la. Sinta-se à vontade para adicioná-la novamente com uma nota, mas é tão antiga que acho melhor ir.
Evan Carroll
1
Tecnicamente, ele retorna um objeto jQuery que não contém nós DOM. Dizer que retorna uma matriz vazia não está certo.
Vigrant
39

Eu gosto de fazer algo assim:

$.fn.exists = function(){
    return this.length > 0 ? this : false;
}

Então você pode fazer algo assim:

var firstExistingElement = 
    $('#iDontExist').exists() ||      //<-returns false;
    $('#iExist').exists() ||          //<-gets assigned to the variable 
    $('#iExistAsWell').exists();      //<-never runs

firstExistingElement.doSomething();   //<-executes on #iExist

http://jsfiddle.net/vhbSG/

CSharp
fonte
6
@Ehsan Na verdade, não é uma duplicata da resposta aceita ... observe que a resposta aceita retorna apenas verdadeiro / falso, enquanto essa resposta retorna o objeto original ("this") ou false. Esta resposta permite que você faça coisas adicionais com o valor de retorno (como encadeamento de funções adicionais) se não for falso.
RSW
1
Eu tenho exatamente o mesmo código no meu kit de ferramentas padrão. Este formulário é equivalente a object.presence no Rails e super útil na construção de detalhamento descrita pelo @CSharp.
Inopinatus
Essa é uma boa resposta, mas seria útil se você explicasse o que acontece se NENHUM dos elementos testados existir. Resposta curta: TypeError: firstExistingElement.doSomething is not a function. Você pode embrulhar toda a atribuição de variável / teste em uma if () e apenas fazer algo se um elemento é encontrado ....
Stephen R
9

Eu gosto de usar presence, inspirado no Ruby on Rails :

$.fn.presence = function () {
    return this.length !== 0 && this;
}

Seu exemplo se torna:

alert($('#notAnElement').presence() || "No object found");

Acho que é superior ao proposto $.fn.existsporque você ainda pode usar operadores booleanos ou if, mas o resultado verdadeiro é mais útil. Outro exemplo:

$ul = $elem.find('ul').presence() || $('<ul class="foo">').appendTo($elem)
$ul.append('...')
Marc-André Lafortune
fonte
7

Minha preferência, e eu não tenho idéia por que isso ainda não está no jQuery:

$.fn.orElse = function(elseFunction) {
  if (!this.length) {
    elseFunction();
  }
};

Usado assim:

$('#notAnElement').each(function () {
  alert("Wrong, it is an element")
}).orElse(function() {
  alert("Yup, it's not an element")
});

Ou, como parece no CoffeeScript:

$('#notAnElement').each ->
  alert "Wrong, it is an element"; return
.orElse ->
  alert "Yup, it's not an element"
nilskp
fonte
0

Você pode fazer isso o tempo todo por padrão. Eu tenho lutado para quebrar a função jquery ou o método jquery.fn.init para fazer isso sem erros, mas você pode fazer uma alteração simples na fonte do jquery para fazer isso. Estão incluídas algumas linhas circundantes que você pode pesquisar. Eu recomendo procurar na fonte jquery porThe jQuery object is actually just the init constructor 'enhanced'

var
  version = "3.3.1",

  // Define a local copy of jQuery
  jQuery = function( selector, context ) {

    // The jQuery object is actually just the init constructor 'enhanced'
    // Need init if jQuery is called (just allow error to be thrown if not included)
    var result = new jQuery.fn.init( selector, context );
    if ( result.length === 0 ) {
      if (window.console && console.warn && context !== 'failsafe') {
        if (selector != null) {
          console.warn(
            new Error('$(\''+selector+'\') selected nothing. Do $(sel, "failsafe") to silence warning. Context:'+context)
          );
        }
      }
    }
    return result;
  },

  // Support: Android <=4.0 only
  // Make sure we trim BOM and NBSP
  rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;

jQuery.fn = jQuery.prototype = {

Por último, mas não menos importante, você pode obter o código fonte do jquery não compactado aqui: http://code.jquery.com/

Devin G Rhode
fonte