Como faço para que o jQuery selecione elementos com a. (período) em seu ID?

172

Dadas as seguintes classes e método de ação do controlador:

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 };
}

E o seguinte formulário:

<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>

Consigo atualizar a instância da escola e o membro de endereço da escola. Isso é muito legal! Obrigado equipe ASP.NET MVC!

No entanto, como uso o jQuery para selecionar a lista suspensa para preenchê-la previamente? Sei que poderia fazer esse lado do servidor, mas haverá outros elementos dinâmicos na página que afetam a lista.

A seguir, é o que tenho até agora e não funciona, pois os seletores parecem não corresponder aos IDs:

$(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
fonte

Respostas:

293

Dos Grupos do Google :

Use duas barras invertidas antes de cada caractere especial.

Uma barra invertida em um seletor jQuery escapa o próximo caractere. Mas você precisa de dois deles, porque a barra invertida também é o caractere de escape para as strings JavaScript. A primeira barra invertida escapa à segunda, fornecendo uma barra invertida real em sua string - que, em seguida, escapa o próximo caractere para o jQuery.

Então, eu acho que você está olhando

$(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);
    });
  });
});

Verifique também como faço para selecionar um elemento por um ID que possua caracteres usados ​​na notação CSS? no FAQ do jQuery.

bdukes
fonte
4
Gostaria de saber qual é a racionalização para exigir que o desenvolvedor faça isso, parece que um conjunto simples de heurísticas no jQuery resolveria esse problema, já que não há nada errado com IDs com períodos neles ...
Jason Bunting
5
Se você não tivesse que escapar, como consultaria um elemento com o endereço de ID e o estado da classe (desde que, se você conhece o ID, não está adicionando muito especificando a classe, mas ainda assim deve ser válido, eu pensar)?
bdukes
12
Por esse motivo, no próprio CSS, você também deve escapar de um ponto em um ID. Tudo que o jQuery está fazendo exige que você siga as regras definidas pelo CSS.
bdukes
6
Você também pode selecionar por nome em vez de ID. Por exemplo, $ ('[name = "Address.Country"]')
Funka 20/08/2010
25

Você não pode usar um seletor de id do jQuery se o id contiver espaços. Use um seletor de atributos:

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

Se possível, especifique também o tipo de elemento:

$('div[id=foo bar]').show();
Elliot Nelson
fonte
Prefiro fazê-lo dessa maneira do que usar os caracteres de escape ... Obviamente, a melhor solução alternativa é não usar pontos no id.
precisa
Os espaços não são permitidos nos IDs, nem mesmo na aceitação mais liberal de caracteres do HTML5. stackoverflow.com/questions/70579/...
Jay Blanchard
É verdade, mas se eles são permitidos ou não, não importa para o pobre coitado que está adicionando um visual de janela a um aplicativo da Web mal escrito, implantado no final dos anos 90.
Elliot Nelson
4
deve haver aspas para que funcione: `$ (" div [id = '"+ variável +"'] ")` ou `$ (" div [id = 'foo bar'] ")`
olga
Como disse @olga, a resposta não é mais legal. Especificamente, você receberá uma mensagem de erro "Erro não capturado: erro de sintaxe, expressão não reconhecida: div [id = foo bar]"
James Moore
13

Escape para o Jquery:

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

exemplo de uso:

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

mais informações aqui .


fonte
2
A solução, conforme os documentos do jQuery, está adicionando apenas um "\" (barra). alert (escapeSelector ("some.id")); será exibido como alguns \ .id. Portanto, acho que o regex de substituição deveria ter sido s.replace (/(:|\.|[||))/g, "\\\\ $ 1");
Arun
Eu tenho o mesmo problema, por que mais ninguém vê isso?
TruthOf42
9

O Release Candidate do ASP.NET MVC que acabou de ser lançado corrigiu esse problema, agora substitui os pontos por sublinhados para o atributo ID.

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

