views:

229

answers:

5

I have a set of DOM elements that I want to show only when a controlling checkbox is checked by the user. All of these items have a common class and are initially hidden:

 .spec { display:none; }

In the click handler of the checkbox, I originally had the following, which worked fine for existing elements. However, the tables are dynamically generated via AJAX, and when new elements are added with the "spec" class, they are not displayed when the checkbox is checked.

// Basic jQuery show/hide
if (btn.checked)
    $('.spec').show();
else
    $('.spec').hide();

Since in my case this is in the same JS module, I could always just re-execute this code after adding to the DOM. But in general, that may not be true, so my question is:

What is the normal jQuery way to address this issue?

Since the jQuery show/hide functions alter the element.style and not the style object itself, I ended up writing a jQuery plugin that alters the stylesheet, which works fine, but seems like over kill, hence the question.

var nval = btn.checked ? '' : 'none';
$.styleSheet('.spec', 'display', nval );
A: 

Perhaps altering the class of the elements would be better. Then when you add elements in the DOM, you can assign them the proper class for the state the page is in.

Ned Batchelder
That occurred to me, but currently details of the template (from which the elements are created) aren't known by the JS code.
NVRAM
A: 

I know 2 solutions: 1) Use live for element which doesn't exist yet for example: `$('a .special').live("click", function(){...});

2) Use callback function of load. For example: $('p .special').load('x.html', {}, function(){ //search for new element and bind them new function. ...

IMHO second is better ;)

Rin
The elements themselves don't have event handlers, so I don't think **$.live()** works, does it? I'll look into .load() I didn't think it applied.
NVRAM
The *$.load()* function doesn't help since: (1) I'm creating HTML from XML returned by the server, and (2) it's not event handling, but visibility I'm wanting to change. See my post starting at "I could always just...".
NVRAM
A: 

It looks like you are testing if the btn is checked or unchecked when the doc loads. Instead of (or in addition to) this, add an event handler that fires whenever the checkbox is interacted with by the user. The change handler is the one you want. This will always use the current state of the DOM, and so it will include any newly added elements:

$(btn).change(function(){
  $('.spec').toggle();
});

For simplicity, I've used the toggle handler to change display:hidden to display:block/inline or vice versa. If you want to be explicit, you could do this:

$(btn).change(function(){
  $('.spec')[$(this).val() ? 'show' : 'hide']();
});
Premasagar
No, as I said, I do this "*In the click handler of the checkbox...*". And that wasn't the question, it's dynamic DOM elements.
NVRAM
Ah, indeed you did. Sorry I missed that.
Premasagar
A: 

You came up with two good solutions and shot them both down :)

If you're looking for a simple solution, re-running $(".spec").show() seems the best.

Otherwise, I don't see why is tweaking the stylesheet an overkill? It's exactly what should be done -- you want to control the presentation of all the elements with the given class, both existing and added dynamically. It's exactly what CSS is for.

Nickolay
Valid point -- but the "overkill" was writing a jQuery plugin when, so far, I've only needed this in one place, and as you point out I *could* add the show/hide call to the creation phase. But, since I wanted to keep the data-processing and UI separated and jQuery doesn't support SS modification, I asked: "What is the *normal* jQuery way to address this issue?"
NVRAM
+2  A: 

You should add a class to the <body> (or to some other parent element) for this purpose, and then toggle that class via jQuery.

CSS:

body.spec_is_hidden .spec {
  display: none;
}

JS:

if (btn.checked)
    $('body').addClass('spec_is_hidden');
else
    $('body').removeClass('spec_is_hidden');
Joel L
This works brilliantly, thanks. Seems obvious, but only in retrospect.
NVRAM
Since I want to hide them initially, and the body is defined externally so I used a DOM element to wrap the 'spec' elements with *hideStuff* that's defined: ` #wrapper.hideStuff .spec { display: none; }`
NVRAM
Rats, I spoke too soon. It *does not* work when the elements appear within a table in IE, since it's CSS inheritance is broken for tables. I guess I'm stuck with my `$styleSheet()` method.
NVRAM
Perhaps adding an extra CSS selector for IE would also help? (#wrapper.hideStuff table tr.spec {}, for example)
Joel L