Scrolling and executing an event when needed - lazy loading - javascript

Let's imagine I want to make a social media application. I make a div to hold all my posts. When I start the application, I only query as many requests as will fit on the viewport. I append them as divs themselves. When the user scrolls to the point that they can see n more posts, n more posts are queried and appended to the div.
Or another, an application that you can infinitely scroll and generates random numbers for each div, using similar logic as above.
How can I implement this? I have no idea where to start, but right now what I think I might be able to get away with adding a scroll event. Here's some psuedocode of how that might look, but I'm not sure if I can do something like this (or if it's valid logic, because it's late at night):
unsigned lastY
document.addEventListener('scroll', () => {
// check if there is space to add more elements
if ((lastY - postsDiv.sizeY) != 0) { // yes, there is space to add more elements
// how many can we?
unsigned toAdd =
// (I am very, very unsure if this is correct)
floor(lastY - postsDiv.sizeY) * postsDiv.lengthInYOfEachElement;
}
lastY = window.scrollY
})
Is this even a good approach?

You can use element's scrollTop property to check for amount of height scrolled. When this amount gets past a certain percentage of element's visible scroll height, you can add your posts to the element.
In the example below, new numbers are added when user scrolls 90% (0.9) of the height.
let n = 50;
let i = 0;
let cont = document.querySelector(".container");
function generateNumbers(ini) {
for (var i = ini; i <= n + ini; i++) {
let span = document.createElement("span");
span.innerText = i;
cont.appendChild(span);
}
}
generateNumbers(i);
cont.addEventListener("scroll", () => {
if (cont.scrollTop >= (cont.scrollHeight - cont.clientHeight) * 0.9) {
i = n + 1;
n += 50;
generateNumbers(i);
}
});
.container {
display: flex;
flex-direction: column;
height: 200px;
overflow: scroll;
}
<div class="container">
</div>

You can do this easily with the Intersection Observer (IO)
Basically you set up your structure like this:
let options = {
rootMargin: '0px',
threshold: 0.9
};
target = document.querySelector('#js-load-more');
observer = new IntersectionObserver(entries => {
var entry = entries[0];
if (entry.isIntersecting) {
console.log('You reached the bottom of the list!');
appendMorePosts();
}
}, options);
observer.observe(target);
appendMorePosts = function() {
const post = document.createElement('div');
post.classList.add('post');
post.innerHTML = 'blabla';
document.querySelector('.post-container').insertBefore(post,document.querySelector('#js-load-more') );
}
.post {
height: 400px;
background: linear-gradient(to bottom, hotpink, cyan)
}
<div class="post-container">
<div class="post"> blabla </div> <!-- this is one "post" with images, text, .. -->
<div class="post"> blabla </div>
<div class="post"> blabla </div>
<div id="js-load-more"></div> <!-- just an empty div, to check if you should load more -->
</div>

Related

Is there any way to wait until every html component is in its position to show website to the user?

