Get all HTML elements scrolled into view - javascript

I've got a scrollable table in HTML that updates frequently (about once per second) and can contain upwards of 1000 rows. Obviously, it's not reasonable to replace the entire table every time it updates, so I'd like to just replace the table rows that are currently visible.
My first attempt was to just check iterate over all the rows and check their offsets; this works, but it's far too slow to be effective.
What I'm trying to do now is use document.elementFromPoint() to find the topmost element overtop the <tbody>, which is usually a <td> element from where I can get its containing <tr>. This almost works, except in the case where the table itself is obscured by another element (a floating lightbox, for example).
I'm currently looking for either a third solution, or a way to get all elements under a specific point, not just the topmost one. If anyone has any idea how to accomplish either of those, that would be much appreciated.

So I was thinking about this one and came up with this.
http://jsfiddle.net/RKzRE/7/
Instead of monitoring all 1000 rows just monitor a subset of them. Cache their scrolltops on page load for efficiency. So what if you update a few rows above or below the display area? You can find a happy medium between granularity and speed of updates.
I only implemented scrolling down and hardcoded the number of rows to update. But I think the details will be easy to figure out.
//create an object to hold a list of row top locations
var rowmarkers = new Object;
//gather all rows and store their top location
$('tr').each(function(index) {
//create markers for every ten rows
if (index % 10 == 0) {
$(this).addClass('marker');
rowmarkers[$(this).prop('id')] = $(this).offset().top;
}
});
//track whether user scrolls up or down
var prevScrollTop = $(document).scrollTop();
//monitor scroll event
$(document).scroll(function() {
var currentScrollTop = $(this).scrollTop();
if (currentScrollTop > prevScrollTop) {
downScroll(currentScrollTop);
} else {
//up
}
prevScrollTop = currentScrollTop;
});
function downScroll(scrollTop) {
//find the first row that is visible on screen
for (var row in rowmarkers) {
if (rowmarkers[row] > scrollTop) {
//all rows after this can be updated
var updaterow = $('#' + row).prevAll('.marker:first');
if (!updaterow.length) { updaterow = $('.marker:first'); }
//hardcoded # of rows to update
for (var i = 0; i < 20; i++) {
console.log($(updaterow).prop('id'));
updaterow = updaterow.next('tr');
updaterow.not('.marker').addClass('updaterow');
}
return;
}
}
}

Related

change rows depending on the ordernumber in database

I'm creating for my education-project a pizza-ordering website. With the help of the stackoverflow-community I've achieved already a lot - so thank you! But now I'm stuck and can't find any working solution to my problem.
Question
How can I change the row color alternating (white / grey / white / grey ...) depending on the ordernumber in the database(mysqli)? The ordernumber can be in more than one row, so I can not simple change the color row by row.
I've tried with jquery, but this works only if the ordering numbers remain always in the list (even/odd) ... if an order is cancelled, then it doesn't works anymore (see image with missing ordernumber 7)
Here is the code in jquery:
$(document).ready(function() {
var check = 0;
for(var i =0; i<= $("tr").length;i++){
$("tr").each(function(){
if(parseInt($(this).find("#bestnr").text())==check){
if(check%2 == 0){
$(this).css("background-color","white");
}else{
$(this).css("background-color","#DCDCDC");
}
}
});
check +=1;
}
});
Any ideas? Thanks for your help!
Since you're working with JQuery, something like this ought to do the trick - explanations in code comments.
$(document).ready(function() {
// define the initial "previous order id" as 0 assuming
// there will never be an order with id 0
var previousOrderId = 0;
var previousBgColour = '#dcdcdc';
var thisBgColour;
// loop the table rows
$("tr").each(function() {
// determine "this" row id (assuming bestnr is short for bestelnummer)
// and that the text in that table cell *is* the order number
// I've changed this to a class as an id HAS to be unique
// you'll need to update your code to accommodate
var thisOrderId = parseInt($(this).find(".bestnr").text());
// define the background colour based on whether the order id has changed
// if it has change it
if(thisOrderId != previousOrderId) {
thisBgColour = previousBgColour == '#dcdcdc' ? '#ffffff' : '#dcdcdc';
previousBgColour = thisBgColour;
}
else {
thisBgColour = previousBgColour;
}
$(this).css({'background-color' : thisBgColour});
//update the previousOrderId to this id
previousOrderId = thisOrderId;
});
});
You're basically storing the previous order id and comparing it to the current order id - if the order id hasn't changed it'll use the previous background colour, if it has it'll flipflop it to the alternate colour.
If it is just alternating colors, you can use CSS directly and not worry about anything else:
tr:nth-child(odd) {
background-color:white;
}
tr:nth-child(even) {
background-color:#DCDCDC;
}
If this is somehow dependent on logic from the backend, we can look at adding a class in jQuery and adding colors to this class via CSS

