Comment obtenir jQuery pour sélectionner des éléments avec un. (période) dans leur pièce d'identité?

172

Compte tenu des classes et de la méthode d'action du contrôleur suivantes:

public School
{
  public Int32 ID { get; set; }
  publig String Name { get; set; }
  public Address Address { get; set; }
}

public class Address
{
  public string Street1 { get; set; }
  public string City { get; set; }
  public String ZipCode { get; set; }
  public String State { get; set; }
  public String Country { get; set; }
}

[Authorize(Roles = "SchoolEditor")]
[AcceptVerbs(HttpVerbs.Post)]
public SchoolResponse Edit(Int32 id, FormCollection form)
{
  School school = GetSchoolFromRepository(id);

  UpdateModel(school, form);

  return new SchoolResponse() { School = school };
}

Et la forme suivante:

<form method="post">
  School: <%= Html.TextBox("Name") %><br />
  Street: <%= Html.TextBox("Address.Street") %><br />
  City:  <%= Html.TextBox("Address.City") %><br />
  Zip Code: <%= Html.TextBox("Address.ZipCode") %><br />
  Sate: <select id="Address.State"></select><br />
  Country: <select id="Address.Country"></select><br />
</form>

Je suis en mesure de mettre à jour à la fois l'instance School et le membre Address de l'école. C'est assez sympa! Merci à l'équipe ASP.NET MVC!

Cependant, comment utiliser jQuery pour sélectionner la liste déroulante afin de pouvoir la pré-remplir? Je me rends compte que je pourrais faire ce côté serveur mais il y aura d'autres éléments dynamiques sur la page qui affecteront la liste.

Ce qui suit est ce que j'ai jusqu'à présent, et cela ne fonctionne pas car les sélecteurs ne semblent pas correspondre aux ID:

$(function() {
  $.getJSON("/Location/GetCountryList", null, function(data) {
    $("#Address.Country").fillSelect(data);
  });
  $("#Address.Country").change(function() {
    $.getJSON("/Location/GetRegionsForCountry", { country: $(this).val() }, function(data) {
      $("#Address.State").fillSelect(data);
    });
  });
});
Doug Wilson
la source

Réponses:

293

Depuis Google Groupes :

Utilisez deux barres obliques inverses avant chaque caractère spécial.

Une barre oblique inverse dans un sélecteur jQuery échappe le caractère suivant. Mais vous avez besoin de deux d'entre eux car la barre oblique inverse est également le caractère d'échappement des chaînes JavaScript. La première barre oblique inverse échappe à la seconde, vous donnant une barre oblique inverse réelle dans votre chaîne - qui échappe ensuite le caractère suivant pour jQuery.

Alors, je suppose que tu regardes

$(function() {
  $.getJSON("/Location/GetCountryList", null, function(data) {
    $("#Address\\.Country").fillSelect(data);
  });
  $("#Address\\.Country").change(function() {
    $.getJSON("/Location/GetRegionsForCountry", { country: $(this).val() }, function(data) {
      $("#Address\\.State").fillSelect(data);
    });
  });
});

Consultez également Comment sélectionner un élément par un identifiant contenant des caractères utilisés en notation CSS? sur la FAQ jQuery.

bdukes
la source
4
Je me demande quelle est la rationalisation pour obliger le développeur à faire cela, il semble qu'un simple ensemble d'heuristiques dans jQuery résoudrait ce problème, car il n'y a rien de mal avec les ID avec des points ...
Jason Bunting
5
Si vous n'aviez pas à vous échapper, comment interrogeriez-vous un élément avec l'adresse ID et l'état de la classe (à condition que si vous connaissez l'ID, vous n'ajoutez pas grand-chose en spécifiant la classe, mais elle devrait toujours être valide, je pense)?
bdukes
12
Pour cette raison, dans CSS lui-même, vous devez également échapper un point dans un ID. Tout ce que fait jQuery est de vous obliger à suivre les règles définies par CSS.
bdukes
6
Vous pouvez également sélectionner par nom au lieu d'ID. Par exemple, $ ('[name = "Address.Country"]')
Funka
25

