When do I need to escape metacharectars? (jQuery Selectors) - javascript

According to the jQuery docs, I need to escape metacharacters that occur in my selector strings, when they occur as a literal. However, I couldn't find very many specific examples of when and when not to escape selectors. So when and when don't I need to escape metacharacters, when they are to be interpreted as a literal, in:
Attribute selectors? ie
$("[attr=value]")
Id selectors? ie
$("#id")
Class selectors? ie
$(".class");
And, is there a way to write a function that replaces metachars in selector strings, while still preserving the beginning character? ie:
// replace all meta chars, preserving the id selection?
$("#id.rest$of*string")
// replace all meta chars, preserving the attribute selection?
// going back to my previous question, do I even need to escape the metachars in this situation?
$("[attr=blah.dee#foo*yay]")
The reason I ask this question, is because I'm working with a website that happens to have some really nasty selectors. And I don't have control over the website, so I can't go change the selectors to be nicer to work with.
THANKS!!

From the jQuery docs:
If you wish to use any of the meta-characters (#;&,.+*~':"!^$=>|/ ) as a literal part of a name, you must escape the character with two backslashes ...
All of these must be escaped:
id
class name
attribute name
attribute value
element name
The first four are obvious, and here's an example for the fifth. Element names in XML can contain a "." character for instance and still be valid.
<user.name>John Doe</user.name>
If you had to select all elements of user.name, then that . must be escaped
$(xml).find("user\\.name");

Rather than blatantly stealing someone else's answer, I'll point you to it: jQuery selector value escaping, where jQuery's selector parsing method is described in detail.
The short answer: you may be in trouble since jQuery's selector parser is not 100% standards-complaint. Per the suggestion in the linked answer, you may be able to workaround by calling the regular DOM methods (document.getElementById()), which will work with funny selectors, and then pass the raw DOM element to the jQuery selector.
$(document.getElementById("id.rest$of*string"));

Related

jQuery Escaping Special Characters Fails

I am trying to make a jQuery selector to select, by an arbitrary id, an html element. The ids may contains special characters that need to be escaped. An example is test_E///_AAAAA
I am basically doing exactly what is going on in this working fiddle (which uses v 1.11.0, where I am using v 1.11.3 and have also tested with 2.1.3)
However, in my scaled up environment, it doesn't work. I get Syntax error, unrecognized expression: #test_E\\/\\/\\/_AAAAA
There must be some obscure factoid about jQuery that is the difference between this working and not working. I, being a novice, have no hope of identifying it.
I notice that I am not alone though. A commentator on this thread had the same issue.
The code files are thousands of lines long, and I'm probably prohibited from posting more than a couple lines by my employer. I'm just looking for a hint, a clue, a shot in the dark about what would cause a perfectly reasonable selection string to be rejected.
You just need enough backslashes :)
ID:
The ID of the element is test_E\\/\\/\\/_AAAAA. Note that backslashes don't have any special meaning in HTML, so there really are six backslashes in the ID.
jQuery selector: Backslashes, forward slashes, and several other characters have special meaning in jQuery selectors, so we need to escape them with a backslash. The selector therefore needs to be #test_E\\\\\/\\\\\/\\\\\/_AAAAA. This tells jQuery to look for an element whose ID contains test_E, then two backslashes, then one forward slash, and so on.
JavaScript string literal: To represent that selector using a JavaScript string literal, each backslash needs to be escaped. So the string literal would be "#test_E\\\\\\\\\\/\\\\\\\\\\/\\\\\\\\\\/_AAAAA".
var selectionString = "#test_E\\\\\\\\\\/\\\\\\\\\\/\\\\\\\\\\/_AAAAA";
snippet.log("actual id: " + $("p")[0].id);
snippet.log("selection string given to jQuery: " + selectionString);
snippet.log("text: " + $(selectionString).text());
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<!-- Provides the `snippet` object, see http://meta.stackexchange.com/a/242144 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
<p id="test_E\\/\\/\\/_AAAAA">This is a test :)</p>
As you can see, this is extremely ugly, hard to understand, and hard to get right. I highly recommend avoiding such IDs. Another option is to use good old document.getElementById(), which only requires the string literal escapes:
$(document.getElementById('test_E\\\\/\\\\/\\\\/_AAAAA')).text()
The code in the fiddle doesn't work either. I have tried it in IE, Firefox and Chrome, and neither of them finds the element.
You need to escape a slash to use it in a # selector. If you use a backslash, you have to escape it twice, once to put it in a string, and once for the selector.
To match the id test\A you need the selector #test\\A which as a string is "#test\\\\A".
To match the id test/A you need the selector #test\/A which as a string is "#test\\/A".
To match the id test_E\\/\\/\\/_AAAAA you need the selector #test_E\\\\\/\\\\\/\\\\\/_AAAAA which as a string is "#test_E\\\\\\\\\\/\\\\\\\\\\/\\\\\\\\\\/_AAAAA".
Demo: https://jsfiddle.net/Guffa/463849xj/4/
Generally you should avoid unusual characters in an identity. Even if you can make it work, there is still a risk that some browser handles it differently.
Update:
The error message is shown with the selector unescaped, so as the error message shows the selector #test_E\\/\\/\\/_AAAAA it means that you actually use the string "#test_E\\\\/\\\\/\\\\/_AAAAA". That leaves the slashes unescaped, which causes the syntax error.