I am currently developing a mobile website in which I intend to load a series of data to show it to the user. I need to show that website to the user once everything has loaded, so the program can then figure out where is each of the categories of products, so as to give the user the chance to scroll from the top of the website to any category as swiftly as possible.
For that, I have implemented a Promise by which the program tells the website when everything has been processed, so it can hide a loading spinner and show the website. However, there is a slight delay between the processing of that information in my .ts and the positioning and loading of the information I have to show in my .html.
I am making the trick by setting a timeout whenever I set that Promise to be true, but that's rubbish and not reliable at all, as some users can load the information faster than that set timeout, having an unnecessary delay as a result, and some users, with a slower connection, can't get the data in time, making it all useless.
What I want is pretty simple: whenever everything is positioned and ready to be served to the user, I mean, having that loading spinner until the website can be seen without images positioning themselves, list groups out of position, etc. show everything to the user, without using fixed timeouts.
I have read widely about the use of Observables, Promises and so on, but my level of experience and knowledge seems to be rather limited, at the moment.
I am developing the website on Angular 10, with TypeScript and HTML, no jQuery.
Marked in red, there is an image. In orange, the name of a restaurant. And then, in grey, some of their products. Those are part of several list-groups, which are set as collapsable items.
The problem I am having, then, is that when my timeout falls short, the red square can be anywhere, which disturbs the offsetTop position of those lines called "Tus favoritos", "Entrantes", etc. and disable the scroll by clicking in those names functionality, for example. The other case, in which the timeout is higher than what the user needs is also unacceptable.
Here is some code I'm using. Sorry for the Spanish names.
establecimiento.html
<div id="panelFinal" *ngIf="datosCargados | async" class="animacion"> ...
</div>
<div id="panelCarga" *ngIf="!datosCargados">
<div class="d-flex justify-content-center align-items-center mt-5">
<div class="spinner-border" style="width: 3rem; height: 3rem; color: rgb(224, 96, 11);" role="status">
</div>
</div>
<br>
<label class="d-flex justify-content-center align-items-center">Cargando establecimiento...</label>
</div>
establecimiento.ts
cargaDatos() {
if (this.loadCategorias && this.loadLogo){
setTimeout(() => {
this.datosCargados = Promise.resolve(true);
}, 500);
}
}
mostrarCompleta() {
this.authSvc.guardarStorage('tipoCarta', '0');
const arrayFavs = [];
for (const prodFav of this.infoProductosFav){
const fav = `${prodFav.categoriaID}-${prodFav.productoID}`;
arrayFavs.push(fav);
}
if (this.infoProductos.length === 0){
for (let i = 0; i < this.categorias.length; i++) {
let idCategoria = '';
if (i < 9){
idCategoria = '0' + (i + 1);
}
else {
idCategoria = (i + 1).toString();
}
this.firestoreSvc.db.collection('establecimientos').doc(this.establecimientoID).
collection('categorias').doc(idCategoria).collection('productos').valueChanges().subscribe(val => {
this.infoProductos[i] = val;
for (const producto of val.entries()){
producto[1].Puntuacion = producto[1].Puntuacion.toFixed(1);
if (producto[1].Disponibilidad === 'Fuera de carta'){
this.infoProductos[i].splice(producto[0], 1);
this.categorias[i].Productos = this.infoProductos[i].length.toString();
}
if (producto[1].Disponibilidad !== 'Disponible') {
let idProducto = '';
const id = producto[0];
if (id < 9){
idProducto = '0' + (id + 1);
}
else {
idProducto = (id + 1).toString();
}
console.log(`${idCategoria}-${idProducto}`);
if (arrayFavs.includes(`${idCategoria}-${idProducto}`)){
const index = arrayFavs.indexOf(`${idCategoria}-${idProducto}`);
this.infoProductosFav[index].Indisponibilidad = true;
}
}
}
this.categorias[i].Productos = this.infoProductos[i].length.toString();
});
}
this.loadCategorias = true;
this.cargaDatos();
}
this.cartaCategorias = false;
this.cartaCompleta = true;
let categoriaFocus;
if (this.authSvc.cargarStorage('CategoriaCarta')) {
categoriaFocus = this.authSvc.cargarStorage('CategoriaCarta');
}
let rect;
setTimeout( () => {
if (categoriaFocus && this.establecimientoID === this.authSvc.cargarStorage('idEstablecimiento')) {
rect = document.getElementById(categoriaFocus).offsetTop;
window.scrollTo(0, rect - 50);
localStorage.removeItem('CategoriaCarta');
}
for (const categoria of this.categorias){
if (categoria.Productos !== '0'){
this.posicionesScroll.push(document.getElementById(categoria.Nombre_Categoria).offsetTop - 75);
this.sliderCategorias.push(categoria.Nombre_Categoria);
} else {
this.posicionesScroll.push(50000);
this.sliderCategorias.push(categoria.Nombre_Categoria);
}
}
if (this.productosFavoritos){
this.posicionesScroll.unshift(document.getElementById('favoritos').offsetTop - 75);
this.sliderCategorias.unshift('favoritos');
this.posicionesScroll.unshift(0);
this.sliderCategorias.unshift('busqueda');
} else {
this.posicionesScroll.unshift(0);
this.sliderCategorias.unshift('busqueda');
}
document.getElementById('panelFinal').style.visibility = 'visible';
}, 500);
}
Thank you very much in advance and sorry for the longpost, I tried to be as detailed as possible. Cheers.

How can I detect the scrollTop of an element using Vanilla Javascript?

