开发者

JQuery won't toggle if id is a number

This is a fragment of an html doc my app has generated from a webserver log file:

<div class='ip' id='220.181.108.95'>
  <h3>220.181.108.95</h3>
  <h4 class='records' id='220.181.108.95'>
    Records:
  </h4>
  <div class='records' id='220.181.108.95'>
    <div class='record' id='220.181.108.95'>
      <p>ip: 220.181.108.95 timestamp: 15/Jun/2011:21:21:14 +0100 access_request_type: GET page: / status_code: 200 </p>
    </div>

    <div class='record' id='220.181.108.95'>
      <p>ip: 220.181.108.95 timestamp: 13/Jun/2011:08:18:09 +0100 access_request_type: GET page: / status_code: 200 </p>
    </div>

    <div class='record' id='220.181.108.95'>
      <p>ip: 220.181.108.95 timestamp: 12/Jun/2011:13:23:11 +0100 access_request_type: GET page: / status_code: 200 </p>
    </div>
  </div>
</div>

<div class='ip' id='123.125.71.60'>
  <h3>123.125.71.60</h3>
  <h4 class='records' id='123.125.71.60'>
    Records:
  </h4>
  <div class='records' id='123.125.71.60'>
    <div class='record' id='123.125.71.60'>
      <p>ip: 123.125.71.60 timestamp: 11/Jun/2011:04:19:31 +0100 access_request_type: GET page: /stylesheet.css status_开发者_如何转开发code: 200 </p>
    </div>  
  </div>
</div>

Here is some JQuery I've been using to toggle the records div:

<script>
      $(document).ready(function(){
            $("h4.records").click(function(){
                  var id = $(this).attr("id");
                  $("div#".concat(id, ".records")).toggle();
            });
      });
</script>

I've two problems with the way it's functioning:

  1. It only works when the id is a letter or string of letters. Numbers and dots stop the toggle working. Replace the id's with "a" and "b" respectively and it toggles.
  2. It may toggle, but then it toggles all divs with a class of "record:, even though I've passed in elem#id.class as the selector to toggle.

Is there a way I can keep the id as the ip-address (which is the obvious unique reference for the record) and toggle only the exact div by class and id and not all divs with that class?

Any help is much appreciated. I know several languages but it's rare I write in javascript, and I've not used JQuery before.

JQuery version is 1.6.1, JQueryUI is also being loaded, version 1.8.13.


Some quick notes:

  1. Pretty much everyone had a hand in getting me to the code I'm using now, so it's unfortunate I can only pick one correct answer.
  2. @Liangliang Zheng's answer works, but didn't work once I added in a "hide on load" javascript function, so @Matt Ball gets the tick for a more flexible solution.
  3. I've started to use a custom attribute for the ip address, thanks to @Dhruva Sagar and @Liangliang Zheng for suggesting it.
  4. Ip addresses elsewhere are now prefixed, thanks to @James Khoury for that suggestion.
  5. I've no idea why anyone would get downvoted for their answers, they're all at least partially correct.

I've put the solution to work in an app for reading webserver access logs and checking their geographical info via the ip, the code is up on Github if anyone's interested https://github.com/yb66/GeoIPalise. I'll give everyone here props with the next git push! Thanks to you all!


The problem is twofold:

  1. As I commented on the question, you're trying to select an element by ID when that ID contains characters which have special meaning. You need to escape those characters, or use document.getElementByID.
  2. As @Dhruva points out, the DOM must not contain elements with duplicate IDs. Use a class instead, or strip out the duplicate IDs entirely. Once the DOM contains more than one element with a given ID, all bets are off, and Cthulhu will probably be summoned shortly thereafter.

All that said, you can just use .closest() and forget about element IDs entirely.

HTML

<div class='ip' id='220.181.108.95'>
  <h3>220.181.108.95</h3>
  <h4 class='records'>
    Records:
  </h4>
  <div class='records'>
    <div class='record'>
      <p>ip: 220.181.108.95 timestamp: 15/Jun/2011:21:21:14 +0100 access_request_type: GET page: / status_code: 200 </p>
    </div>

    <div class='record'>
      <p>ip: 220.181.108.95 timestamp: 13/Jun/2011:08:18:09 +0100 access_request_type: GET page: / status_code: 200 </p>
    </div>

    <div class='record'>
      <p>ip: 220.181.108.95 timestamp: 12/Jun/2011:13:23:11 +0100 access_request_type: GET page: / status_code: 200 </p>
    </div>
  </div>
</div>

<div class='ip' id='123.125.71.60'>
  <h3>123.125.71.60</h3>
  <h4 class='records'>
    Records:
  </h4>
  <div class='records'>
    <div class='record'>
      <p>ip: 123.125.71.60 timestamp: 11/Jun/2011:04:19:31 +0100 access_request_type: GET page: /stylesheet.css status_code: 200 </p>
    </div>  
  </div>
</div>

JavaScript

$(function(){
    $("h4.records").live('click', function(){
        $(this).closest('div.ip').find('div.records').toggle();
    });
});

Other WTFs:

  • Use this.id instead of $(this).attr('id'). (See When to use Vanilla JavaScript vs. jQuery?)
  • Specifying an element type along with an ID is completely unnecessary since, as mentioned, IDs must be unique.
  • .concat()? Really? What's wrong with + (the concatenation operator)?

(No personal offense meant. It's the code, not you.)

Demo: http://jsfiddle.net/mattball/fE9Xf/


In HTML multiple nodes can't have the same 'id'. That is the problem here. Instead of id, you should use some other attribute, perhaps a data-id and it should work then.


The issue is that when you are try to select $('#220.181.108.95'), what jQuery is querying the DOM for is:

Element with id of 220 and classes 181, 108 and 95
eg. <div id="220" class="181 108 95"></div>

To fix this, you need to escape the periods in the selector. To do this, you need to add a \\, as per: http://api.jquery.com/category/selectors/

So your selector needs to be $('#220\\.181\\.108\\.95')

You can do this easily by using a replace().

id.replace('.','\\.');
See edit...

Also, id's should be unique.

EDIT:

As Matt Bell links to, there is a better and preferred way to do this (which I did not know)

function jq(myid) { 
   return '#' + myid.replace(/(:|\.)/g,'\\$1');
}

would be used:

$( jq('220.181.108.95') )

http://docs.jquery.com/Frequently_Asked_Questions#How_do_I_select_an_element_by_an_ID_that_has_characters_used_in_CSS_notation.3F


I would recommend you to use custom attribute instead of id.

<div class='record' ip='1.2.3.4'><p></p></div>

Therefore, in your js, you can :

$('div.record[ip="' + target_ip + '"]').toggle();


http://www.w3.org/TR/html40/types.html#type-name

Id's must start with a letter. From the w3c:

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 (".").

I suggest you add "ip" to the beginning of the id's (e.g id='ip220.181.108.95')

EDIT as noticed by some others that you have multiple id's i suggest you name the first one with an id and the child records can be access in jQuery by

jQuery("div#id .records").toggle();

this will toggle all elements inside your div with the specified id.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