Prevent overlapping while positioning element at height of another

Inside a long text document there are some "special words" to which I want to display notes/annotations on the left. Each note should be as close as possible to the level of the word it is refering to.
The HTML for this is organised in a table. Each paragraph is one table row, consisting on annotations in the left and main text in the right table column. the notes/annotations go to the left. However, unfortunately, there are also some other elements/text nodes in there.
<table>
<tr>
<td class"comments">
<span id="dog" class="note">Note for dog</span>
<span id="cat" class="note">Note for cat</span>
<span id="horse" class="note">Note for horse</span>
Somethin else than a note.
</td>
<td>[Text...]
<span id="dog_anchor" class="reference">Dog</span>
<span id="cat_anchor" class="reference">Cat</span>
<span id="horse_anchor" class="reference">Horse</span>
[Text...]
</td>
</tr>
</table>
It's easy to change the "note"-spans to absolute and positioned them on the level of their reference:
$('span[class*="note"]').each(function (index, value) {
var my_id = $(this).attr('id');
var element_ref = document.getElementById(my_id + "_anchor"); // get reference element
var pos_of_ref = element_ref.offsetTop; // get position of reference element
$(this).css('top', pos_of_ref); // set own position to position of reference element
});
However, life is not so simple here. Since there could be a lot of reference words in one line (while on other there are none of them) I need a rather sophisticated way to distribute the notes so that they are as close as possible to their references without destroying anything in the layout (e.g. being placed outside of the table cell or overlapping with other elements).
Furthermore, the height of the table cells could not be changed. Elements which are not notes must not be moved. (Note elements are always in the order they appear in the main text. That's not the problem.)
So, I need an algorithm like this:
Take all notes in a table cell.
Analyse blank space in that table cell: Which areas are blank, which are blocked?
Distribute the notes in the table cell so that each note is as close as possible to its reference word without any element colliding with any other item in the table cell.
Is there any fast and elegant way to do this without having to write hundreds of lines of code?
Here is a JSfiddle: https://jsfiddle.net/5vLsrLa7/7/
[Update on suggested solutions]
Simply setting the position of the side notes to relative or just moving notes down won't work, because in this case, the side notes will just go downwards relative to their desired position which results in side notes way to far from their reference words. After all, for a neat solution I need to side notes spread in both directions: up and down.
[Update]
The expected result would be something like this:
As you see, it's never possible to place all the notes at the height of their reference. However, the free space is used to position them as close as possible, moving them up and down.
I changed move() function as follows:
function move(){
var prev_offset = 0;
$('span.note').each(function (index, value){
var my_id = $(this).attr('id');
var element_ref = document.getElementById(my_id + "_anchor"); // get reference element
var pos_of_ref = element_ref.offsetTop; // get position of reference element
if (prev_offset >= pos_of_ref){
pos_of_ref = prev_offset + 30;
}
$(this).css('top', pos_of_ref); // set own position to position of reference element
prev_offset = pos_of_ref;
});
}
I'm assuming that your element's notes will be in the correct order always
I made some changes to your javascript:
function move()
{
var arrayTops = [];
$('span[class*="note"]').each(function (index, value)
{
var my_id = $(this).attr('id');
var element_ref = document.getElementById(my_id + "_anchor"); // get reference element
var pos_of_ref = element_ref.offsetTop; // get position of reference element
pos_of_ref = getCorrectTopPosition(arrayTops,pos_of_ref);
$(this).css('top', pos_of_ref); // set own position to position of reference element
arrayTops.push(pos_of_ref);
});
}
function getCorrectTopPosition(arrayTops, newOffsetTop)
{
var notesHeight = 18;
var marginBetweenNotes = 3;
var noteheightWithMargin = notesHeight + marginBetweenNotes;
var lastTop = arrayTops[arrayTops.length-1];
if((lastTop + noteheightWithMargin) >= newOffsetTop)
return lastTop + noteheightWithMargin;
return newOffsetTop;
}
Thanks for all the answers and comments. I was finally able to figure out at least a partical solution which works for me.
First of all, I was able to restructure my HTML, so that now the "non note" elements in the left td are all wrapped in one div which is now the very first element in the td. So, now there is nothing between notes, maybe something before them.
The idea of my solution is not to give the notes a new position but to set a new margin-top to each of them. The maximum amount of margin-top values to be added within a table cell is calculated before (called "roaming space"), being the space below the last note in a table cell. Thus, the table layout is not destroyed.
function move_notes() {
$('tr').each(function (index, value) {
var current_tr = $(this);
var last_app_element_in_tr = $(this).find('span[class*="note"]').last();
if ($(last_app_element_in_tr).length) /* Only preceed if there is at least one note in the table row */ {
var tr_height = $(this).height();
var tr_offset = $(this).offset().top;
var bottom_of_tr = tr_offset + tr_height;
var bottom_of_last_app_el = $(last_app_element_in_tr).offset().top + $(last_app_element_in_tr).height();
var roaming_space = bottom_of_tr - bottom_of_last_app_el; // Calculate the amount of pixels which are "free": The space below the very last note element
$(this).find('span[class*="note"]').each(function (index, value) {
var my_id = $(this).attr('id');
var element_ref = $(current_tr).find("#" + my_id + "_anchor");
var pos_of_ref = $(element_ref).offset().top;
var new_margin_top;
/* Calculate the new margin top: The note should be at the same level as the reference element.
When loading, in most cases the notes are placed too high. So, the margin top of the note should equal
the amount of pixels which the note is "too high". So we subtract the height and the offset of the element
before the current note from the offset of the reference. */
var previous_note = $(this).prev();
// not just notes, but every element in the td in general
if (! $(previous_note).length) // If there is no previous_note, than take the table cell
{
closest_td = $(this).closest("td");
new_margin_top = pos_of_ref - $(closest_td).offset().top;
} else {
new_margin_top = pos_of_ref - $(previous_note).offset().top - $(previous_note).height();
}
var difference_to_previous = $(this).css('marginTop').replace(/[^-\d\.]/g, '') - new_margin_top; // Calculate the difference between the old and the new margin top
if (new_margin_top > 0 && Math.abs(difference_to_previous) > 2) // Only move, if the new margin is greater than zero (no negative margins!) if the difference is greater than 2px (thus preventing ugly "micro moving".
{
var new_roaming_space = roaming_space - difference_to_previous;
if (new_roaming_space > 0) /* if there is still room to move */ {
var margin_top_ready = new_margin_top + "px";
$(this).css('margin-top', margin_top_ready);
roaming_space = new_roaming_space;
} else /* If there is no more space to move: */ {
var margin_top_ready = roaming_space + "px"; // take the rest of the "roaming space" left as margin top
$(this).css('margin-top', margin_top_ready);
return false; // Stop the execution because there is nothing left to do.
}
}
});
}
});
}
window.onload = function () {
move_notes();
};
$(window).resize(function () {
move_notes();
});
As you will notice, one of my main concerns is still not addressed: Notes are only moved down, never up. Because of various problems with my real world webpage I didn't implement that yet. However, an algorith could be something like: If the new margin top is greater than the height of the current note and the difference between the offet of the current note anchor and the following note anchor is less than the height of the current note, than subtract the height of the current note from the new margin.
Still, two problems remain:
If the window is maximized or quickly resized from a rather thin width to a greater width, the adjustment of the note positions won't work. I don't know why.
The performance could be better. As a user, you can see the notes jump down. (Because of strange and unpredictable behaviour in Firefox, I had to move the event handler from document.ready to window.onload)

Fullcalendar.io: how to display one event per line in agendaWeek then mix all in one?

I use Fullcalendar.io v2
In my agendaWeek mod I have events and all of them are displayed on one line in day square. So, more events I have, then thiner event blocks.
How can I show one event per line? Like in month mod. And more events I have, then higher day block will me (height). Perhaps, it is hard to use functions like eventRender, because if you inspect .fs-event element (web developer tool), you will see event block uses position:absolute;top:300px;left:33%... so I don't know what to do.
I want something like this:
I was stuck with that problem too, it is very difficult because the plugin compose the calendar in an odd way, using some tables and locating the events with dynamically with a position absolute and varying the css top property.
However i found a generic solution that works very good. First i will show you the code, and them i will explain what exactly the code does.
I use the option eventAfterAllRender of the fullCalendar. This is an example working.
I use moment for manage time and i assume the id of the fullCalendar html element is 'Calendar'.
eventAfterAllRender: function() {
// define static values, use this values to vary the event item height
var defaultItemHeight = 25;
var defaultEventItemHeight = 18;
// ...
// find all rows and define a function to select one row with an specific time
var rows = [];
$('div.fc-slats > table > tbody > tr[data-time]').each(function() {
rows.push($(this));
});
var rowIndex = 0;
var getRowElement = function(time) {
while (rowIndex < rows.length && moment(rows[rowIndex].attr('data-time'), ['HH:mm:ss']) <= time) {
rowIndex++;
}
var selectedIndex = rowIndex - 1;
return selectedIndex >= 0 ? rows[selectedIndex] : null;
};
// reorder events items position and increment row height when is necessary
$('div.fc-content-col > div.fc-event-container').each(function() { // for-each week column
var accumulator = 0;
var previousRowElement = null;
$(this).find('> a.fc-time-grid-event.fc-v-event.fc-event.fc-start.fc-end').each(function() { // for-each event on week column
// select the current event time and its row
var currentEventTime = moment($(this).find('> div.fc-content > div.fc-time').attr('data-full'), ['h:mm A']);
var currentEventRowElement = getRowElement(currentEventTime);
// the current row has to more than one item
if (currentEventRowElement === previousRowElement) {
accumulator++;
// move down the event (with margin-top prop. IT HAS TO BE THAT PROPERTY TO AVOID CONFLICTS WITH FullCalendar BEHAVIOR)
$(this).css('margin-top', '+=' + (accumulator * defaultItemHeight).toString() + 'px');
// increse the heigth of current row if it overcome its current max-items
var maxItemsOnRow = currentEventRowElement.attr('data-max-items') || 1;
if (accumulator >= maxItemsOnRow) {
currentEventRowElement.attr('data-max-items', accumulator + 1);
currentEventRowElement.css('height', '+=' + defaultItemHeight.toString() + 'px');
}
} else {
// reset count
rowIndex = 0;
accumulator = 0;
}
// set default styles for event item and update previosRow
$(this).css('left', '0');
$(this).css('right', '7px');
$(this).css('height', defaultEventItemHeight.toString() + 'px');
$(this).css('margin-right', '0');
previousRowElement = currentEventRowElement;
});
});
// this is used for re-paint the calendar
$('#calendar').fullCalendar('option', 'aspectRatio', $('#calendar').fullCalendar('option', 'aspectRatio'));
}
How the code works:
First i found all tr elements that are the rows of my calendar (note that they contains an attribute with its owns time).
Later I iterate for each column and get, for each one, its events items. Each event item is an anchor element with some inner child with the date as an attribute data-full.
From the event i peek what should be its row, and in that row if there are more than one item, then increase the position where the event item should be located. I use for that the margin-top property because this property is not used or readjust by the plugin (don't use top property).
In the row i set a data attribute to take the max amount of events that has any column of that row. With that, i can calculate if the row must be increase its height or not.
Well, this is basically what the codes does. If you have some question please do-it.
You can add a class to your events and try to customize this events with CSS
As an example you can use style
.test {
width: 100%;
height: auto;
position: relative !important;
left: 0% !important;
margin-right: 0% !important;
}
and event like this:
{
title: 'Lunch',
start: '2014-06-09T10:30:00',
className: 'test'
},
Look on this Fiddle if this is what you want to achieve
Also with a little bit workaround you can use eventAfterRender callback to adjust height of specific row. But this is not very safe solution and it requires some tuning:
eventAfterRender: function( event, element, view ) {
var row = $(".fc-slats tr:contains('"+ moment(event.start).format('ha') + "')");
if (moment(event.start).format('mm') != '00')
{
row = row.next();
}
row.height(element.height()+row.height());
}
https://jsfiddle.net/m5uupf9x/3/
I also faced the same issue and while Alexander's answer is great, i had performance issues with it as it does lot of DOM manipulation. I have about 2000-3000 events per week and became unusable in browsers like Firefox, IE etc. Therefore adapting Alexander's answer and minimizing DOM manipulation came up with following solution.
variables
var itemsOnSlot = {}; // counter to save number of events in same time slot
var maxItemsOnRow = {}; // counter to save max number of events in row
utilize eventRender and eventAfterAllRender callbacks
eventRender: function(event, element, view){
// for each event, margin top and other css attributes are changed to stack events on top of each other
if(!(event.start in itemsOnSlot)){ // if itemsOnSlot has no index with current event's start time
itemsOnSlot[event.start] = 1; // create index and set count to 1
$(element).addClass('slot-attributes'); // add css to change the event style
}else{ // if itemsOnSlot already has a index with current event's start time
itemsOnSlot[event.start] += 1; // increase counter by 1
// change margin top to stack events on top of each other and add css to change the event style
$(element).css('cssText','margin-top:'+(itemsOnSlot[event.start]*18)+'px !important;').addClass('slot-attributes');
}
},
eventAfterAllRender: function(view) {
// this loop is run to get the max number of events per row
for(var start in itemsOnSlot){ // for all the timeslots with events in them
var time = start.substr(16,8); // extract required time format from index - eg. 14:00:00
if(!(time in maxItemsOnRow)){ // if maxItemsOnRow has no index with current time
maxItemsOnRow[time] = itemsOnSlot[start]; // create index and set count to current day's number of events in this time slot
}else{ // if maxItemsOnRow already has a index with current time
if(itemsOnSlot[start] > maxItemsOnRow[time]){ // if current day's number of events in this time slot are greater than existing number
maxItemsOnRow[time] = itemsOnSlot[start]; // replace current time's number of slots
}
}
}
// change height of each row using values from maxItemsOnRow
$('div.fc-slats > table> tbody > tr[data-time]').each(function() { // for all rows in calendar
var time = $(this).attr('data-time'); // get time of each row
if(time in maxItemsOnRow){ // if current row's time is in maxItemsOnRow
$(this).css('cssText','height:'+(maxItemsOnRow[time]*18)+'px !important;'); // change the height of the row to contain max items in row
}else{ // if current row's time is not in maxItemsOnRow (no events in current time slot)
$(this).css('cssText','display: none !important;'); // hide timeslot
}
});
// repaint the calendar with new dimensions
$('#calendar').fullCalendar('option', 'aspectRatio', $('#calendar').fullCalendar('option', 'aspectRatio'));
itemsOnSlot = {}; // reset variables
maxItemsOnRow = {}; // reset variables
},
CSS
.slot-attributes {
left: 4px !important;
right: 3px !important;
height: 15px !important;
margin-right: 0 !important;
}

Ext setLoading(true,true) being called too late?

I have a grid with a good amount of data which the user can filter or show/hide groups of columns by using combo boxes. Some of the column switches take a long time to load and I want to call setLoading(true,true) on the grid or the combobox to show the user that the browser is working.
I have a listener function that is called when the user makes a selection on the combo box. I call combo.setLoading(true,true) before starting any of the code that takes a while to execute. Then I call combo.setLoading(false,false) at the very bottom of the function.
The loading only shows up for a split second after the code between the two setLoading calls has executed. If I take out the call to remove the loading icon, the icon still only shows up after the code is executed.
Anyone have an idea what is happening? This seems very odd to me.
categorycomboselect: function(combo, records){
combo.setLoading(true,true);
var panel = combo.up('panel');
console.log(panel);
var category = records[0].data.name;
var grid = Ext.ComponentQuery.query('grid')[1];
Ext.suspendLayouts();
grid.suspendedLayout=true;
var columns = grid.columns;//.getView().getGridColumns();
//slow code that shows/hides columns
grid.suspendedLayout=false;
Ext.resumeLayouts(true);
combo.setLoading(false,false);
},
UPDATE
Here is my code with Trimboli's suggestion, it still isn't working. I'm showing/hiding the columns based on a string in their ID. I did it this way because the categories I want to show/hide the columns on are dynamic and the columns are dynamic.
categorycomboselect: function(combo, records){
combo.setLoading(true,true);
setTimeout( function(){
var panel = combo.up('panel');
var category = records[0].data.name;
var grid = Ext.ComponentQuery.query('grid')[1];
Ext.suspendLayouts();
grid.suspendedLayout=true;
var columns = grid.columns;
if(category=='All grade items'){
for(var i = 0; i< columns.length; i++){
columns[i].setVisible(true);
}
}else{
for(var i = 0; i< columns.length; i++){
columns[i].hide();//setVisible(false);
if(!(typeof columns[i].itemId ==='undefined')){
if((columns[i].itemId).indexOf(category)>=0){
columns[i].show();
}
}
}
}
grid.suspendedLayout=false;
Ext.resumeLayouts(true);
combo.setLoading(false,false);
},1);
},
Also, I wasnt sure if
Ext.suspendLayouts();
grid.suspendedLayout=true;
do the same thing or not. And if not, which is better.
What you're essentially doing is this:
showMask();
for (i = 0; i < 10000000; ++i) {
// busy loop
}
hideMask();
If you show/hide a mask without giving the browser a "break" for it to update the DOM, you won't see anything because it all gets flushed out at the end once you relinquish control back to the browser.
If you wanted to let the mask actually show, you need to give a slight delay before continuing on with your busy loop:
showMask();
setTimeout(function() {
// Busy stuff
hideMask();
}, 1);

JQuery If Statement using each value from an array

I am writing a function that will be executed on multiple views of an application, and each view can have up to 50 instances of the same element: '.console'. I need to be able to perform an action every time the viewport scrolls to each instance. I have the following code setting up the variables:
//Create empty array with variable values, up to 50
var console = [];
//Find each instance of ".console" and populate the array with its pixel position.
$('.console').each(function() {
console.push($(this)[0].offsetTop);
});
//Determine the current pixel position of the scroll
var scroll = $(document).scrollTop();
Those variables all work fine and dandy, but after hours of pouring over jquery docs I can't figure the if statement out. Here is what I have that works well for the first item in the array:
if (scroll == console[0]){
$('.container').show();
} else {
$('.container').hide();
}
However, I want it to be anytime the scroll position matches each of the values in that array, hopefully something like this:
if (scroll == console[0-50])
Here is the full chunk as is:
$(document).on('scroll', function(){
//Create empty array with variable values, up to 50
var console = [];
//Find each instance of ".console" and populate the array with its pixel position.
$('.console').each(function() {
console.push($(this)[0].offsetTop);
});
//Determine the current pixel position of the scroll
var scroll = $(document).scrollTop();
//Anytime the scroll matches any of the instances of console, show a div
if (scroll == console[0]){
$('.container').show();
} else {
$('.container').hide();
}
});
Any help would be appreciated. I am pretty new to Javascript/JQuery so if I'm approaching the problem in the wrong way altogether, please let me know. Thanks!
Since you said it works for the first one, I'm guessing this may work.
// cache the container
var container = $('.container');
$(document).on('scroll', function(){
//Determine the current pixel position of the scroll
var scroll = $(document).scrollTop();
//Create empty array with variable values, up to 50
var console = [];
//Find each instance of ".console" and populate the array with its pixel position.
$('.console').each(function(index) {
console.push($(this)[0].offsetTop);
if (scroll == console[index]){
$(container).show();
} else {
$(container).hide();
}
});
});
You may wish to take a look at Waypoints. It's a jQuery plugin that is well suited for what you're trying to accomplish.
I whipped up a quick jsFiddle to show it in action: http://jsfiddle.net/dmillz/4xqMb/
$(".console").waypoint(function(direction) {
// Hide or show your ".container" object
});
More Waypoint examples: http://imakewebthings.com/jquery-waypoints/#get-started
Hopefully I understand your problem, which is as follows:
You have a bunch of elements with the .console class, and you want to appear as soon as they are in the viewport. When these elements aren't in the viewport you want them to dissapear?
Since you're interested in when these objects with the .console class are in the viewport, I suggest using this jQuery plugin
http://plugins.jquery.com/appear/
https://github.com/morr/jquery.appear
I suggest wrapping each of the .console objects in a container with another class, and then as these containers appear and disappear show and hide them.
At document ready just do the following:
$(document).ready(function() {
$('<.container-class>').appear();
$('<.container-class>').on('appear', function() { $(this).find('.console').show(); });
$('<.container-class>').on('disappear', function() { $(this).find('.console').hide(); });
});
To answer the question, you could do this:
var cons = $.map($('.console'), function(el) {
return $(el).offset().top;
});
$(document).on('scroll', function(){
var scroll = $(window).scrollTop();
$('.container').toggle( $.inArray(scroll, cons) != -1 );
});
But creating something for a range, considering the height of each element, the height of the window etc. would be a lot more involved.
While the problem was solved via another answer, figuring out how to perform a loop for each value in the array wasn't really solved ... UNTIL NOW!
This is probably a really gross and bloated way to do it, but if you essentially count how many items are in the array, you can then run a loop that many times, putting in the index for each value in the array. Code below:
//Create empty array with variable values
var console = [];
//Find each instance of ".console" and populate the array with its pixel position.
$('.console').each(function() {
console.push($(this)[0].offsetTop);
});
//Count the number of items in the array
var consoleIndex = console.length - 1;
$(document).on('scroll', function(){
//Determine the current pixel position of the scroll
var scroll = $(document).scrollTop();
//Anytime the scroll matches any of the instances of console, show a div
for (var i = 0; i <= consoleIndex; i++) {
if (scroll = console[i]) {
$('.container').toggle();
}
}
});

Categories

Resources