186

Given the following classes and controller action method:

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

And the following form:

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

I am able to update both the School instance and the Address member of the school. This is quite nice! Thank you ASP.NET MVC team!

However, how do I use jQuery to select the drop down list so that I can pre-fill it? I realize that I could do this server side but there will be other dynamic elements on the page that affect the list.

The following is what I have so far, and it does not work as the selectors don't seem to match the 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);
    });
  });
});
Keavon
  • 6,837
  • 9
  • 51
  • 79
Doug Wilson
  • 4,185
  • 3
  • 30
  • 35

8 Answers8

309

From Google Groups:

Use two backslashes before each special character.

A backslash in a jQuery selector escapes the next character. But you need two of them because backslash is also the escape character for JavaScript strings. The first backslash escapes the second one, giving you one actual backslash in your string - which then escapes the next character for jQuery.

So, I guess you're looking at

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

Also check out How do I select an element by an ID that has characters used in CSS notation? on the jQuery FAQ.

Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
bdukes
  • 152,002
  • 23
  • 148
  • 175
  • 4
    I wonder what the rationalization is for requiring the developer to do this, it seems like a simple set of heuristics within jQuery would solve this problem, since there isn't anything wrong with ID's with periods in them... – Jason Bunting Mar 24 '09 at 22:46
  • 6
    If you didn't have to escape, how would you query an element with ID Address and class State (granted that if you know the ID you aren't adding much by specifying the class, but it should still be valid, I'd think)? – bdukes Mar 25 '09 at 13:12
  • 13
    For that reason, in CSS itself, you must escape a dot in an ID, too. All jQuery is doing is requiring you to follow the rules set out by CSS. – bdukes Apr 06 '09 at 14:11
  • 7
    You could also select by name instead of ID. For example, $('[name="Address.Country"]') – Funka Aug 20 '09 at 04:03
25

You can't use a jQuery id selector if the id contains spaces. Use an attribute selector:

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

If possible, specify element type as well:

$('div[id=foo bar]').show();
Elliot Nelson
  • 11,371
  • 3
  • 30
  • 44
  • I prefer doing it this way than using the escape characters.... Obviously the best workaround is not to use periods in the id. – GordonBy Jul 13 '10 at 14:01
  • Spaces are not allowed in id's, not even in HTML5's more liberal acceptance of characters. http://stackoverflow.com/questions/70579/what-are-valid-values-for-the-id-attribute-in-html – Jay Blanchard Jun 05 '13 at 20:52
  • True, but whether they are _allowed_ or not doesn't matter to the poor sap who's stuck adding window dressing to a poorly-written web app deployed in the late 90s. – Elliot Nelson Jun 06 '13 at 17:55
  • 4
    there must be quates in order to work:` $( "div[id='"+variable+"']" )` or ` $( "div[id='foo bar' ]" ) ` – olga Sep 11 '16 at 23:39
  • As @olga said, the answer isn't legal any more. Specifically, you'll get an error message "Uncaught Error: Syntax error, unrecognized expression: div[id=foo bar]" – James Moore Aug 24 '17 at 15:19
  • bear in mind that using an attribute selector will bypass the index on id, making this much slower than going directly after the element by id – Ross Kerr Aug 23 '19 at 17:56
  • 1
    space != period – aross Mar 31 '21 at 08:52
13

Escape it for Jquery:

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

usage example:

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

more info here.

  • 3
    The solution as per the jQuery docs is adding only one "\" (slash). alert(escapeSelector("some.id")); will output as some\.id. So I guess the replace regex should have been s.replace( /(:|\.|\[|\])/g, "\\\\$1" ); – Arun Apr 30 '15 at 10:35
  • I have the same issue, why doesn't anyone else see this? – TruthOf42 Dec 13 '19 at 20:21
9

The Release Candidate of ASP.NET MVC that was just released fixed this issue, it now replaces the dots with underscores for the ID attribute.

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

Renders to

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

For more information view the release notes, starting on page 14.

Dale Ragan
  • 18,202
  • 3
  • 54
  • 70
  • 1
    I fail to see how this is a "fix" - why should ASP.NET MVC have to change the ID to something jQuery needs? I think jQuery is where the problem lies, not using a . in an ID. – Jason Bunting Mar 24 '09 at 22:41
  • 7
    the dot has special meaning in CSS to identify/combine classes, which is why having it in an ID is troublesome. The "problem" is not with jquery. – Funka Aug 20 '09 at 04:02
8

This is documented in jQuery Selectors docs:

To use any of the meta-characters (such as !"#$%&'()*+,./:;<=>?@[\]^`{|}~) as a literal part of a name, it must be escaped with with two backslashes: \\. For example, an element with id="foo.bar", can use the selector $("#foo\\.bar").

In short, prefix the . with \\ as follows:

$("#Address\\.Country")

Why doesn't . work in my ID?

The problem is that . has special significance, the string following is interpreted as a class selector. So $('#Address.Country') would match <div id="Address" class="Country">.

When escaped as \\., the dot will be treated as normal text with no special significance, matching the ID you desire <div id="Address.Country">.

This applies to all the characters !"#$%&'()*+,./:;<=>?@[\]^`{|}~ which would otherwise have special significance as a selector in jQuery. Just prepend \\ to treat them as normal text.

Why 2 \\?

As noted in bdukes answer, there is a reason we need 2 \ characters. \ will escape the following character in JavaScript. Se when JavaScript interprets the string "#Address\.Country", it will see the \, interpret it to mean take the following character litterally and remove it when the string is passed in as the argument to $(). That means jQuery will still see the string as "#Address.Country".

That's where the second \ comes in to play. The first one tells JavaScript to interpret the second as a literal (non-special) character. This means the second will be seen by jQuery and understand that the following . character is a literal character.

Phew! Maybe we can visualize that.

//    Javascript, the following \ is not special.
//         | 
//         |
//         v    
$("#Address\\.Country");
//          ^ 
//          |
//          |
//      jQuery, the following . is not special.
Jon Surrell
  • 9,444
  • 8
  • 48
  • 54
3

Using two Backslashes it´s ok, it´s work. But if you are using a dynamic name, I mean, a variable name, you will need to replace characters.

If you don´t wan´t to change your variables names you can do this:

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

and than you have your jquery object.

Daniel
  • 2,780
  • 23
  • 21
1

I solved the issue with the solution given by jquery docs

My function:

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

function jq(myid){


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


}

Note: i remove the "#" because in my code i concat the ID with another text

Font: Jquery Docs select element with especial chars

brodoll
  • 1,851
  • 5
  • 22
  • 25
0

Just additional information: Check this ASP.NET MVC issue #2403.

Until the issue is fixed, I use my own extension methods like Html.TextBoxFixed, etc. that simply replaces dots with underscores in the id attribute (not in the name attribute), so that you use jquery like $("#Address_Street") but on the server, it's like Address.Street.

Sample code follows:

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
  • 9,289
  • 3
  • 33
  • 62
  • 1
    from the abovementioned issue: "UpdateModel() uses a dot because that's how the form elements come in. The form elements use a dot because that's how they're specified in the HTML helper calls. The HTML helper calls use a dot because that's how ViewData.Eval() works. Finally, ViewData.Eval() uses a dot because that's how one separates an object and its property in the main .NET Framework languages. Using a delimiter other than a dot at any point in this chain would break the flow for the entire chain." – Simon_Weaver Dec 16 '12 at 00:06