Scroll a container on initial load in an Angular app - javascript

I have a container which animates its scrollTop to the bottom whenever a new item is added. The markup looks something like this:
<div class="scrolly">
<div class="item" ng-repeat="item in items" ng-animate=" 'scroll-to-bottom' ">
{{item.value}}
</div>
</div>
This works great when adding new items, but on the initial page load, the container is scrolled to the top. I'd like to figure out the right way to have the scrollTop set to the bottom on initial page load.
Example jsFiddle: http://jsfiddle.net/bkad/JnwCP/

The trick is to add some delay when you populate the data like this :)
$timeout(function () {
for (var i = 0; i < 20; i++)
$scope.items.push({
value: i
})
}, 10);
Demo

I ended up using scrollGlue which implements this as a directive.

Related

Bootstrap UI Carousel function wont run within tab

Using Bootstrap UI for Angular, I need to gather the index of the slide being displayed, which I can then use to gather data in order to display content in a separate container.
Following this exact example I can log the index of the slide. And when I replicate it in my own environment, it works.
The issue I am having is that I have inserted the carousel within a tabset also provided by Bootstrap UI, like so:
<uib-tabset active="activePhaseTab" type="pills">
<uib-tab heading="Blue" index="3" ng-click="$ctrl.phaseSlide = 3;$ctrl.phaseSliderInfo($ctrl.phaseSlide)">
<div style="height: 305px">
<div uib-carousel active="activeSlide" interval="myInterval" no-wrap="noWrapSlides">
<div uib-slide ng-repeat="slide in slides track by slide.id" index="slide.id">
<img ng-src="{{slide.image}}" style="margin:auto;">
<div class="carousel-caption">
<h4>Slide {{slide.id}}</h4>
<p>{{slide.text}}</p>
</div>
</div>
</div>
</div>
</uib-tab>
</uib-tabset>
Without encapsulating the carousel within the tabs, I was able to use the $watch method on the activeSlide, but now the carousel is within the tabs, it is failing to do so.
Question
How do I $watch for change on 'activeSlide' within the tabset?
$scope.myInterval = 3000;
$scope.noWrapSlides = false;
var slides = $scope.slides = [];
var currIndex = 0;
$scope.addSlide = function() {
var newWidth = 600 + slides.length + 1;
slides.push({
image: '//unsplash.it/' + newWidth + '/300',
text: ['Nice image','Awesome photograph','That is so cool','I love that'][slides.length % 4],
id: currIndex++
});
};
for (var i = 0; i < 4; i++) {
$scope.addSlide();
}
$scope.$watch('activeSlide', function (active) { //SHOULD LOG THE ACTIVE SLIDE
if(active !== undefined) {
console.log(active)
console.log('slide ' + active + ' is active');
}
});
Your initial plunker link has this weird syntax error, so I made another one using the Bootstrap UI examples.
I fit in the carousel demo within the tabset pill demo.$scope.$watch('activeSlide'... did fail. But thankfully this specific scenario has been answered before in this stackoverflow question.
So I just followed their suggestions and tried out their directive. Now every slide change is monitored by on-carousel-change="onSlideChanged(nextSlide, direction)". You can check the console of the plunker below and play around with it however you like.
Here's the plunker
Hope that helps!

If element is scrolled on data-attribute then

I have two headers (menu1 - default, menu2 - display:none).
In sections of website I added special attribute (data-ix="change-header").
I want to have the effect.. that if I will scroll site and if we scrolled on section where data-ix="change-header" then header will be other - so menu1 will be display:none and menu2 will be display:block;
I have something like that, but I don't know how I can use scroll.
if ($(this).attr("data-ix") == "change-header"){
$("‪#‎menu1‬").css("display","none");
$("‪#‎menu2‬").css("display","block");
} else {
$("#menu1").css("display","block");
$("#menu2").css("display","none");
}
My html looks like that:
<header id="menu1"></header>
<header id="menu2"></header>
<div class="test" data-ix="change-header"></div>
<div class="test"></div>
<div class="test" data-ix="change-header"></div>
<div class="test" data-ix="change-header"></div>
<div class="test" data-ix="change-header"></div>
<div class="test"></div>
<footer></footer>
Help :)
You can take a look at this: http://janpaepke.github.io/ScrollMagic/
It's only 6Kb gzipped, and it lets you animate elements or toggle CSS classes based on scroll position :)
You can compute the threshold values at which you will change header (or not). Something like this
var thresholds = [];
$('.test').each(function(i, e) {
// after we scroll past the top coordinate of this element,
// either show or hide the second header, based on the presence
// of the data-ix attribute
thresholds.push([e.offsetTop, $(e).data('ix') === 'change-header']);
});
Then, consult these thresholds on every scroll event
// cache menu elements
var $menu1 = $('#menu1'), $menu2 = $('#menu2');
// update header once, and listen on scroll
update();
$(window).on('scroll', update);
function update() {
// pick first visible threshold
var scrollTop = $(this).scrollTop(), thresh;
for (var i = 0, len = thresholds.length; i < len; ++i) {
thresh = thresholds[i];
if (thresh[0] >= scrollTop) break;
}
// update header as necessary
if (thresh[1]) {
$menu1.hide();
$menu2.show();
} else {
$menu2.hide();
$menu1.show();
}
}
Here is a working Plunker.

