-2

I'm having some issues figuring out why my click function isn't working.

I have a JSFiddle for it here: http://jsfiddle.net/adbakke/ve9oewvh/

My html breaks down like so (condensed for posting here):

<div class="projectDisplay"></div>

<div class="flex-grid project-list">

   <div id="project1" class="project">
      <div class="projectImg"><img></div>
      <div class="projectDesc">
        <h3>title</h3>
        <p>Description</p>
        <span>click to close</span>
      </div>
   </div>

Now my JQuery gets all that HTML under "project" like so:

$('.project').click(
   function() {
     var newGet = $(this).html();

Then there's a bunch of functions (that all work beautifully) to add this data to <div class="projectDisplay"></div>, and replace it all if there's already something there.

Then when I want to close the project by hitting <span> click to close</span>, it works fine when I click the first item, but if I click a second before closing it does not work.

Edit: Click one image, then (before hitting close), click a second image in the project list, and then attempt to click "close project".

My close function looks like so:

$('.closeMe').click(
  function() {
    $('.projectDisplay').fadeOut(500);
  }
);

I have tried putting it both inside and outside the scope of my click function itself. Neither will allow me to have it close upon clicking a second time to open up a different project.

What am I missing?

Update: Updated JSFiddle base so you can tell the different sections are different.

ChaBuku Bakke
  • 685
  • 1
  • 7
  • 24
  • Just did a chrome inspect element on the close button and found out that for the first time there is a click event listener attached to the button and rightly so. But somehow the event listener disappears. – Jay Oct 10 '14 at 13:51
  • 2
    your writing html dinamically, you have to rebind the event after writing the html. – Mathieu Labrie Parent Oct 10 '14 at 13:51
  • Why do you feel the need to keep serializing existing elements into HTML and then creating new elements from that after destroying the old ones? Seems like it would make more sense just to move the existing elements around. –  Oct 10 '14 at 13:59
  • @squint: I don't want to take them out of the context of the page I suppose – ChaBuku Bakke Oct 10 '14 at 13:59
  • @MelanciaUK: The question needs a clear step-by-step to replicate the issue. To see the issue, click a project, and then without closing it, scroll down and click another. Then try to close the new one. –  Oct 10 '14 at 14:09
  • @ChaBuku: What do you mean by taking them out of the context of the page? They can stay right where they are. Just relocate the current one into the `projectDisplay` and put it back when done. –  Oct 10 '14 at 14:10
  • Comments removed because they were not constructive. A single one then: Possible duplicate of [Event binding on dynamically created elements?](http://stackoverflow.com/questions/1359018/in-jquery-how-to-attach-events-to-dynamic-html-elements) – emerson.marini Oct 10 '14 at 14:12
  • @squint: Perhaps my understanding isn't full, wouldn't 'relocating' move the actual div into the upper div and remove it from the lower, changing the lower section itself by removing the div? Or would 'relocating' as you are suggesting simply copy it? – ChaBuku Bakke Oct 10 '14 at 14:14
  • 1
    If you wanted to keep the selected one in the list, then you'd clone it, which would make it even easier. You'd just use `.clone(true)`, which copies the elements and handlers. I personally would rework it so that you're not having to keep creating the buttons since that's where the handlers are. Just keep those in the `projectDisplay` and hide them when there's nothing to show. –  Oct 10 '14 at 14:17
  • Brilliant! Thank you. I'm just getting started on learning this, mostly by studying the API. I'll rework it using your suggestion. – ChaBuku Bakke Oct 10 '14 at 14:18

3 Answers3

3

Instead of:

$('.closeMe').click(

Which will bind the click event for all .closeMe elements present in the DOM at that moment

use:

$(document).on('click', .closeMe,

Which will bind the click event to body and then delegate it to .closeMe, meaning that it will fire for .closeMe elements added dynamically even after the initial binding.

i.e

  $(document).on('click', '.closeMe',
    function() {
      $('.projectDisplay').fadeOut(500);
    }
  );

Try it at http://jsfiddle.net/L4Lmf6zy/1/

Robert Falkén
  • 2,287
  • 2
  • 16
  • 16
  • Why this is downvoted ? it's probably the answer to this question ... ( p.s you should use $(document) as default target element because body could be floated etc and couldn't be click in sometime – Sebastien B. Oct 10 '14 at 13:51
  • Just for my learning purposes, the order of what's happening in this is: $selector.on(action, selectorForAction, function to perform on action --- ? Am I thinking of that correctly? – ChaBuku Bakke Oct 10 '14 at 13:58
  • 1
    @MelanciaUK Open the jsFiddle, click the first image in the list, then click the second in the list. After the fade animation, try to 'Close project', it doesn't work (in Chrome). – Robert Falkén Oct 10 '14 at 14:08
  • Going to mark this as the answer, though due to @Squirt I'm going to rewrite this entire thing. *Which is the reason I asked this question, to get a better understanding*. I'd like to delete it too so I don't garner any more down votes. – ChaBuku Bakke Oct 10 '14 at 14:20
  • @ChaBuku I don't fully understand your question in the comment. But yeah, in your example the $selector should be something that will always be present in the DOM that can delegate your event, and selectorForAction is the selector that you actually want to handle your event. – Robert Falkén Oct 10 '14 at 14:25
1

You should delegate the click event on .clickMe because you are adding the button dynamically on every opening of a project.

Working example here http://jsfiddle.net/ve9oewvh/3/

So you should use

$(document).on('click', '.closeMe',
    function() {
      $('.projectDisplay').fadeOut(500);
    }
);
Bojan Petkovski
  • 6,835
  • 1
  • 25
  • 34
1

The problem is you are removing all child nodes when you click on another project and you are not rebinding the click function. You need to rebind the click event with the new HTML.

$(document).ready( function () {
// Hide the Description, Close Button and Link to Site
  $('.projectDesc a, .projectDesc p, .projectDesc span').hide();

// What happens when you click the project button
  $('.project').click(
    function() {
      var newGet = $(this).html();

      if ($('.projectDisplay').is(':empty')) {
      // Add the description section if empty
        $(newGet).hide().appendTo('.projectDisplay').fadeIn(500);
        $('.projectDisplay .projectDesc a, .projectDisplay .projectDesc p, .projectDisplay .projectDesc span').fadeIn(250);
      } else {
      // If description is not empty, fade out, empty and add new project description
        $('.projectDisplay').fadeOut(500, function (){
          $('.projectDisplay').empty().append(newGet).fadeIn(250);
          $('.projectDisplay .projectDesc a, .projectDisplay .projectDesc p, .projectDisplay .projectDesc span').fadeIn(250);
            $('.closeMe').click(
        function() {
          $('.projectDisplay').fadeOut(500);
        }
      );
        })
      };

      $('html, body').animate({
          // scrollTop: $(".projectDisplay").position().top
          scrollTop: $(".projectDisplay").offset().top - 200
      }, 750);

      $('.closeMe').click(
        function() {
          $('.projectDisplay').fadeOut(500);
        }
      );


    });
});
// End of Project Click Function
Travis Pettry
  • 1,220
  • 1
  • 14
  • 35