Vous ne pouvez pas utiliser un sélecteur d'identifiant jQuery si l'identifiant contient des espaces. Utilisez un sélecteur d'attribut:

$('[id=foo bar]').show();

Si possible, spécifiez également le type d'élément:

$('div[id=foo bar]').show();
Elliot Nelson
la source
Je préfère le faire de cette façon que d'utiliser les caractères d'échappement .... De toute évidence, la meilleure solution de contournement est de ne pas utiliser de points dans l'identifiant.
GordonB
Les espaces ne sont pas autorisés dans les identifiants, pas même dans l'acceptation plus libérale des caractères par HTML5. stackoverflow.com/questions/70579/…
Jay Blanchard
C'est vrai, mais qu'ils soient autorisés ou non, cela n'a pas d'importance pour la pauvre sève qui est coincée en ajoutant une vitrine à une application Web mal écrite déployée à la fin des années 90.
Elliot Nelson
4
il doit y avoir des quates pour fonctionner: `$ (" div [id = '"+ variable +"'] ")` ou `$ (" div [id = 'foo bar'] ")`
olga
Comme l'a dit @olga, la réponse n'est plus légale. Plus précisément, vous obtiendrez un message d'erreur "Erreur non interceptée: erreur de syntaxe, expression non reconnue: div [id = foo bar]"
James Moore
13

Échappez-vous à Jquery:

function escapeSelector(s){
    return s.replace( /(:|\.|\[|\])/g, "\\$1" );
}

exemple d'utilisation:

e.find('option[value='+escapeSelector(val)+']')

plus d'infos ici .