Renderiza para

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

Para mais informações, veja as notas de versão, começando na página 14.

Dale Ragan
fonte
1
Não vejo como isso é uma "correção" - por que o ASP.NET MVC precisa alterar o ID para algo que o jQuery precisa? Eu acho que jQuery é onde está o problema, não usando a. em um ID.
23909 Jason Bunting
7
o ponto tem um significado especial no CSS para identificar / combinar classes, e é por isso que é problemático tê-lo em um ID. O "problema" não está no jquery.
Funka
4

Isso está documentado nos documentos do jQuery Selectors :

Para usar qualquer um dos meta-caracteres (tais como !"#$%&'()*+,./:;<=>?@[\]^`{|}~) como uma parte literal de um nome, deve ser escapado com com duas barras invertidas: \\. Por exemplo, um elemento com id="foo.bar", pode usar o seletor $("#foo\\.bar").

Em resumo, prefixe o .com da \\seguinte maneira:

$("#Address\\.Country")

Por que não .funciona no meu ID?

O problema é que .tem um significado especial, a sequência a seguir é interpretada como um seletor de classe. Então $('#Address.Country')combinaria <div id="Address" class="Country">.

Quando escapado como \\., o ponto será tratado como texto normal sem significado especial, correspondendo ao ID que você deseja <div id="Address.Country">.

Isso se aplica a todos os caracteres !"#$%&'()*+,./:;<=>?@[\]^`{|}~que, de outra forma, teriam um significado especial como seletor no jQuery. Anexe apenas \\para tratá-los como texto normal.

Por que 2 \\?

Conforme observado na resposta do bdukes, há uma razão pela qual precisamos de 2 \caracteres. \escapará do seguinte caractere em JavaScript. Se, quando o JavaScript interpreta a string "#Address\.Country", ele vê \, interpreta-o com o seguinte caractere alfabético e remove -o quando a string é passada como argumento para $(). Isso significa que o jQuery ainda verá a string como "#Address.Country".

É aí que o segundo \entra para jogar. O primeiro diz ao JavaScript para interpretar o segundo como um caractere literal (não especial). Isso significa que o segundo será visto pelo jQuery e entenderá que o seguinte . caractere é um caractere literal.

Ufa! Talvez possamos visualizar isso.

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

Usando duas barras invertidas, tudo bem, está funcionando. Mas se você estiver usando um nome dinâmico, quero dizer, um nome de variável, precisará substituir caracteres.

Se você não quiser alterar os nomes das variáveis, faça o seguinte:

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

e do que você tem seu objeto jquery.

Daniel
fonte
0

Apenas informações adicionais: verifique este problema do ASP.NET MVC # 2403 .

Até que o problema seja resolvido, eu uso meus próprios métodos de extensão, como Html.TextBoxFixed, etc. que simplesmente substituem pontos por sublinhados no atributo id (não no atributo name), para que você use jquery como $ ("# Address_Street") mas no servidor, é como Address.Street.

Código de exemplo a seguir:

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
fonte
1
da questão mencionada: "UpdateModel () usa um ponto porque é assim que os elementos do formulário entram. Os elementos do formulário usam um ponto porque é assim que são especificados nas chamadas auxiliares HTML. As chamadas auxiliares HTML usam um ponto porque é assim que ViewData.Eval () funciona. Finalmente, ViewData.Eval () usa um ponto porque é assim que se separa um objeto e sua propriedade nas principais linguagens do .NET Framework. Usar um delimitador diferente de um ponto em qualquer ponto desta cadeia o fluxo para toda a cadeia ".
226126 Simon_Weaver
0

Resolvi o problema com a solução dada pelo jquery docs

Minha função:

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

function jq(myid){


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


}

Nota: removo o "#" porque no meu código concato o ID com outro texto

Fonte: Jquery Docs seleciona elemento com caracteres especiais

Gabriel Molina
fonte