I want to add a class to an element when the user scrolls more than 100px from the top of the element but I seem to be triggering this as soon as the page loads. This is the code that I have at the moment
const content = document.getElementById("content");
document.addEventListener("scroll", () => {
content.classList.add(
'curtain-in',
content.scrollTop > 100
);
});
Also with your answer can you please explain where I've gone wrong.
Thank you in advance
Maybe what is happening is that content.scrollTop is always returning 0 and your condition is never fulfilled. I've struggled myself with that problem trying to make a fiddle to test your case.
To check if the scroll has passed the beginning of the element plus 100px we need to know where the element starts and the new position of the scroll, we can get both values like this:
var position = content.offsetTop;
var scrolled = document.scrollingElement.scrollTop;
With these, you can do something like this in your event function:
const content = document.getElementById("content");
document.addEventListener("scroll", (e) => {
var scrolled = document.scrollingElement.scrollTop;
var position = content.offsetTop;
if(scrolled > position + 100){
content.classList.add(
'curtain-in');
}
});
Here's the fiddle: https://jsfiddle.net/cvmw3L1o/1/
I want to add a class to an element when the user scrolls more than
100px from the top of the element
You should add addEventListener to content not document
const content = document.getElementById("content");
content.addEventListener("scroll", () => {
console.log('class added');
content.classList.add(
'curtain-in',
content.scrollTop >= 100
);
});
#content {
height: 200px;
width: 200px;
overflow: scroll;
}
p {
height: 1000px;
}
<div id="content">
<p></p>
</div>

Pop pre-pended div items in jQuery (on message receive)

I have a small function the uses a web socket to receive realtime updates. When a new response is received the function prepends a div in the html. I only want the updates to be shown in a window within the page, ie. only ~10 prepended divs should be showing at the most. Ideally I need to pop the oldest div before it overflows out of its parent div.
My question:
How do I pop divs before they overflow the parent? Considering I will receive a response nearly every second or so, what is the most efficient way of doing this?
#HTML
<div class="content">
<p>archienorman-thesis $ realtime_bitcoin</p>
<div id="messages"></div>
<!-- window content -->
</div>
#JS FUNCTION
var total = 0;
var btcs = new WebSocket('wss://ws.blockchain.info/inv');
btcs.onopen = function () {
btcs.send(JSON.stringify({"op": "unconfirmed_sub"}));
};
btcs.onmessage = function (onmsg) {
console.log(response);
var response = JSON.parse(onmsg.data);
var amount = response.x.out[0].value;
var calAmount = amount / 100000000;
var msgs = $('#messages .message');
var count = msgs.length;
if (count == 10) {
msgs.first().remove();
}
$('#messages').prepend("<p class='tx'> Amount: " + calAmount + "</p>");
}
Make the container div overflow: hidden, check if there is overflow using JS scrollHeight and clientHeight.
CSS
#messages {
overflow: hidden;
}
JS
Remove your if statement and add this after your prepend() line:
$('#messages').prepend("<p class='tx'> Amount: " + calAmount + "</p>");
$('#messages').css("overflow", "scroll");
if($('#messages')[0].scrollHeight > $('#messages').height())
msgs.last().remove();
$('#messages').css("overflow", "hidden");
The above quickly makes #messages have the overflow: scroll property in order for the scrollHeight property to work. If there is extra scroll, then it deletes the element.
See Demo.
NOTE
See my comment to your question. You should be removing last(), not first(). See the demo as an example -- try changing last() to first(), and it will not work.
I think something like this should work. This is test code that will basically remove the extra child elements when their combined width exceeds that of the container.
HTML
<div class="container">
<div>1.Test</div>
<div>2.Test</div>
<div>3.Test</div>
<div>4.Test</div>
<div>5.Test</div>
<div>6.Test</div>
<div>7.Test</div>
<div>8.Test</div>
<div>9.Test</div>
<div>10.Test</div>
<div>11.Test</div>
<div>12.Test</div>
<div>13.Test</div>
<div>14.Test</div>
<div>15.Test</div>
</div>
CSS
.container {
width:1000px;
}
.container div {
width: 100px;
display: inline-block;
}
Javascript
function a () {
var containerWidth = $('div.container').width();
var childWidth = $('div.container div').width();
var childCount = $('div.container div').length;
var removeCount = (childWidth * childCount) - containerWidth;
if(removeCount > 0) {
removeCount = Math.floor(removeCount/childWidth);
console.log(removeCount);
for(i = childCount; i > (childCount-removeCount); i--) {
$('div.container div:nth-child('+i+')').remove();
}
}
}
a();
Fiddle: https://jsfiddle.net/L3r2nk6z/5/

