Q:

Add class to element when scrolled into view (scrollable div)

Is there a solution for adding a class to the element in view when scrolling, and removing when out of view? This needs to work for a scrollable div. I have found a few solutions so far but they only seem to work for body... not a scrollable div.
I am happy to use a plugin if you know one exists. Something like this...
if ($('.journal-slider .each-slide img').inViewport() ) {
    $(this).addClass('in-view');
} else {
   $('.journal-slider .each-slide img').removeClass('in-view');
}

Thanks,
R

A:

You could make your own jQuery plugin to do this. Something like this which takes two functions (whenInView, whenNotInView):
$('.journal-slider .each-slide img').inViewport(
    function(){$(this).addClass("am-in-view");},
    function(){$(this).removeClass("am-in-view");}
);

It tests on scroll (or resize) wether the target elements are currently within the viewport and calls the related function. 
Here's the whole thing as a demo Snippet. In this example I have added an animation to the .am-in-view class so that you can see it working as the elements enter the viewport. This has not been tested on anything other than Chrome so far. Feel free to use and improve.

/*! inViewport 0.0.1 
 *  jQuery plugin by Moob
 * ======================== 
 *  (requires jQuery) 
 */  
(function ($) {

    var vph=0;
    function getViewportDimensions(){
        vph = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
    }
    getViewportDimensions();    
    //on resize/scroll
    $(window).on('resize orientationChanged', function(){
        getViewportDimensions();
    });            
    
    $.fn.inViewport = function (whenInView, whenNotInView) {                  
        return this.each(function () {
            var el = $(this),
                inviewalreadycalled = false,
                notinviewalreadycalled = false;                            
            //on resize/scroll
            $(window).on('resize orientationChanged scroll', function(){
                checkInView();
            });               
            function checkInView(){
                var rect = el[0].getBoundingClientRect(),
                    t = rect.top,
                    b = rect.bottom;
                if(t<vph && b>0){
                    if(!inviewalreadycalled){
                        whenInView.call(el);
                        inviewalreadycalled = true;
                        notinviewalreadycalled = false;
                    }
                } else {
                    if(!notinviewalreadycalled){
                        whenNotInView.call(el);
                        notinviewalreadycalled = true;
                        inviewalreadycalled = false;
                    }
                }
            }
            //initial check
            checkInView();                
        });
    }             
}(jQuery));
html, body {
    margin:0;
}
.me, .not-me {
    padding:20px;
    border:1px solid #aaa;
    margin:20px;
}
.am-in-view {
    background-color:pink;
    -webkit-transition: all 1500ms;
    -moz-transition: all 1500ms;
    -o-transition: all 1500ms;
    transition: all 1500ms;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="me">
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Eveniet, pariatur.</p>
    <p>Saepe, eligendi nihil totam dolorum reprehenderit! Repellat omnis neque quasi.</p>
    <p>Eos cumque voluptatum placeat eius nisi facere neque nesciunt praesentium.</p>
    <p>Eos qui consectetur voluptatem eum, labore accusamus tempora distinctio sunt?</p>
</div>
<div class="me">
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Excepturi, sit.</p>
    <p>A veritatis quis quae totam accusamus repellendus adipisci corporis soluta.</p>
    <p>Debitis animi dolor distinctio ratione dolorum ex aperiam maiores fugit?</p>
    <p>Incidunt non consequatur porro provident recusandae sunt architecto repellat enim.</p>
</div>
<div class="me">
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis, reprehenderit?</p>
    <p>Neque tempora perferendis dolor, mollitia debitis sunt voluptas ea ut!</p>
    <p>Maiores earum officia corporis, sint voluptatem, in laboriosam perferendis asperiores?</p>
    <p>Odit dolor voluptate laboriosam voluptatem accusamus aperiam explicabo at provident.</p>
</div>
<div class="not-me">
    <p>I'm totally normal</p>
</div>
<div class="me">
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ullam, accusamus.</p>
    <p>Quisquam architecto repellat facere amet sapiente dolore obcaecati harum fuga.</p>
    <p>Tempora labore, unde necessitatibus ipsam repellat architecto, aliquam autem at.</p>
    <p>Sapiente quis doloremque a illum, repellat, eius corporis ab placeat.</p>
</div>
<div class="me">
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Voluptate, assumenda!</p>
    <p>Nesciunt corrupti, eaque dolores ut libero ipsam dolorem laudantium saepe.</p>
    <p>Similique quisquam quod esse expedita, voluptate quia nobis? Cum, tempore.</p>
    <p>Amet voluptatem eaque non, praesentium tenetur molestias minima architecto laboriosam?</p>
</div>
<div class="me">
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Tempore, ex?</p>
    <p>Perferendis hic, sint maxime similique quia autem cum quasi? Sed.</p>
    <p>Nemo ratione aliquid itaque est blanditiis aliquam maiores veniam ab!</p>
    <p>Reiciendis cumque fugit earum ea animi et aut molestiae dolores!</p>
</div>

<!-- how to call it -->
<script>
    $(function(){
      
        $('.me').inViewport(
            function(){$(this).addClass("am-in-view");},
            function(){$(this).removeClass("am-in-view");}
        );
      
    });
</script>

A:

The plugin you are looking for is called waypoints
Quote from the "Get Started" :
"Let's say you have a div with overflow:scroll, and you want a waypoint inside of this scrollable element. The context option lets you do this. Scroll the box below."
$('#example-context').waypoint(function() {
    notify('Hit top of context');
}, { context: '.example-scroll-div' });

EDIT: Not using waypoints
Based on what you already did, I came to this :

function  checkInView(elem,partial)
{
    var container = $(".scrollable");
    var contHeight = container.height();
    var contTop = container.scrollTop();
    var contBottom = contTop + contHeight ;
 
    var elemTop = $(elem).offset().top - container.offset().top;
    var elemBottom = elemTop + $(elem).height();

    var isTotal = (elemTop >= 0 && elemBottom <=contHeight);
    var isPart = ((elemTop < 0 && elemBottom > 0 ) || (elemTop > 0 && elemTop <= container.height())) && partial ;

    return  isTotal  || isPart ;
}

$(document).ready(function(){
$(".scrollable").scroll(function(){
    var result="",result2="";
   $.each( $(".scrollable p"),function(i,e){
       if (checkInView($(e),false)) {
           $( this ).addClass( "red" );
       } else {
           $( this ).removeClass( "red" );
       }
        result += " " +  checkInView($(e),false);
       result2 += " " +  checkInView($(e),true);
    });
    $("#tt").text(result);
    $("#kk").text(result2);
});
});
.scrollable{
    margin:10px;
    height:100px;
    overflow-y:scroll;
}
p
{
    border-width:1px;
    border-color:black;
    border-style:solid;
}
.red {
    background-color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
full:  <div id="tt"></div>
part: <div id="kk"></div>
<div class="scrollable">
    <p>item1<span></span></p>
    <p>item2<span></span></p>
    <p>item3<span></span></p>
    <p>item4<span></span></p>
    <p>item5<span></span></p>
    <p>item6<span></span></p>
    <p>item7<span></span></p>
    <p>item8<span></span></p>
</div>

