web-dev-qa-db-fra.com

jQuery selector value escaping

J'ai une liste déroulante qui contient une série d'options:

<select id=SomeDropdown>
  <option value="a'b]&lt;p>">a'b]&lt;p></option>
  <option value="easy">easy</option>
<select>

Notez que l'option valeur/texte contient des éléments désagréables:

  • guillemets simples
  • crochet carré de fermeture
  • hTML échappé

Je dois supprimer l'option a'b] <p> mais je n'ai aucune chance d'écrire le sélecteur. Ni:

$("#SomeDropdown >option[value='a''b]&lt;p>']");

ou

$("#SomeDropdown >option[value='a\'b]&lt;p>']");

retournent l'option.

Quelle est la bonne façon d'échapper des valeurs lors de l'utilisation du sélecteur "value ="?

54
user53794

Je ne pense pas que vous puissiez. Il devrait être:

#SomeDropdown >option[value='a\'b]<p>']

Et cela fonctionne comme un sélecteur CSS (dans les navigateurs modernes). Exprimé dans un littéral de chaîne JavaScript, vous auriez naturellement besoin d'un autre cycle d'échappement:

$("#SomeDropdown >option[value='a\\'b]<p>']")

Mais cela ne fonctionne pas dans jQuery car son analyseur de sélecteur n'est pas complètement conforme aux normes. Il utilise cette expression régulière pour analyser la partie value d'un [attr=value] condition:

(['"]*)(.*?)\3|)\s*\]

\ 3 étant le groupe contenant les guillemets d'ouverture, qui étrangement sont autorisés à être plusieurs guillemets d'ouverture, ou pas de guillemets d'ouverture du tout. Le .*? peut alors analyser n'importe quel caractère, y compris les guillemets jusqu'à ce qu'il atteigne le premier caractère "]", mettant fin à la correspondance. Il n'y a aucune disposition pour les caractères spéciaux CSS à barre oblique inverse, vous ne pouvez donc pas faire correspondre une valeur de chaîne arbitraire dans jQuery.

(Encore une fois, les analyseurs d'expressions rationnelles perdent.)

Mais la bonne nouvelle est que vous n'avez pas à vous fier aux sélecteurs jQuery; il existe de très bonnes méthodes DOM que vous pouvez utiliser, en particulier HTMLSelectElement.options:

var select= document.getElementById('SomeDropdown');
for (var i= select.options.length; i-->0;) {
    if (select.options[i].value=="a'b]<p>") {
        // do something with option
}   }

Ceci est plusieurs fois plus simple et plus rapide que de demander à jQuery d'analyser et d'implémenter laborieusement votre sélecteur, et vous pouvez utiliser n'importe quelle chaîne de valeur que vous souhaitez sans avoir à vous soucier d'échapper les caractères spéciaux.

38
bobince

J'utilise cette fonction pour échapper aux sélecteurs jquery. Il échappe pratiquement à tout, mais peut être trop agressif.

 fonction escapeStr (str) 
 {
 if (str) 
 return str.replace (/ ([#;?% &,. + * ~\' : "! ^ $ [\] () => | \/@])/g, '\\ $ 1'); 
 
 return str; 
} 
51
Sam Hendley

utilisez .filter() avec une fonction personnalisée. txt devrait contenir votre chaîne désagréable, ou vous pouvez simplement remplacer indexOf par n'importe quelle autre fonction de votre choix.

$("#SomeDropdown option")
   .filter(function(i){
       return $(this).attr("value").indexOf(txt) != -1;
   })
   .remove();
9
brainsucker

Je trouve que vous pouvez utiliser\\ pour échapper aux sélecteurs. Considérez-le comme un\pour le regex et un pour échapper au regex.

Exemple:

$(this).find('input[name=user\\[1\\]\\[name\\]]').val();
5
Strixy

Si vous essayez de faire l'échappement par programme, vous n'avez besoin que d'un seul jeu de barres obliques. Cela ne fonctionnera pas:

var key = 'user[1][name]';
$(this).find('select[name=' + key + ']');

Mais cela:

var key = 'user\[1\]\[name\]';
$(this).find('select[name=' + key + ']');

Et il en sera de même:

$(this).find('select[name=user\\[1\\]\\[name\\]]');

Vous pouvez utiliser ce javascript pour créer un sélecteur correctement échappé:

if(key.indexOf('[') !== -1) {
    key = key.replace(/([\[\]])/g, "\\$1");
}

Voici un JS Fiddle qui montre certains des comportements étranges:

http://jsfiddle.net/dH3cV/

3
Steve Tauber

Le problème est dû aux entités HTML; les "&lt; "est vu par le navigateur comme" < ".

La même chose pourrait être dite pour l'exemple fourni par bobince; veuillez noter que ce qui suit ne fonctionne pas avec jQuery 1.32 sur Win + FF3:

var select= document.getElementById('SomeDropdown');
for (var i= select.options.length; i-->0;) {
    if (select.options[i].value=="a'b]&lt;p>") {
        alert('found it');
    }   
}

Cependant, changer l'entité en un littéral trouvera en effet la valeur souhaitée:

var select= document.getElementById('SomeDropdown');
for (var i= select.options.length; i-->0;) {
    if (select.options[i].value=="a'b]<p>") {
        alert('found it');
    }   
}

Bien sûr, il y a un problème ici, car la valeur que vous spécifiez n'est pas la valeur exacte que vous recherchez. Cela peut également être corrigé avec l'ajout d'une fonction d'aide:

function html_entity_decode(str) {
    var decoder = document.createElement('textarea');
    decoder.innerHTML = str;
    return decoder.value;
}

Tous ensemble maintenant:

var srcValue = html_entity_decode("a'b]&lt;p>");
var select= document.getElementById('SomeDropdown');
for (var i= select.options.length; i-->0;) {
    if (select.options[i].value == srcValue) {
        alert('found it');
    }   
}

Maintenant, la valeur d'entrée que vous recherchez correspond exactement à la valeur de l'élément select.

Cela peut également être écrit à l'aide des méthodes jQuery:

var srcValue = html_entity_decode("a'b]&lt;p>");
$($('#SomeDropdown').attr('options')).each(function() {
    if (this.value == srcValue)
    {
        $(this).remove();
    }
});

Et puis enfin, en tant que plugin car ils sont si faciles à réaliser:

jQuery.fn.removeByValue = function( val )
{
    var decoder = document.createElement('textarea');
    decoder.innerHTML = val;    
    var srcValue = decoder.value;

    $( $(this)[0].options ).each(function() {
        if (this.value == srcValue) {
            $(this).remove();
        }
    });

    return this;
};

$('#SomeDropdown').removeByValue("a'b]&lt;p>");
2
ken

En toute sécurité échapper la chaîne CSS n'est pas facile et ne peut pas être fait avec une simple expression régulière.

Vous pouvez utiliser CSS.escape() .

ce n'est pas supporté par tous les navigateurs mais n polyfill existe .

1
Yukulélé

le forum de jQuery a une solution intéressante pour cela:

https://learn.jquery.com/using-jquery-core/faq/how-do-i-select-an-element-by-an-id-that-has-characters-used-in- notation css /

Cette version légèrement modifiée de ce qu'ils suggèrent est également nullsafe.

function jqid (id) {
  return (!id) ? null : '#' + id.replace(/(:|\.|\[|\]|,)/g, '\\$1');
}
1
theUtherSide