On Dec 30, 8:00 pm, "Erik R. Peterson" <eriks...@mac.com> wrote:
> Wow...  I'm just now getting back to this and I am totally messed up.  
>
> I never thought it would be such a challenge.

It's not that this is a challenge.  There are many different
directions you could go from here.  You didn't supply a sample page or
your markup, so the only clues to what you wanted had to be divined
from your code and comments.  But the suggestions made were correct.

If you're interested, let me take you through some steps that you
might go through to make your code more robust.

First, I'm going to assume a markup format:

    <div class="entry">
      <h2>My Entry</h2>
      <p class="teaser">Teaser content</p>
      <p><a id="slick-toggle" href="#">More Details</a></p>
      <div id="content1">
        <p>Additional content</p>
        <p>More additional content</p>
        <p>Still more additional content</p>
      </div>
    </div>

Of course it's quite possible that you are using very different
markup, but this should be enough for demonstration.

I have a page with that markup and your code at:

    http://scott.sauyet.com/Javascript/Demo/2009-12-31a/1/


This page works as expected.  Now you want to extend this to other
DIVs, I've added several more "entry" sections here:

    http://scott.sauyet.com/Javascript/Demo/2009-12-31a/2/


The only markup change I made was to note that since every id must be
unique on the page, I changed the initial "slick-toggle" to "slick-
toggle1" to match the "content1", and I updated the JS to match.  This
might well be the issue you are having with independent DIVS.  If
you've repeated the "slick-toggle" id in your multiple entries, then
clicking on the first one would toggle all content sections.

Now we can update the script to handle all these.  This is not my
suggested way to do it, but it's a good first pass:

    function createToggler(contentId, linkId) {
        $('#' + contentId).hide();
        $('a#' + linkId).click(function() {
            $('#' + contentId).slideToggle(400);
            $(this).text($(this).text() == 'More Details' ? 'Close' :
'More Details');
            return false;
        });
    }
    $(document).ready(function() {
        createToggler('content1', 'slick-toggle1');
        createToggler('content2', 'slick-toggle2');
        createToggler('content3', 'slick-toggle3');
        createToggler('content4', 'slick-toggle4');
    });

You can see this in action at

    http://scott.sauyet.com/Javascript/Demo/2009-12-31a/3/


But there is something inconvenient about this, especially if the page
is to include generated content.  You have to include a separate
Javascript line for every section you want toggle-able.  You can get
around this if you have consistent markup like this, using the fact
that every entry is in a div with class "entry", and you can use code
like this:

    $(document).ready(function() {
        var count = $("div.entry").size();
        for (var i = 1; i <= count; i++) {
            createToggler('content' + i, 'slick-toggle' + i);
        }
    });

This is available at

    http://scott.sauyet.com/Javascript/Demo/2009-12-31a/4/


This can be extended further, by noting that the relationships between
the additional content and the link used to toggle it can be
determined by their relationship in the DOM.  We can remove the IDs
and replace them with appropriate classes.  So we can change the
markup to this:

    <div class="entry">
      <h2>My Entry</h2>
      <p class="teaser">Teaser content</p>
      <p><a class="slick-toggle" href="#">More Details</a></p>
      <div class="content">
        <p>Additional content</p>
        <p>More additional content</p>
        <p>Still more additional content</p>
      </div>
    </div>

And then we can simplify our script to just this:

    $(document).ready(function() {
        $('.content').hide();
        $('a.slick-toggle').click(function() {
            $(this).text($(this).text() == 'More Details' ? 'Close' :
'More Details')
                   .parent().nextAll(.content').slideToggle(400);
            return false;
        });
    });

By traversing the DOM from our link to its parent and from there to
the next sibling element that has class "content", we maintain the
relationship between the link and the additional content without
having to synchronize IDs.  This is at

    http://scott.sauyet.com/Javascript/Demo/2009-12-31a/5/


There is still one nagging issue here.  If you view this page with
Javascript turned off, the content is properly in place, but there are
these useless links on the page, all reading "More Details".  These
shouldn't be here unless the user has Javascript turned on and they
can actually do something.  One possible solution is to hide them with
CSS and show them with JS, but that still leaves them in the markup
for readers that aren't using JS or CSS.  A better choice might be to
add them in the first place using JS.  To do this, we can remove them
in the markup:

    <div class="entry">
      <h2>My Entry</h2>
      <p class="teaser">Teaser content</p>
      <div class="content">
        <p>Additional content</p>
        <p>More additional content</p>
        <p>Still more additional content</p>
      </div>
    </div>

Now that's clean markup!  We then have to add them in the Javascript,
so we can update to this:

    $(document).ready(function() {
        $('.content').hide().before('<p><a class="slick-toggle"
href="#">More Details</a></p>');
        $('a.slick-toggle').click(function() {
            $(this).text($(this).text() == 'More Details' ? 'Close' :
'More Details')
                   .parent().nextAll('.content').slideToggle(400);
            return false;
        });
    });

And of course this is at

    http://scott.sauyet.com/Javascript/Demo/2009-12-31a/6/


If you were really interested in taking this one step further, you
might consider making this a plug-in that you could include on
multiple pages, and that you might invoke like this:

    $('.content').superToggle({showText: 'More Details', hideText:
'Close'});

But I'm not going to take it that far here.  If you're interested,
Mike Alsup's tutorial is excellent:

    http://www.learningjquery.com/2007/10/a-plugin-development-pattern

This has been a long post, especially for one that started by saying
that the problem is not complex!  I still say that.  In fact, I spent
much more time typing the post than in creating pages with six
variations of your code and markup to match.

As you get more experience with jQuery, you will find yourself
starting with markup and code similar to this.  There is no real
complexity in it.  It's simply a matter of learning what you can
comfortably do with Javascript and with jQuery.

Cheers,

  -- Scott

Reply via email to