Changing html tag structure on window resizing

I would like to rebuild an html tag structure to a new one on resizing the browser window. Have anyone an idea how can I get from the first structure to the second structure. I need this for an responsive personal project. Maybe with an JavaScript resize Event, I don't know...
<div class="wrapper">
<div class="slide">
<div class="item"></div>
<div class="item"></div>
</div>
<div class="slide">
<div class="item"></div>
<div class="item"></div>
</div>
</div>
<div class="wrapper">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
You could listen to the resize event on the window and then restructure your HTML when the window is below a certain size. Moving elements from the first structure to the second isn't a big problem, however the challenge lies in reverting that again. How will you know which of the .item's belonged to which .slide?
One way to do this is to keep track of the parent for each .item in a separate data- attribute when you make the list:
function makeList() {
var $slides = $('.slide'),
$items = $();
// For each slide set a data-attribute on all its child .item's
$slides.each(function(i) {
var $item = $(this).children('.item');
$item.attr('data-slide', i+1);
$items = $items.add($item);
});
// Append all items directly to the wrapper
$('.wrapper').html($items).attr('data-structure', 'list');
}
I set a data attribute to the .wrapper so we know that it's already converted to a list. Otherwise on every resize this would be fired, you only want it once (until it resizes back to where you want the slides).
When you want the slide again, loop through all the .items and keep a list of slide number's. For each new data-slide number you encounter make a new slide and add that to the total list;
function makeSlides() {
var $slides = $(),
slideNumbers = [],
$currentSlide = $();
$('.item[data-slide]').each(function() {
var $item = $(this),
slideNumber = $item.attr('data-slide');
// if the slide number wasn't in the array yet push the current slide into $slides and create a new one
if(slideNumbers.indexOf(slideNumber) < 0) {
$slides = $slides.add($currentSlide);
$currentSlide = $('<div class="slide" />');
slideNumbers.push(slideNumber);
}
$currentSlide.append($item);
});
// add the last currentSlide
$slides = $slides.add($currentSlide);
// place all slides in the wrapper
$('.wrapper').html($slides).attr('data-structure', 'slides');
}
Then finally you bind the resize event and fire these functions when needed:
$(window).resize(function(e) {
var currentStructure = $('.wrapper').attr('data-structure');
if(window.innerWidth < 600) {
if( currentStructure !== 'list') {
makeList();
}
} else {
if( currentStructure !== 'slides') {
makeSlides();
}
}
});
jsFiddle demo: http://jsfiddle.net/gktLnw31/3/
I do think this could be a bit more efficient, but this is just a proof of concept. Hopefully it'll give you some insights.
I would better take a look at foundation since it already includes the responsive design by default instead of trying to change it dynamically by code

JQuery jCarousel with paging dots?

