user2387319
user2387319

Reputation: 123

selecting <div> using jQuery

I asked here a big question 1 day ago, but didn't get enough good answers, so I divided the question into parts. This is one part:

Have a look at this code:

<?php
    foreach($tickets as $key=>$value)
           {
?>
               <div id="topic_<?php echo $key;?>"  data-id="<?php echo $key;?>" onclick="showDetails()">
                   ------------------------------
               </div>
               <div id="details_<?php echo $key;?>"  data-id="<?php echo $key;?>">
                   ------------------------------
               </div>
<?php
           }
?>

Here, we have some <div>s ("topic_..." and "details_..."), each with unique id(data-id). We don't know how much of these <div>s will be there, because of the foreach() loop. All "details" <div>s will be hidden at the first time. Now, what I want, when I click on a "topic" <div>, its corresponding "details" <div> will be shown. I think I should use a function and call that function in the onclick event, that's why I used onclick="showDetails()" in the "topic" <div>. If I am wrong or you have a better idea, please share with me. Here is the Javascript code:

<script>
    $(document).ready(function(){
           $("#details_").hide();
    });
    function showDetails()
    {
        var id=$(this).attr('data-id');
        $("#details_"+id).show();
    }
</script>

I know I couldn't detect all "details_......" <div>s here, and may be there are also some problems in the showDetails() function. Please help me.

Thanks guys.

Upvotes: 2

Views: 696

Answers (6)

Jason M. Batchelor
Jason M. Batchelor

Reputation: 2951

Above and beyond all of these things, you really really really don't need to have onclick inside your divs. Please, just don't do it.

Consider instead something like this:

<?php
foreach($tickets as $key=>$value)
       {
?>
           <div id="topic_<?php echo $key;?>"  data-id="<?php echo $key;?>">
               ------------------------------
           </div>
           <div id="details_<?php echo $key;?>"  data-id="<?php echo $key;?>">
               ------------------------------
           </div>
<?php
       }
?>

Note that I got rid of onclick... Now, in your js:

// set up your doc-ready code...
$(function(){
    var showDetails = function(evt)
    {
        var id= $(this).data('id');
        $("#details_"+id).show();
    };
    // now bind all divs that start with topic_ with a click event, with showDetails as the handler
    $('div[id^=topic_]').on('click',showDetails);
});

NOW, great, hunky dory, but can't we get even better than this?? I think we can! If you have the power to choose a tag structure, choose one that gives you nesting as part of its logical semantic markup, so that your markup has meaning...

First, let's choose logical markup:

<dl class="topicslist">
<?php
foreach($tickets as $key=>$value)
       {
?>
           <dt data-id="<?php echo $key;?>">
               ------------------------------
           </dt>
           <dd data-id="<?php echo $key;?>">
               ------------------------------
           </dd>
<?php
       }
?>
</dl>

CSS:

.topiclist dd {
    display:none;
    margin:0 0 1em;
    padding:0;
}

.topiclist dd.show {
    display:block;
}

JS!

// set up your doc-ready code...
$(function(){
    var showDetails = function()
    {
        // find the next sibling dd to this object and show it!
        $(this).next('dd').show();
    };
    // now bind all divs that start with topic_ with a click event, with showDetails as the handler
    $('dl dt').on('click',showDetails);
});

It's not too many steps from that to making one function that can also toggle the show/hide!

// set up your doc-ready code...
$(function(){
    var toggleDetails = function(){
        var mySib = $(this).next('dd');
        ($(mySib).hasClass('show')) ? $(mySib).removeClass('show') : $(mySib).addClass('show');
    };

    $('.topiclist dt').on('click',toggleDetails);
});

With this in mind, really, you don't even need to have the data-id in your markup at all... as long as you always arrange your list so that the dt is first and directly followed by a dd, this should work.

http://jsfiddle.net/mori57/nqyRX/

Upvotes: 0

officert
officert

Reputation: 1232

It sounds like what you are trying to do is an accordion. Each Topic div is the accordion header, each Details div is the accordion body. When you click on a Topic div its corresponding Details div will open up. You can easily find a jQuery plugin for accordions that will provide this kind of functionality.

But if you don't want a plugin you could do something like this:

1) Add a class to the topic divs, class="topic"

2) Add a class to the details divs, class="details"

$(document).ready(function() {
    var details = $('div.details');
    var topics = $('div.topics');
    details .hide();        //hide all the details divs
    topics .click(function() {
        details.hide();     //hide any open details    
        $(this).next('div.details').show();   //or you could use slideDown()/fadeIn()
    };
});

This code assumes that each topic div will have a details div right after it. If you don't want the details divs to hide each time you click a topic div, just remove the details.hide() line.

Upvotes: 0

Adil
Adil

Reputation: 148180

You need to pass the source of event to function using this.

Html

<div id="topic_<?php echo $key;?>" 
        data-id="<?php echo $key;?>" onclick="showDetails(this)">

Javascript

function showDetails(obj)
{
    var id=$(obj).attr('data-id');
    $("#details_"+id).show();
}

If you bind the event using jQuery then you can use this inside handler

$('[id^=topic_]').click(function(){
    var id=$(this).attr('data-id');
    $("#details_"+id).show();
});

Upvotes: 1

VVV
VVV

Reputation: 7603

First off, you want to hide all the divs. Either add a css class like "hidden" and set the display to none or go with jquery with something like this

$('div[id^="details_"]').hide();

Then, the showDetails function needs to know which item needs to be shown. Instead of having the onclick on every single item, I suggest you use jquery.

(This is not necessary but is an alternative to what you have)

$('div[id^="details_"]').click(function() {
    $("#details_"+ $(this).attr('data-id')).show();
    // or as Diodeus suggested
    // $(this).next('div').show().
});

In sum, you can put all of this in the document ready method

$(document).ready(function() {
    $('div[id^="details_"]').hide();
    $('div[id^="details_"]').click(function() {
        $("#details_"+ $(this).attr('data-id')).show();
    });
})

Upvotes: 0

Diodeus - James MacFarlane
Diodeus - James MacFarlane

Reputation: 114417

You can avoid all of this ID nonsense by using relative selectors.

showDetails(this) <--- send a refernce to the current element

function showDetails(element) {
      $(element).next('div').show().
}

Upvotes: 2

km6zla
km6zla

Reputation: 4907

$('div[id^=details_]') will get you all divs where the id starts with the string details_

Upvotes: 0

Related Questions