ReactJS: Modeling Bi-Directional Infinite Scrolling

Our application uses infinite scrolling to navigate large lists of heterogenous items. There are a few wrinkles:
It's common for our users to have a list of 10,000 items and need to scroll through 3k+.
These are rich items, so we can only have a few hundred in the DOM before browser performance becomes unacceptable.
The items are of varying heights.
The items may contain images and we allow the user to jump to a specific date. This is tricky because the user can jump to a point in the list where we need to load images above the viewport, which would push the content down when they load. Failing to handle that means that the user may jump to a date, but then be shifted to an earlier date.
Known, incomplete solutions:
(react-infinite-scroll) - This is just a simple "load more when we hit the bottom" component. It does not cull any of the DOM, so it will die on thousands of items.
(Scroll Position with React) - Shows how to store and restore the scroll position when inserting at the top or inserting at the bottom, but not both together.
I'm not looking for the code for a complete solution (although that would be great.) Instead, I'm looking for the "React way" to model this situation. Is scroll position state or not? What state should I be tracking to retain my position in the list? What state do I need to keep so that I trigger a new render when I scroll near the bottom or top of what is rendered?
This is a mix of an infinite table and an infinite scroll scenario. The best abstraction I found for this is the following:
Overview
Make a <List> component that takes an array of all children. Since we do not render them, it's really cheap to just allocate them and discard them. If 10k allocations is too big, you can instead pass a function that takes a range and return the elements.
<List>
{thousandelements.map(function() { return <Element /> })}
</List>
Your List component is keeping track of what the scroll position is and only renders the children that are in view. It adds a large empty div at the beginning to fake the previous items that are not rendered.
Now, the interesting part is that once an Element component is rendered, you measure its height and store it in your List. This lets you compute the height of the spacer and know how many elements should be displayed in view.
Image
You are saying that when the image are loading they make everything "jump" down. The solution for this is to set the image dimensions in your img tag: <img src="..." width="100" height="58" />. This way the browser doesn't have to wait to download it before knowing what size it is going to be displayed. This requires some infrastructure but it's really worth it.
If you can't know the size in advance, then add onload listeners to your image and when it is loaded then measure its displayed dimension and update the stored row height and compensate the scroll position.
Jumping at a random element
If you need to jump at a random element in the list that's going to require some trickery with scroll position because you don't know the size of the elements in between. What I suggest you to do is to average the element heights you already have computed and jump to the scroll position of last known height + (number of elements * average).
Since this is not exact it's going to cause issues when you reach back to the last known good position. When a conflict happens, simply change the scroll position to fix it. This is going to move the scroll bar a bit but shouldn't affect him/her too much.
React Specifics
You want to provide a key to all the rendered elements so that they are maintained across renders. There are two strategies: (1) have only n keys (0, 1, 2, ... n) where n is the maximum number of elements you can display and use their position modulo n. (2) have a different key per element. If all the elements share a similar structure it's good to use (1) to reuse their DOM nodes. If they don't then use (2).
I would only have two pieces of React state: the index of the first element and the number of elements being displayed. The current scroll position and the height of all the elements would be directly attached to this. When using setState you are actually doing a rerender which should only happen when the range changes.
Here is an example of infinite list using some of the techniques I describe in this answer. It's going to be some work but React is definitively a good way to implement an infinite list :)
have a look at http://adazzle.github.io/react-data-grid/index.html#
This looks like a powerful and performant datagrid with Excel-like features and lazy loading/optimized rendering (for millions of rows) with rich editing features (MIT licenced).
Not yet tried in our project but will do so pretty soon.
A great resource to search for things like these is also http://react.rocks/
In this case, a tag search is helpful:
http://react.rocks/tag/InfiniteScroll
I was facing a similar challenge for modeling single-direction infinite scrolling with heterogeneous item heights and so made an npm package out of my solution:
https://www.npmjs.com/package/react-variable-height-infinite-scroller
and a demo: http://tnrich.github.io/react-variable-height-infinite-scroller/
You can check out the source code for the logic, but I basically followed the recipe #Vjeux outlined in the above answer. I haven't yet tackled jumping to a particular item, but I'm hoping to implement that soon.
Here's the nitty-gritty of what the code currently looks like:
var React = require('react');
var areNonNegativeIntegers = require('validate.io-nonnegative-integer-array');
var InfiniteScoller = React.createClass({
propTypes: {
averageElementHeight: React.PropTypes.number.isRequired,
containerHeight: React.PropTypes.number.isRequired,
preloadRowStart: React.PropTypes.number.isRequired,
renderRow: React.PropTypes.func.isRequired,
rowData: React.PropTypes.array.isRequired,
},
onEditorScroll: function(event) {
var infiniteContainer = event.currentTarget;
var visibleRowsContainer = React.findDOMNode(this.refs.visibleRowsContainer);
var currentAverageElementHeight = (visibleRowsContainer.getBoundingClientRect().height / this.state.visibleRows.length);
this.oldRowStart = this.rowStart;
var newRowStart;
var distanceFromTopOfVisibleRows = infiniteContainer.getBoundingClientRect().top - visibleRowsContainer.getBoundingClientRect().top;
var distanceFromBottomOfVisibleRows = visibleRowsContainer.getBoundingClientRect().bottom - infiniteContainer.getBoundingClientRect().bottom;
var rowsToAdd;
if (distanceFromTopOfVisibleRows < 0) {
if (this.rowStart > 0) {
rowsToAdd = Math.ceil(-1 * distanceFromTopOfVisibleRows / currentAverageElementHeight);
newRowStart = this.rowStart - rowsToAdd;
if (newRowStart < 0) {
newRowStart = 0;
}
this.prepareVisibleRows(newRowStart, this.state.visibleRows.length);
}
} else if (distanceFromBottomOfVisibleRows < 0) {
//scrolling down, so add a row below
var rowsToGiveOnBottom = this.props.rowData.length - 1 - this.rowEnd;
if (rowsToGiveOnBottom > 0) {
rowsToAdd = Math.ceil(-1 * distanceFromBottomOfVisibleRows / currentAverageElementHeight);
newRowStart = this.rowStart + rowsToAdd;
if (newRowStart + this.state.visibleRows.length >= this.props.rowData.length) {
//the new row start is too high, so we instead just append the max rowsToGiveOnBottom to our current preloadRowStart
newRowStart = this.rowStart + rowsToGiveOnBottom;
}
this.prepareVisibleRows(newRowStart, this.state.visibleRows.length);
}
} else {
//we haven't scrolled enough, so do nothing
}
this.updateTriggeredByScroll = true;
//set the averageElementHeight to the currentAverageElementHeight
// setAverageRowHeight(currentAverageElementHeight);
},
componentWillReceiveProps: function(nextProps) {
var rowStart = this.rowStart;
var newNumberOfRowsToDisplay = this.state.visibleRows.length;
this.props.rowData = nextProps.rowData;
this.prepareVisibleRows(rowStart, newNumberOfRowsToDisplay);
},
componentWillUpdate: function() {
var visibleRowsContainer = React.findDOMNode(this.refs.visibleRowsContainer);
this.soonToBeRemovedRowElementHeights = 0;
this.numberOfRowsAddedToTop = 0;
if (this.updateTriggeredByScroll === true) {
this.updateTriggeredByScroll = false;
var rowStartDifference = this.oldRowStart - this.rowStart;
if (rowStartDifference < 0) {
// scrolling down
for (var i = 0; i < -rowStartDifference; i++) {
var soonToBeRemovedRowElement = visibleRowsContainer.children[i];
if (soonToBeRemovedRowElement) {
var height = soonToBeRemovedRowElement.getBoundingClientRect().height;
this.soonToBeRemovedRowElementHeights += this.props.averageElementHeight - height;
// this.soonToBeRemovedRowElementHeights.push(soonToBeRemovedRowElement.getBoundingClientRect().height);
}
}
} else if (rowStartDifference > 0) {
this.numberOfRowsAddedToTop = rowStartDifference;
}
}
},
componentDidUpdate: function() {
//strategy: as we scroll, we're losing or gaining rows from the top and replacing them with rows of the "averageRowHeight"
//thus we need to adjust the scrollTop positioning of the infinite container so that the UI doesn't jump as we
//make the replacements
var infiniteContainer = React.findDOMNode(this.refs.infiniteContainer);
var visibleRowsContainer = React.findDOMNode(this.refs.visibleRowsContainer);
var self = this;
if (this.soonToBeRemovedRowElementHeights) {
infiniteContainer.scrollTop = infiniteContainer.scrollTop + this.soonToBeRemovedRowElementHeights;
}
if (this.numberOfRowsAddedToTop) {
//we're adding rows to the top, so we're going from 100's to random heights, so we'll calculate the differenece
//and adjust the infiniteContainer.scrollTop by it
var adjustmentScroll = 0;
for (var i = 0; i < this.numberOfRowsAddedToTop; i++) {
var justAddedElement = visibleRowsContainer.children[i];
if (justAddedElement) {
adjustmentScroll += this.props.averageElementHeight - justAddedElement.getBoundingClientRect().height;
var height = justAddedElement.getBoundingClientRect().height;
}
}
infiniteContainer.scrollTop = infiniteContainer.scrollTop - adjustmentScroll;
}
var visibleRowsContainer = React.findDOMNode(this.refs.visibleRowsContainer);
if (!visibleRowsContainer.childNodes[0]) {
if (this.props.rowData.length) {
//we've probably made it here because a bunch of rows have been removed all at once
//and the visible rows isn't mapping to the row data, so we need to shift the visible rows
var numberOfRowsToDisplay = this.numberOfRowsToDisplay || 4;
var newRowStart = this.props.rowData.length - numberOfRowsToDisplay;
if (!areNonNegativeIntegers([newRowStart])) {
newRowStart = 0;
}
this.prepareVisibleRows(newRowStart , numberOfRowsToDisplay);
return; //return early because we need to recompute the visible rows
} else {
throw new Error('no visible rows!!');
}
}
var adjustInfiniteContainerByThisAmount;
//check if the visible rows fill up the viewport
//tnrtodo: maybe put logic in here to reshrink the number of rows to display... maybe...
if (visibleRowsContainer.getBoundingClientRect().height / 2 <= this.props.containerHeight) {
//visible rows don't yet fill up the viewport, so we need to add rows
if (this.rowStart + this.state.visibleRows.length < this.props.rowData.length) {
//load another row to the bottom
this.prepareVisibleRows(this.rowStart, this.state.visibleRows.length + 1);
} else {
//there aren't more rows that we can load at the bottom so we load more at the top
if (this.rowStart - 1 > 0) {
this.prepareVisibleRows(this.rowStart - 1, this.state.visibleRows.length + 1); //don't want to just shift view
} else if (this.state.visibleRows.length < this.props.rowData.length) {
this.prepareVisibleRows(0, this.state.visibleRows.length + 1);
}
}
} else if (visibleRowsContainer.getBoundingClientRect().top > infiniteContainer.getBoundingClientRect().top) {
//scroll to align the tops of the boxes
adjustInfiniteContainerByThisAmount = visibleRowsContainer.getBoundingClientRect().top - infiniteContainer.getBoundingClientRect().top;
// this.adjustmentScroll = true;
infiniteContainer.scrollTop = infiniteContainer.scrollTop + adjustInfiniteContainerByThisAmount;
} else if (visibleRowsContainer.getBoundingClientRect().bottom < infiniteContainer.getBoundingClientRect().bottom) {
//scroll to align the bottoms of the boxes
adjustInfiniteContainerByThisAmount = visibleRowsContainer.getBoundingClientRect().bottom - infiniteContainer.getBoundingClientRect().bottom;
// this.adjustmentScroll = true;
infiniteContainer.scrollTop = infiniteContainer.scrollTop + adjustInfiniteContainerByThisAmount;
}
},
componentWillMount: function(argument) {
//this is the only place where we use preloadRowStart
var newRowStart = 0;
if (this.props.preloadRowStart < this.props.rowData.length) {
newRowStart = this.props.preloadRowStart;
}
this.prepareVisibleRows(newRowStart, 4);
},
componentDidMount: function(argument) {
//call componentDidUpdate so that the scroll position will be adjusted properly
//(we may load a random row in the middle of the sequence and not have the infinte container scrolled properly initially, so we scroll to the show the rowContainer)
this.componentDidUpdate();
},
prepareVisibleRows: function(rowStart, newNumberOfRowsToDisplay) { //note, rowEnd is optional
//setting this property here, but we should try not to use it if possible, it is better to use
//this.state.visibleRowData.length
this.numberOfRowsToDisplay = newNumberOfRowsToDisplay;
var rowData = this.props.rowData;
if (rowStart + newNumberOfRowsToDisplay > this.props.rowData.length) {
this.rowEnd = rowData.length - 1;
} else {
this.rowEnd = rowStart + newNumberOfRowsToDisplay - 1;
}
// var visibleRows = this.state.visibleRowsDataData.slice(rowStart, this.rowEnd + 1);
// rowData.slice(rowStart, this.rowEnd + 1);
// setPreloadRowStart(rowStart);
this.rowStart = rowStart;
if (!areNonNegativeIntegers([this.rowStart, this.rowEnd])) {
var e = new Error('Error: row start or end invalid!');
console.warn('e.trace', e.trace);
throw e;
}
var newVisibleRows = rowData.slice(this.rowStart, this.rowEnd + 1);
this.setState({
visibleRows: newVisibleRows
});
},
getVisibleRowsContainerDomNode: function() {
return this.refs.visibleRowsContainer.getDOMNode();
},
render: function() {
var self = this;
var rowItems = this.state.visibleRows.map(function(row) {
return self.props.renderRow(row);
});
var rowHeight = this.currentAverageElementHeight ? this.currentAverageElementHeight : this.props.averageElementHeight;
this.topSpacerHeight = this.rowStart * rowHeight;
this.bottomSpacerHeight = (this.props.rowData.length - 1 - this.rowEnd) * rowHeight;
var infiniteContainerStyle = {
height: this.props.containerHeight,
overflowY: "scroll",
};
return (
<div
ref="infiniteContainer"
className="infiniteContainer"
style={infiniteContainerStyle}
onScroll={this.onEditorScroll}
>
<div ref="topSpacer" className="topSpacer" style={{height: this.topSpacerHeight}}/>
<div ref="visibleRowsContainer" className="visibleRowsContainer">
{rowItems}
</div>
<div ref="bottomSpacer" className="bottomSpacer" style={{height: this.bottomSpacerHeight}}/>
</div>
);
}
});
module.exports = InfiniteScoller;