Selecting elements with exotic id [duplicate]

This question already has answers here:
jquery exotic id selection
(2 answers)
Closed 9 years ago.
I'm working on a legacy system that uses square brackets in id parameters. E.g.:
<select id="mySelect[]">
<option value="1">Yadda</option>
<option value="2">Yadda</option>
<option value="3">Yadda</option>
</select>
jQuery (being javaScript) quite rightly complains when I try to use this id in, say,
$("#mySelect[]").append(options);
Given the fact that I can't change the legacy code and therefore I'm stuck with the existing id's (which may or may not be valid in any context), what would be a good way to work around this mess and let me select my elements?
While using meta characters you have to escapse those.
$("#mySelect\\[\\]").append(options);
Jquery selector docs saying that
To use any of the meta-characters ( such as !"#$%&'()*+,./:;<=>?#[]^`{|}~ ) as a literal part of a name, it must be escaped with with two backslashes: \.
If you don't want to escape it, you can use the selector
$( document.getElementById('mySelect[]')
Try this way:
$("#mySelect\\[\\]").append(options);
You need to escape [ and ] as they are reserved jquery chars used in selectors.
Have a look at the jquery 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").
and a fiddle here
Plus ofcourse you could do this $('[id="mySelect[]"]') But since it is an attribute selector performance wise this will be slower and you lose the advantage of using the id selector, but handy if you are in no way to escape the chars.
Try this jsfiddle link.
Both of the below work fine:
console.log($('[id^=mySelect]'));
console.log($('#mySelect\\[\\]'));

javascript/jQuery can't find element with messed up id

I'm trying to access an element in MS CRM 2011 with the following id:
account|NoRelationship|Form|B_GenerateInvoice-Large
I can see this element in the IE developer tools:
Unfortunately I always get null when trying to find this element.
I've tried the following:
alert(document.getElementById('account|NoRelationship|Form|B_GenerateInvoice-Large'));
alert($("[id='account|NoRelationship|Form|B_GenerateInvoice-Large]").html());
alert($(jq("account|NoRelationship|Form|B_GenerateInvoice-Large")).html()); // jq() adds the '#' and escapes special characters
alert($("#account|NoRelationship|Form|B_GenerateInvoice-Large").html());
alert(document.getElementById("#account\\|NoRelationship\\|Form\\|B_GenerateInvoice-Large"));
alert($("#account\\|NoRelationship\\|Form\\|B_GenerateInvoice-Large").html());
These all fail to find the element.
Am I missing something obvious here?
Solution:
The javascript was inside an iframe while the element was outside of the iframe..
I did not manage to solve it.
The jQuery Manual on Selectors states:
If you wish to use any of the
meta-characters ( such as
!"#$%&'()*+,./:;<=>?#[]^`{|}~ ) as a
literal part of a name, you must
escape the character with two
backslashes: \\. For example, if you
have an element with id="foo.bar", you
can use the selector $("#foo\\.bar").
The W3C CSS specification contains the
complete set of rules regarding valid CSS selectors.
So try this one:
$('#account\\|NoRelationship\\|Form\\|B_GenerateInvoice-Large')...
jsFiddle Demo
EDIT: I have successfully tested my Fiddle in Chrome, Firefox 4, IE9, IE8 and IE7, it works fine.
It may be a bug in browser, since HTML5 specification allows any character except spaces in id attribute
ID #
Any string, with the following restrictions:
must be at least one character long
must not contain any space characters
however, it is encrouaged not to put any weired character in id attribute, only number, letter and underscore there:)
From the jQuery documentation:
If you wish to use any of the meta-characters ( such as !"#$%&'()*+,./:;<=>?#[]^`{|}~ ) as a literal part of a name, you must escape the character with two backslashes: \. For example, if you have an element with id="foo.bar", you can use the selector $("#foo\.bar").
So this should work:
alert($("#account\\|NoRelationship\\|Form\\|B_GenerateInvoice-Large").html());
And it does, indeed: http://jsfiddle.net/Cdz9w/
What version of HTML is the page declaring that it's using? Because that's a valid HTML5 id, but it's an invalid HTML4.01 and earlier id. (It's also an invalid CSS id, which is vaguely relevant if you use something like jQuery to look it up, as jQuery uses CSS selectors.)
The fiddle in #bazmegakapa's answer works for me on Chrome, but perhaps your page is declaring a different version of HTML, or perhaps a less-advanced browser doesn't like it, etc.

Find DOM element by ID when ID contains square brackets?

I have a DOM element with an ID similar to:
something[500]
which was built by my Ruby on Rails application. I need to be able to get this element via jQuery so that I can traverse my way up the DOM to delete the parent of it's parent, which has a variable ID that I don't have access to beforehand.
Does anyone know how I could go about this? The following code doesn't seem to be working:
alert($("#something["+id+"]").parent().parent().attr("id"));
Upon further inspection, the following:
$("#something["+id+"]")
returns an object, but when I run ".html()" or ".text()" on it, the result is always null or just an empty string.
You need to escape the square brackets so that they are not counted as attribute selectors. Try this:
alert($("#something\\["+id+"\\]").parent().parent().attr("id"));
See Special Characters In Selectors, specifically the second paragraph:
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"). The W3C CSS specification contains the complete set of rules regarding valid CSS selectors. Also useful is the blog entry by Mathias Bynens on CSS character escape sequences for identifiers.
You can also do
$('[id="something['+id+']"]')
An id cannot include square brackets. It is forbidden by the spec.
Some browsers might error correct and cope, but you should fix you data instead of trying to deal with bad data.
Square brackets have special meaning to jQuery selectors, the attribute filters specifically.
Just escape these and it will find your element fine
$( "#something\\[" + id + "\\]" )
Try this:
alert($("#something\\["+id+"\\]").parent()[0].parent()[0].attr("id"));
You can escape them using \\ or you could do something like this...
$(document.getElementById("something[" + id + "]"))
"Any of the meta-characters
!"#$%&'()*+,./:;<=>?#[\]^`{|}~
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")
" [source: jquery doc], and an element with id="foo[bar]" (even though not valid for W3C but recognised by JQuery), can use the selector
$("#foo\\[bar\\]")
(Just an asnwer like the many others, but all together :))

Javascript and CSS, using dashes

I'm starting to learn some javascript and understand that dashes are not permitted when naming identifiers. However, in CSS it's common to use a dash for IDs and classes.
Does using a dash in CSS interfere with javascript interaction somehow? For instance if I were to use getElementByID("css-dash-name"). I've tried a few examples using getElementByID with dashes as a name for a div ID and it worked, but I'm not sure if that's the case in all other contexts.
Having dashes and underscores in the ID (or class name if you select by that) that won't have any negative effect, it's safe to use them. You just can't do something like:
var some-element = document.getElementByID('css-dash-name');
The above example is going to error out because there is a dash in the variable you're assigning the element to.
The following would be fine though since the variable doesn't contain a dash:
var someElement = document.getElementByID('css-dash-name');
That naming limitation only exists for the javascript variables themselves.
It's only in the cases where you can access the elements as properties that it makes a difference. For example form fields:
<form>
<input type="text" name="go-figure" />
<input type="button" value="Eat me!" onclick="...">
</form>
In the onclick event you can't access the text box as a property, as the dash is interpreted as minus in Javascript:
onclick="this.form.go-figure.value='Ouch!';"
But you can still access it using a string:
onclick="this.form['go-figure'].value='Ouch!';"
Whenever you have to address a CSS property as a JavaScript variable name, CamelCase is the official way to go.
element.style.backgroundColor = "#FFFFFF";
You will never be in the situation to have to address a element's ID as a variable name. It will always be in a string, so
document.getElementById("my-id");
will always work.
Using Hypen (or dash) is OK
I too is currently studying JavaScript, and as far as I read David Flanagan's book (JavaScript: The Definitive Guide, 5th Edition) — I suggest you read it. It doesn't warn me anything about the use of hypen or dash (-) in IDs and Classes (even the Name attribute) in an HTML document.
Just as what Parrots already said, hypens are not allowed in variables, because the JavaScript interpreter will treat it as a minus and/or a negative sign; but to use it on strings, is pretty much ok.
Like what Parrots and Guffa said, you can use the following ...
[ ] (square brackets)
'' (single quotation marks or single quotes)
"" (double quotation marks or double quotes)
to tell the JavaScript interpreter that your are declaring strings (the id/class/name of your elements for instance).
Use Hyphen (or dash) — for 'Consistency'
#KP, that would be ok if he is using HTML 4.1 or earlier, but if he is using any versions of XHTML (.e.g., XHTML 1.0), then that cannot be possible, because XHTML syntax prohibits uppercase (except the !DOCTYPE, which is the only thing that needs to declared in uppercase).
#Choy, if you're using HTML 4.1 or earlier, going to either camelCase or PascalCase will not be a problem. Although, for consistency's sake as to how CSS use separators (it uses hypen or dash), I suggest following its rule. It will be much more convinient for you to code your HTML and CSS alike. And moreoever, you don't even have to worry if you're using XHTML or HTML.
IDs are allowed to contain hyphens:
ID and NAME tokens must begin with a letter ([A-Za-z]) and may be followed by any number of letters, digits ([0-9]), hyphens ("-"), underscores ("_"), colons (":"), and periods (".").
And there is no restriction when using IDs in JavaScript except if you want to refer to elements in the global scope. There you need to use:
window['css-dash-name']
Other answers are correct as far as where you can and can't use hyphens, however at the root of the question, you should consider the idea of not using dashes/hyphens in your variable/class/ID names altogether. It's not standard practice, even if it does work and requires careful coding to make use of it.
Consider using either PascalCase (all words begin in capital) or camelCase (first word begins in lowercase, following words being in uppercase). These are the two most common, accepted naming conventions.
Different resources will recommend different choices between the two (with the exception of JavaScript which is pretty much always recommended camelCase). In the end as long as you are consistent in your approach, this is the most important part. Using camel or Pascal case will ensure you don't have to worry about special accessors or brackets in your code.
For JavaScript conventions, try this question/discussion:
javascript naming conventions
Here's another great discussion of conventions for CSS, Html elements, etc:
What's the best way to name IDs and classes in CSS and HTML?
It would cause an error in this case:
const fontSize = element.style.font-size;
Because including a hyphen prevents the property from being accessed via the dot operator. The JavaScript parser would see the hyphen as a subtraction operator. Correct way would be:
const fontSize = element.style['font-size']
No, this won't cause an issue. You're accessing the ID as a string (it's enclosed in quotes), so the dash poses no problem. However, I would suggest not using document.getElementById("css-dash-name"), and instead using jQuery, so you can do:
$("#css-dash-name");
Which is much clearer. the jQuery documentation is also quite good. It's a web developers best friend.

Categories

Resources