Search code examples
javascriptjqueryscrolljquery-waypoints

Showing a div when scrolling to it


I am somewhat familiar with waypoints and tried setting it up to work for the following.

I am trying to get #bundler-offer to display after the user clicks on the radio button for Option 2. The blue div #bundle-offer should fade in, however the waypoints is registering on page load - as you can see in the console.

What do I have to do to only get the waypoints to show when the #review-main is in view?

Jsfiddle

var package1 = $('#package1');
var package2 = $('#package2');
$('.product').on('change', function() {
  if (package1.is(':checked')) {
    console.log("Option - Package 1");
    $('#pack2-details').hide();
    $('#pack1-details').show();
  } else if (package2.is(':checked')) {
    console.log("Option - Package 2");
    $('#pack2-details').show();
    $('#pack1-details').hide();
  }
});
$('#review-main').waypoint(function() {
  // handler: function(direction) {
  $('#bundle-offer').addClass('fadeUp');
  console.log('Scrolled to waypoint!');
}, {
  offset: '100%'
});
.check {
  display: none;
}

.wrap {
  background: green;
  height: 600px;
  width: 100%;
}

#bundle-offer {
  position: fixed;
  bottom: -120px;
  left: 0;
  right: 0;
  width: 100%;
  height: 120px;
  background: blue;
  opacity: 0;
  transition: all 0.5s ease;
}

#bundle-offer.fadeUp {
  opacity: 1;
  transition: all 0.5s ease;
  bottom: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/waypoints/4.0.1/jquery.waypoints.min.js"></script>
<label>Option 1</label>
<input type="radio" class="product" id="package1">
<label>Option 2</label>
<input type="radio" class="product" id="package2">
<div id="pack1-details" class="check">
  <p>Package 1</p>
  <div class="wrap" id="pack1-details">
    Package 1 showing
  </div>
</div>
<div id="pack2-details" class="check">
  <p>Package 2</p>
  <div class="wrap" id="pack2-details">
    Package 2 showing
    <div id="review-main">
      <div id="bundle-offer">Working IF fading in</div>
    </div>
  </div>
</div>


Solution

  • This is covered in the waypoints debugging documentation and also addressed elsewhere on SO.

    Here's the explanation from waypoints:

    [...] When Waypoints is calculating the trigger point, it doesn't have a way to find the would-be-if-not-display-none position. The resulting calculation ends up incorrect, often with sporadic values.

    You should never use a display:none element as a waypoint. This includes elements that gain display:none at any time in the lifetime of your page, as trigger points are recalculated whenever a refresh occurs, such as a window resize event.

    [and because of this, you're waypoint function is firing on page load]

    If you utilize opacity to hide the element, rather than display:none, waypoints should be able to locate the element:

    Example from waypoints

    $('.something')
      .css('opacity', 0) // immediately hide element
      .waypoint(function(direction) {
        if (direction === 'down') {
          $(this.element).animate({ opacity: 1 })
        }
        else {
          $(this.element).animate({ opacity: 0 })
        }
      }, {
        offset: 'bottom-in-view'
      });
    

    If you implement this into your code and change the css on page load accordingly, you should get the behavior you're looking for.

    Edit:

    While not elegant, I think this code snippet essential applies the waypoint documentation to your issue. It may not be a perfect solution for your use-case, but certainly responds to your comment below.

    fiddle

    Here's what's changed in a nutshell:

    1. Instead of "show/hide" this code uses "opacity"
    2. The waypoint trigger element is added through jQuery (and removed,) otherwise the zero opacity element still occupies space and triggers the waypoint. The same thing could be accomplished by binding/unbinding the waypoint
    3. Some of the css/html needed cleaning up - if avoidable, try not to use more than one instance of the same element id (you should never have this problem if it's all your own html.)
    4. Used a "name" field on your radio inputs so only one can be selected at a time.

    And, code for posterity:

    $("input[name='prod_op']").on('change', function() {
      console.log($(this).attr('id'));
      if ($(this).attr('id') === "package1" && $('#pack1-container').css('opacity', 0)) {
        console.log('selected 1');
        $('#pack1-container').css({
          'opacity': 1,
          'height': '600px'
        });
        $('#pack2-container').css({
          'opacity': 0,
          'height': '0px'
        });
        $('#pack2-details').empty();
      } else if ($(this).attr('id') === "package2" && $('#pack2-container').css('opacity', 0)) {
        console.log('selected 2');
        $('#pack2-container').css({
          'opacity': 1,
          'height': '600px'
        });
        $('#pack1-container').css({
          'opacity': 0,
          'height': '0px'
        });
        $('#pack2-details').append('Package 2 showing <div id="review-main"><div id="bundle-offer" class="hide">Working IF fading in</div></div>');
        setWaypoint();
      }
    });
    
    var setWaypoint = function(){
      var waypoint = new Waypoint({
        element: $('#review-main'),
        handler: function(direction){
          if(direction === "down"){
            console.log('waypoint... down');
            $('#bundle-offer').removeClass('hide fadeDown').addClass('fadeUp');
          } else if(direction === "up") {
            console.log('waypoint... up');
            $('#bundle-offer').removeClass('fadeUp').addClass('fadeDown');
            console.log('waypoint... down');
          }
        },
        //offset: '600px'
      });
    }
    .hide {
      opacity: 0;
      height: 0px;
    }
    
    .wrap {
      background: green;
      height: 600px;
      width: 100%;
      display: block;
    }
    
    #bundle-offer {
      position: fixed;
      left: 0;
      right: 0;
      width: 100%;
      height: 120px;
      background: blue;
      transition: all 0.5s ease;
    }
    
    
    .fadeUp {
      opacity: 1;
      transition: all 0.5s ease;
      bottom: 0;
    }
    
    .fadeDown{
      opacity: 0;
      transition: all 0.5s ease;
      bottom: 0;
    }
    
    .page_wrap{
      min-height: 1000px;
      background-color: pink;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/waypoints/4.0.1/jquery.waypoints.min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <div class="page_wrap">
    
      <label>Option 1</label>
      <input type="radio" class="product" name="prod_op" id="package1" />
      <label>Option 2</label>
      <input type="radio" class="product" name="prod_op" id="package2" />
    
      <div id="pack1-container" class="hide">
        <p>Package 1</p>
        <div class="wrap" id="pack1-details">
          Package 1 showing
        </div>
      </div>
    
      <div id="pack2-container" class="hide">
        <p>Package 2</p>
        <div class="wrap" id="pack2-details">
        </div>
      </div>
    </div>