I was using jCarousel plugin to display a series of items. I was following this example from the web site to get external controls and a paging control.
There's two problems with this approach:
i need to add the items for the numbers manually (instead of just calculating the number of items in the carousel with JS), although I can live with this, and
There seems to be no way to highlight (via a class change) the item for the current slide
What I am doing is using bullets as paging dots, as you can see in this fiddle
<div class="carousel-nav cf">
<table>
<tr>
<td>◀</td>
<td>
<div class="jcarousel-control">
•
•
•
</div>
</td>
<td>►</td>
</tr>
</table>
</div>
and would like to set the class to "active" or similar for the current item.
Any ideas? Or is there a better plugin for this? I tried Cycle but I need two have 2 or more items showing at once. Thanks.
html:
<ul class="jcarousel-control"></ul>
script:
$('.jcarousel-control')
.on('jcarouselpagination:active', 'li', function() {
$(this).addClass('active');
})
.on('jcarouselpagination:inactive', 'li', function() {
$(this).removeClass('active');
})
.jcarouselPagination({
'perPage':1,
'item': function(page, carouselItems) {
return '<li class="' + (page == 1 ? "active" : "") + '"></li>';
}
});
$('.mycarousel-prev').jcarouselControl({target:'-=1'});
$('.mycarousel-next').jcarouselControl({target:'+=1'});
actually you can use call back function for higlighting respective to current active carousel element
function highlighttab1(carousel, state, liindex) {
document.getElementById(liindex).className = "selected";}
function removehighlighttab1(carousel, state, liindex) {
document.getElementById(liindex).className = "unselected";}
few days ago i worked with jcarousel where i had menu label panel (as you have dots) and all static hyperlinks which when clicked will scroll to the intendent carousel element

Getting SmoothDivScroll to start at the center of the scrollable area

I'm trying to get jQuery plugin SmoothDivScroll (http://www.smoothdivscroll.com/) to start at the center of its contained content so there are scrollbars to the left and right on load. I'm aware that there's a startAtElementId option, but this doesn't allow me to start at the center.
I've tried calculating the centerpoint and applying it to the appropriate elements, but the left scroll always stops before it's expected to and the right elements float underneath.
Tried using this Js with no luck:
$("div#scroller").smoothDivScroll();
var halfWayDoc = $(document).width() / 2;
var halfWayScrollArea = $("#scroller .scrollableArea").width() /2;
var halfWay = halfWayDoc - halfWayScrollArea;
var scrollArea = $("#scroller .scrollableArea").width();
var scrollAreaAdjust = scrollArea + halfWay;
$("#scroller .item:first-child").css("margin-left",halfWay);
$("#scroller .item:last-child").css("margin-right",halfWay);
$("#scroller .scrollableArea").width(scrollAreaAdjust);
HTML looks like this:
<div id="scroller">
<div class="scrollingHotSpotLeft"></div>
<div class="scrollingHotSpotRight"></div>
<div class="scrollWrapper">
<div class="scrollableArea">
<div class="item">
<img src="assets/images/detail/Erdem-A-W-11-B2-sml.jpg" alt="example"/>
</div>
...
<div class="item">
<img src="assets/images/detail/Erdem-A-W-11-B2-sml.jpg" alt="example"/>
</div>
</div>
</div>
</div>
Any help or pointers are appreciated.
Cheers,
Shaun
Here is the solution that I suggest :-)
// Element for Scroll
var scrollElement = $("div#scroller");
// Enable Smooth Div Scroll
scrollElement.smoothDivScroll();
// Find out Scrollable area's width
var halfWidth = $("div#scroller .scrollableArea").width()/2;
// Force scroller to move to half width :-)
scrollElement.data("scrollWrapper").scrollLeft(halfWidth);
I update the fiddle, so you can take a look at this update one:
http://jsfiddle.net/3A9Zy/
I hope this helps :-)
The basic sample in the site http://www.smoothdivscroll.com/index.html#quickdemo is having the functionality implemented. The animation starts from an image with ID "startAtMe"
$("div#makeMeScrollable").smoothDivScroll({ autoScroll: "onstart",
autoScrollDirection: "backandforth",
autoScrollStep: 1,
autoScrollInterval: 15,
startAtElementId: "startAtMe",
visibleHotSpots: "always" });
. Did you try by specifying an id to the element you want to start with and passing the startAtElementId: "startAtMe" to the smoothDivScroll function?

Categories