Elemento de filtro com base na chave / valor .data ()

116

Digamos que eu tenha 4 elementos div com class .navlink, que, quando clicados, usam .data()para definir uma chave chamada 'selected', para um valor de true:

$('.navlink')click(function() { $(this).data('selected', true); })

Cada vez que um novo .navlinké clicado, gostaria de armazenar o selecionado anteriormente navlinkpara manipulação posterior. Existe uma maneira rápida e fácil de selecionar um elemento com base no que foi armazenado usando .data()?

Não parece haver nenhum filtro jQuery : que se encaixe no perfil, e tentei o seguinte (dentro do mesmo evento de clique), mas por algum motivo não funcionou:

var $previous = $('.navlink').filter( 
    function() { $(this).data("selected") == true }
);

Eu sei que existem outras maneiras de fazer isso, mas agora estou curioso para saber se isso pode ser feito via .data().

user113716
fonte

Respostas:

192

seu filtro funcionaria, mas você precisa retornar true em objetos correspondentes na função passada ao filtro para que ele os capture.

var $previous = $('.navlink').filter(function() { 
  return $(this).data("selected") == true 
});
BaroqueBobcat
fonte
6
Observe que esta não é mais a única maneira de fazer isso, StefanoP forneceu alternativas
Nathan Koop
3
@NathanKoop, não exatamente. Veja meu comentário em sua resposta.
Bryan Downing
Para aqueles que usam um atributo de dados para encontrar um elemento não encontrado de outra forma (id menos divs etc ... que você precisa ser capaz de acessar por qualquer motivo) em qualquer local do documento:$("*").filter(function() { return $(this).data("DATA IDENTIFIER HERE") == DATA VALUE HERE; });
Tschallacka
isso não é "bagunçado" - essa é a única maneira segura de filtrar em termos arbitrários sem exigir que você "escape" desses valores para garantir que a concatenação do termo de pesquisa com o resto do seletor não crie um seletor ilegal.
Alnitak
145

Apenas para registro, você pode filtrar os dados com jquery (esta questão é bastante antiga, e o jQuery evoluiu desde então, então é certo escrever esta solução também):

$('.navlink[data-selected="true"]');

ou melhor (para desempenho):

$('.navlink').filter('[data-selected="true"]');

ou, se você deseja obter todos os elementos com data-selectedset:

$('[data-selected]')

Observe que este método só funcionará com dados que foram configurados por meio de atributos html. Se você definir ou alterar os dados com a .data()chamada, esse método não funcionará mais.

StefanoP
fonte
9
se a baixa contagem de votos para esta resposta o assusta - é a resposta aceita com mais de 100 votos para uma pergunta virtualmente idêntica stackoverflow.com/questions/4146502
Simon_Weaver
48
-1 Isso não funciona quando os dados são definidos com o .data()método em vez de um data-atributo. Veja este violino: jsfiddle.net/bryandowning/tySWC - Além disso, o .find()método procura por filhos do seletor anterior. No exemplo dado, data-selectedé um atributo de .navlink, não um filho de .navlink. Além disso, $('div p')e $('div').find('p')são essencialmente equivalentes. O uso .find()parece ser mais lento devido à chamada de função extra (embora eu não tenha certeza sobre isso). Por favor, corrija-me se eu estiver errado sobre isso (eu realmente gostaria que esse método funcionasse).
Bryan Downing
3
algumas coisas: 1) você está certo de que isso não funciona se você definir dados com .data(), uma vez que o jQuery pesquisa através do DOM, eu postei para aqueles (como eu) que chegaram a esta pergunta por outros motivos; 2) correto, .find()busca nas crianças, então está errado neste exemplo; 3) Você está errado, eles não são equivalentes, como pesquisas jQuery da direita para a esquerda, ver jonraasch.com/blog/...
StefanoP
2
Votar a favor $('[data-selected]')me ajudou a algo como$('ul.categories a[data-categories_id]').click(......);
Luke Cousins
Além disso, parece que se você atualizar o atributo de dados usando .attr, se você recuperá-lo usando .data, o valor não será atualizado - portanto, tome cuidado ao misturar os dois
Fabio Lolli
13

Podemos fazer um plugin com bastante facilidade:

$.fn.filterData = function(key, value) {
    return this.filter(function() {
        return $(this).data(key) == value;
    });
};

Uso (marcando um botão de opção):

$('input[name=location_id]').filterData('my-data','data-val').prop('checked',true);
mpen
fonte
Você quer dizer o método do plugin, caso contrário, esta é a mesma resposta aceita ...
jave.web
@ jave.web Certamente. Mas nem todo mundo sabe como transformá-lo em um plugin. Palavreado atualizado.
MPEN
não me interpretem mal, sua resposta é ótima, porém as palavras aqui são muito importantes, obrigado pela atualização :)
jave.web
8

Observei duas coisas (podem ser erros de quando você escreveu).

  1. Você perdeu um ponto no primeiro exemplo ( $('.navlink').click)
  2. Para que o filtro funcione, você deve retornar um valor ( return $(this).data("selected")==true)
Thomas
fonte
-1

Parece mais trabalho do que vale a pena.

1) Por que não ter apenas uma única variável JavaScript que armazena uma referência ao objeto elemento \ jQuery atualmente selecionado.

2) Por que não adicionar uma classe ao elemento atualmente selecionado. Então você pode consultar o DOM para a classe ".active" ou algo assim.

Bryan Migliorisi
fonte
Sim, mas como eu disse, eu sabia que havia outras maneiras de fazer isso. Eu estava sem saber se ele poderia ser filtrado via data () e por que filter () não estava funcionando para mim. Obrigado.
usuário113716
Desculpe. Eu perdi essa parte da sua pergunta.
Bryan Migliorisi