o_O
o_O

Reputation: 5737

Appending HTML with click function jQuery not working

http://jsfiddle.net/CCKUz/

So I have a box with a <span class="open"> that will increase the height of a collapsible div to view the content. It's collapsible simply by CSS height and the open click function sets height to auto. Easy and this works.

The problem happens when I go to append the open and close spans. When I include them in the actual html, they work fine. When I append them, they no longer function. I thought maybe this was due to not being available for the js to apply the .click function to them since they were created after the load but even creating them and applying the .click in the same function doesn't help this problem.

Is there anything you see there that might be affecting this? Thanks.

HTML:

<div class="box collapsible">
    <h3>Title</h3>
    <p>This is a sample paragraph that is here for placer purposes.</p>
</div>

CSS:

.box { height: 20px; border: 1px solid #000000; padding: 10px; margin: 20px; position:   relative; overflow: hidden; }
h3 { margin: 0 0 20px 0; line-height: 20px; }
.open, .close { text-indent: -9999px; width: 20px; height: 20px; position: absolute; top:  10px; right: 10px; }
.open { background: #00ff00; }
.close { background: #0000ff; }

JS:

$(function(){
        var box = $(".collapsible");
        var close = $(".collapsible span.close");
        var open = $(".collapsible span.open");
        box.each(function(){
            box.append('<span class="open">Open</span>');
            open.each(function(i){
                open.click(function(){
                    alert("You clicked open");
                    $(this).parent(box).css("height","auto").append('<span class="close">Close</span>');
                    $(this).hide();
                    $(this).parent().find(close).show();
                });
            });
            close.each(function(i){
                close.click(function(){
                    $(this).parent(box).css("height","15px");
                    $(this).hide();
                    $(this).parent().find(open).show();
                });
            });
        });
    });

Upvotes: 0

Views: 179

Answers (4)

adeneo
adeneo

Reputation: 318182

No need for loops, jQuery does that internally, and you need delegated event handlers with dynamic elements, like so:

$(function () {
    var box = $(".collapsible");
    box.append( $('<span />', {'class':'open'}) )
       .on('click', '.close', function () {
         $(this).hide()
                .closest('.collapsible')
                .css("height", "auto")
                .append( $('<span />', {'class':'close'}).show() );
    })
      .on('click', '.close', function () {
          $(this).hide()
                 .closest('.collapsible')
                 .css("height", "15px")
                 .find('.open').show();
    });
});

Upvotes: 2

loganfsmyth
loganfsmyth

Reputation: 161457

The problem is that you are adding your .close spans dynamically, so your initial search will not find anything, so it will not add any click handlers to them. You can use event delegation to fix this easily.

.on('click', 'span.close', function(evt){

You can also simplify your code a lot:

$(".collapsible")
  .append('<span class="open">Open</span>')
  .on('click', 'span.open', function(evt){
    // Search within the parent '.collapsible'.
    $(evt.delegateTarget)
      .css("height", "auto")
      .append('<span class="close">Close</span>');

    // Hide the '.open' span.
    $(this).hide();
  })
  .on('click', 'span.close', function(evt){
    // Search within the parent '.collapsible'.
    $(evt.delegateTarget)
      .css("height","15px");
      .find('.open').show();

    // Remove the old '.close' button since the
    // open handler will make a new one.
    $(this).remove();    
  })

Upvotes: 0

El Hocko
El Hocko

Reputation: 2606

you select the open-elements before adding them:

var open = $(".collapsible span.open");

Try this:

$(function(){
        var box = $(".collapsible");
        var close = $(".collapsible span.close");

        box.each(function(){
            box.append('<span class="open">Open</span>');
            var open = $(".collapsible span.open"); //do it here!!
            open.each(function(i){
                open.click(function(){
                    alert("You clicked open");
                    $(this).parent(box).css("height","auto").append('<span class="close">Close</span>');
                    $(this).hide();
                    $(this).parent().find(close).show();
                });
            });
            close.each(function(i){
                close.click(function(){
                    $(this).parent(box).css("height","15px");
                    $(this).hide();
                    $(this).parent().find(open).show();
                });
            });
        });
    });

Upvotes: 1

Anton
Anton

Reputation: 32581

There is no need for .each delegate the function

$(document).on('click','.collapsible span.open',function(){

demo here http://jsfiddle.net/CCKUz/2/

Upvotes: 0

Related Questions