la source
2
La solution selon les documents jQuery est d'ajouter un seul "\" (barre oblique). alert (escapeSelector ("some.id")); affichera un \ .id. Donc, je suppose que l'expression régulière de remplacement aurait dû être à la place (/(:|\.|[| </font>)/g, "\\\\ $ 1");
Arun
J'ai le même problème, pourquoi personne d'autre ne le voit?
TruthOf42
9

La version Release Candidate d'ASP.NET MVC qui vient d'être publiée a résolu ce problème, elle remplace désormais les points par des traits de soulignement pour l'attribut ID.

<%= Html.TextBox("Person.FirstName") %>

Rend en

<input type="text" name="Person.FirstName" id="Person_FirstName" />

Pour plus d'informations, consultez les notes de mise à jour, à partir de la page 14.

Dale Ragan
la source
1
Je ne vois pas en quoi il s'agit d'un «correctif» - pourquoi ASP.NET MVC devrait-il changer l'ID en quelque chose dont jQuery a besoin? Je pense que jQuery est là où réside le problème, sans utiliser de fichier. dans une pièce d'identité.
Jason Bunting
7
le point a une signification particulière dans CSS pour identifier / combiner des classes, c'est pourquoi l'avoir dans un ID est gênant. Le "problème" ne vient pas de jquery.
Funka
4

Ceci est documenté dans la documentation de jQuery Selectors :

Pour utiliser les méta-caractères ( par exemple !"#$%&'()*+,./:;<=>?@[\]^`{|}~) comme une partie littérale d'un nom, il doit être échappé avec deux barres obliques inverses: \\. Par exemple, un élément avec id="foo.bar", peut utiliser le sélecteur $("#foo\\.bar").

En bref, préfixez le .avec \\comme suit:

$("#Address\\.Country")

Pourquoi ne .fonctionne pas dans mon identifiant?

Le problème est que cela .a une signification particulière, la chaîne suivante est interprétée comme un sélecteur de classe. Donc $('#Address.Country')correspondrait<div id="Address" class="Country"> .

Lorsqu'il est échappé comme \\., le point sera traité comme du texte normal sans signification particulière, correspondant à l'ID souhaité <div id="Address.Country">.

Cela s'applique à tous les caractères !"#$%&'()*+,./:;<=>?@[\]^`{|}~qui auraient autrement une signification particulière en tant que sélecteur dans jQuery. Ajoutez-les simplement \\pour les traiter comme du texte normal.

Pourquoi 2 \\?

Comme indiqué dans la réponse de bdukes, il y a une raison pour laquelle nous avons besoin de 2 \caractères. \échappera au caractère suivant en JavaScript. Lorsque JavaScript interprète la chaîne "#Address\.Country", il verra le \, l'interprétera comme signifiant prendre le caractère suivant littéralement et le supprimer lorsque la chaîne est transmise comme argument à $(). Cela signifie que jQuery verra toujours la chaîne comme "#Address.Country".

C'est là que le second \entre en jeu. Le premier indique à JavaScript d'interpréter le second comme un caractère littéral (non spécial). Cela signifie que le second sera vu par jQuery et comprendra que le . caractère suivant est un caractère littéral.

Phew! Peut-être pouvons-nous visualiser cela.

//    Javascript, the following \ is not special.
//         | 
//         |
//         v    
$("#Address\\.Country");
//          ^ 
//          |
//          |
//      jQuery, the following . is not special.
Jon Surrell
la source
2

En utilisant deux backslashes c'est ok, ça marche. Mais si vous utilisez un nom dynamique, je veux dire, un nom de variable, vous devrez remplacer des caractères.

Si vous ne souhaitez pas changer les noms de vos variables, vous pouvez le faire:

var variable="namewith.andother";    
var jqueryObj = $(document.getElementById(variable));

et que vous avez votre objet jquery.

Daniel
la source
0

Juste des informations supplémentaires: consultez ce problème ASP.NET MVC # 2403 .

Jusqu'à ce que le problème soit résolu, j'utilise mes propres méthodes d'extension comme Html.TextBoxFixed, etc. qui remplace simplement les points par des traits de soulignement dans l'attribut id (pas dans l'attribut name), de sorte que vous utilisez jquery comme $ ("# Address_Street") mais sur le serveur, c'est comme Address.Street.

Un exemple de code suit:

public static string TextBoxFixed(this HtmlHelper html, string name, string value)
{
    return html.TextBox(name, value, GetIdAttributeObject(name));
}

public static string TextBoxFixed(this HtmlHelper html, string name, string value, object htmlAttributes)
{
    return html.TextBox(name, value, GetIdAttributeObject(name, htmlAttributes));
}

private static IDictionary<string, object> GetIdAttributeObject(string name)
{
    Dictionary<string, object> list = new Dictionary<string, object>(1);
    list["id"] = name.Replace('.', '_');
    return list;
}

private static IDictionary<string, object> GetIdAttributeObject(string name, object baseObject)
{
    Dictionary<string, object> list = new Dictionary<string, object>();
    list.LoadFrom(baseObject);
    list["id"] = name.Replace('.', '_');
    return list;
}
gius
la source
1
du problème susmentionné: "UpdateModel () utilise un point parce que c'est ainsi que les éléments de formulaire entrent. Les éléments de formulaire utilisent un point parce que c'est ainsi qu'ils sont spécifiés dans les appels d'assistance HTML. Les appels d'assistance HTML utilisent un point car c'est ainsi ViewData.Eval () fonctionne. Enfin, ViewData.Eval () utilise un point, car c'est ainsi que l'on sépare un objet et sa propriété dans les principaux langages .NET Framework. L'utilisation d'un délimiteur autre qu'un point à tout moment de cette chaîne serait rompue le flux pour toute la chaîne. "
Simon_Weaver
0

J'ai résolu le problème avec la solution donnée par jquery docs

Ma fonction:

//funcion to replace special chars in ID of  HTML tag

function jq(myid){


//return "#" + myid.replace( /(:|\.|\[|\]|,)/g, "\\$1" );
return myid.replace( /(:|\.|\[|\]|,)/g, "\\$1" );


}

Remarque: je supprime le "#" car dans mon code, je concat l'identifiant avec un autre texte

Police: Jquery Docs select élément avec des caractères spéciaux

Gabriel Molina
la source