Automatic sliding content inside a div?

So I have a div with a set width and height, and I want the content inside to slide automatically (without hover or interaction from the user) after like so many seconds to reveal different content. What my actual goal is, I have boxes with an audio player and the notes of the generated content, and I want it to slide up down or left right whatever, to reveal the artist blabhalbalh. You can see what I'm talking about at here.
Oh, silly me. A good example would be Windows Phone 7 live tiles, thats actually what I'm basing it off of.
var swap = false;
var w = 309;
var h = 261;
var i = 0;
var x = 0;
var q = 1;
var t;
window.onload=function(){
i = initPortfolio();
setTimeout("portfolioRotate()",2000);
}
function initPortfolio(){
$('.portfolio-item').each(function(index){i = i+1;});
for(var n=1;n<=i;n=n+1){
lpos = w * n - w;
$('#item-'+n).css('left',lpos);
}
$('.offs').css('display','block');
x = i * w - w;
return i;
}
function portfolioRotate(){
swap = false;
$('.portfolio-item').animate({left:'-='+w},6000,function(){
nn = this.id.split("-")[1];
if(q==nn && swap==false){
$('#item-'+q).css('left',x);
if(q<i){q=q+1}else{q=1};
swap = true;
u=setTimeout("portfolioRotate()",2000);
}
});
}
<div id="portfolio-container">
<div class="portfolio-item" id="item-1"></div>
<div class="portfolio-item" id="item-2"></div>
<div class="portfolio-item" id="item-3"></div>
<div class="portfolio-item offs" id="item-4"></div>
</div>
.offs{
display:none;
}
#portfolio-container{
width:927px;
height:318px;
margin-top:30px;
position:relative;
overflow:hidden;
}
.portfolio-item{
width:309;
padding-top:20px;
position:absolute;
height:100%;
}
This might be terrible, but I just pulled it from something I was working on recently. Let me know if it isn't sliding, or needs explanation. using jQuery. there is probably a way better way to position the components initially with css.

Categories