Adding option elements resets scroll position in select element - javascript

I am building a select list with a large number of options with lazy loading. The data starts by loading a preset number of items, and then as the user scrolls down the list, more items are loaded. This is all working great.
However, when new options are added, the browser scrolls to the most recently selected item, or to the top if no item is selected (tested in Firefox and IE11). This is very jarring and annoying. I would like the viewport to remain in the same spot when adding options. This is not an issue with other HTML elements like divs or lis.
Here is the CSS:
#main {
height: 200px;
width: 200px;
}
Here is the HTML with knockout bindings:
<div>
<span data-bind="text: 'Loaded ' + items().length + ' out of ' + data.length + ' items'"></span>
</div>
<select id="main" size="10" data-bind="foreach: items, event: { scroll: scrolled }">
<option data-bind="text: name"></option>
</select>
Here is the JavaScript:
var data = [];
for (var i = 0; i < 100; i++) {
data.push({
id: i,
name: "Item" + i
});
}
function getItems(count) {
var target = viewModel.maxId + count;
while (viewModel.maxId < target && viewModel.maxId < data.length) {
viewModel.items.push(data[viewModel.maxId++]);
}
}
var viewModel = {
data: data, // total data
items: ko.observableArray([]), // visible items out of data
scrolled: function(data, event) {
var elem = event.target;
if (elem.scrollTop > (elem.scrollHeight - elem.offsetHeight - 10)) {
getItems(20);
}
},
maxId: 0
};
ko.applyBindings(viewModel);
getItems(20);
And here is the fiddle: http://jsfiddle.net/4wjra438/2/

After getting new items, you can reset the scrollTop to what it was before getItems. That will make the jump-to-top less noticeable, but I don't know how to prevent it altogether.
scrolled: function(data, event) {
var elem = event.target;
var scrollPos = elem.scrollTop;
if (scrollPos > (elem.scrollHeight - elem.offsetHeight - 10)) {
getItems(20);
elem.scrollTop = scrollPos;
}
},

Related

How to auto move active class before after in JavaScript

I have created simple scroll animation page, if I scroll right side want to delete previous items
then if I scroll left side want to delete next items. see this bellow image, how to solve this issues. could you please solve this issue.
// Sticky Catergory Menu
if ($(window).scrollTop() > 400) {
$("#stickyMenu").addClass('sticky');
} else {
$("#stickyMenu").removeClass('sticky');
}
//get current sroll position
var scrollPosition = $(window).scrollTop();
//get the position of the containers
for (i = 0; i < span_list.length; i++) {
if (scrollPosition >= ($("#" + span_list[i]).offset().top) - 50) {
$("#nav" + (i + 1)).siblings().removeClass("active");
$("#nav" + (i + 1)).addClass("active");
}
}
// if (("div.item:visible")) {
// if ($("div.item").is(":visible")) {
// var content = $(this).html()
// console.log("content == " + content)
// var row_id = $(this).parent().closest("div[id]").attr("id");
// console.log("row_id == " + row_id)
// }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="topnav sticky" id="stickyMenu">
<span data-id="appetizers" id="nav1" class="cat-nav">Appetizers</span>
<span data-id="desserts" id="nav2" class="cat-nav">Desserts</span>
<span data-id="pizza--classic-11-inches-" id="nav3" class="cat-nav active">Pizza (Classic 11 inches)</span>
<span data-id="salad" id="nav4" class="cat-nav">Salad</span><span data-id="soups" id="nav5" class="cat-nav">Soups</span>
<span data-id="thai-noodles" id="nav6" class="cat-nav">Thai Noodles</span>
</div>

ScrollFire Materialize reveal List

Hi i am looking for a possible solution for the following problem.
I am building a website and i have a table which has many many rows.
I am using materialize (but if there is another plugin that can do it i am open for it).
Materialize uses this
var options = [
{selector: '#staggered-test', offset: 50, callback: function(el) {
Materialize.toast("This is our ScrollFire Demo!", 1500 );
} },
{selector: '#staggered-test', offset: 205, callback: function(el) {
Materialize.toast("Please continue scrolling!", 1500 );
} },
{selector: '#staggered-test', offset: 400, callback: function(el) {
Materialize.showStaggeredList($(el));
} },
{selector: '#image-test', offset: 500, callback: function(el) {
Materialize.fadeInImage($(el));
} }
];
Materialize.scrollFire(options);
But how to implement it on table rows?
I would simply like to hide most of the rows but get visible the more the user scrolls down.
Is this possible?
Thanks
Instead of scroll i made a button to show more using javascript and jquery here is the function
$.fn.RowReveal = function(RowsToShow, numMore) {
var numShown = RowsToShow;
var numMore = numMore;
var $table = $(this).find('tbody');
var numRows = $table.find('tr').length;
var btn_id = parseInt(Math.random()*1000)+numRows;
// Hide rows and add clickable div
$table.find('tr:gt(' + (numShown - 1) + ')').hide().end()
.after('<tbody id="more-'+btn_id+'"><tr><td colspan="' +
$table.find('tr:first td').length + '"><div>Show More</div></tbody></td></tr>');
$('#more-'+btn_id).click(function () {
numShown = numShown + numMore;
if (numShown >= numRows) {
$('#more-'+btn_id).remove();
}
if (numRows - numShown < numMore) {
$('#more-'+btn_id+' span').html(numRows - numShown);
}
$table.find('tr:lt(' + numShown + ')').fadeIn();
});
}

jquery - dynamic menu - click function not working

I have a horizontal category bar. this is populated by php - i set a data-cat-id property on the anchor. then use a jquery click function to get this value like this:
$('.filterCat').click(function() {
alert('cat id is:'+$(this).data("cat-id"))
return false;
});
This works fine. But the horizontal bar has a function that adds list elements to a "more" sub menu when the width gets smaller than its content. using the code:
$(function() {
alignMenu();
$(window).resize(function() {
$("#horizontal").append($("#horizontal li.hideshow ul").html());
$("#horizontal li.hideshow").remove();
alignMenu();
});
function alignMenu() {
var w = 0;
var mw = $("#horizontal").width() - 150;
var i = -1;
var menuhtml = '';
jQuery.each($("#horizontal").children(), function() {
i++;
w += $(this).outerWidth(true);
if (mw < w) {
menuhtml += $('<div>').append($(this).clone()).html();
$(this).remove();
}
});
$("#horizontal").append(
'<li style="position:relative;" href="#" class="hideshow">' + 'More ' + '<span style="font-size:13px">↓</span>' + '<ul>' + menuhtml + '</ul></li>');
$("#horizontal li.hideshow ul").css("top",
$("#horizontal li.hideshow").outerHeight(true) + "px");
$("#horizontal li.hideshow").click(function() {
$(this).children("ul").toggle();
});
if (menuhtml == '') {
$("#horizontal li.hideshow").hide();
} else {
$("#horizontal li.hideshow").show();
}
}
});
This also works but now when there is a "more" button (because the content is bigger) the click function does not work anymore.
i have made a fiddle - if you click on a normal menu item it shows the alert, but if you click on a item that is places under "more" it does nothing see FIDDLE: https://jsfiddle.net/quosa60e/
For dynamically created elements .click() does not work
document.on('click','SELECTOR',function(){});
So you should use:
$(document).on('click','.filterCat',function() {
alert('cat id is:'+$(this).data("cat-id"))
return false;
});

Javascript slider function - How to objectify the selectors?

I'm currently working on a project where a custom slider was needed and i quickly grabbed a neat looking tutorial of the web and went away and staticly it all works great.
Now i want to be able to put several sliders on my page and therefore need to add the controls dynamicly rather than just selecting a certain slider with jquery like I've done below.
This is my code with comments added to explain what im trying to achieve:
var Slider = function() { this.initialize.apply(this, arguments) };
Slider.prototype = {
initialize: function(slider) {
this.ul = slider.children[2];
this.li = this.ul.children;
this.nav = slider.children[3]; //Why cant i use .append on this element?
// make <ul> as large as all <li>’s
this.ul.style.width = (100 * this.li.length) + '%';
// set width of the li's
for(i = 0; i < this.li.length; i++) {
this.li[i].style.width = (100 / this.li.length) + '%';
$(".slider-nav").append( '<div class="slider-dot"></div>'); //Want to make it a this.nav or something similar instead of an external selector
//console.log(this.nav);
}
this.currentIndex = 0;
},
goTo: function(index) {
if (index < 0 || index > this.li.length - 1)
return;
// move <ul> left
this.ul.style.left = '-' + (100 * index) + '%';
this.currentIndex = index
},
goToPrev: function() {
this.goTo(this.currentIndex - 1)
},
goToNext: function() {
this.goTo(this.currentIndex + 1)
}}
var sliders = [];
$('.slider').each(function() {
sliders.push(new Slider(this));
});
//Find a way to implement theese 2 within the slider function, how to find out what position in the array a slider has?
$(".prev-btn").click(function() {
sliders[0].goToPrev();
});
$(".next-btn").click(function() {
sliders[0].goToNext();});
The marks up for the slider looks like this: http://puu.sh/hAUH1/a865792137.png
I managed to get it done by defining this as another var
var sliderEle = this;
I could then call it like this:
$(this.prev).click(function(e) {
e.preventDefault();
sliderEle.goToPrev();
});
with prev and next defined like this:
this.prev = slider.children[0];
this.next = slider.children[1];

javascript not working when page is loaded qtip2

I wrote a nice heatmap in javascript, and that worked pretty nice so far. The heatmap is basically a table with a coloring variation, based on the threshold of the value displayed in the table. I used JavaScript to create the table, and to set up the colors. However, I wanted to show a nice pop up window, so when the user hover over the table's cell, some additional information is displayed. I found this library qTip2
$(document).ready(function(){
$('#mytable td').qtip({
overwrite : false, // make sure it can't be overwritten
content : {
text : function(api){
return "Time spent: " + $(this).html();
}
},
position : {
my : 'top left',
target : 'mouse',
viewport : $(window), //keep it on-screen at all time if possible
adjust : {
x : 10, y : 10
}
},
hide : {
fixed : true // Helps to prevent the tooltip from hiding occassionaly when tracking!
},
style : 'ui-tooltip-tipsy ui-tooltip-shadow'
});
});
This function creates the heatmap:
function makeTable(data)
{
var row = new Array();
var cell = new Array();
var row_num = 26;
var cell_num = 44;
var tab = document.createElement('table');
tab.setAttribute('id', 'mytable');
tab.border = '1px';
var tbo = document.createElement('tbody');
for(var i = 0; i < row_num; i++){
row[i] = document.createElement('tr');
var upper = (i+1)*44;
var lower = i*44;
for(var j = lower; j < upper; j++){
cell[j] = document.createElement('td');
//cell[j].setAttribute('class', 'selector');
if(data[j] != undefined){
var count = document.createTextNode(data[j].diff);
cell[j].appendChild(count);
var index = parseInt(data[j].diff);
/* specify which color better suits the heatmap */
if(index >= 0 && index <= 100){
cell[j].style.backgroundColor = '#00BFFF';
}
else if(index > 100 && index <= 1000){
cell[j].style.backgroundColor = "#6495ED";
}
else if(index > 1000 && index <= 4000){
cell[j].style.backgroundColor = "#4682B4";
}
else if(index > 4000 && index <= 6000){
cell[j].style.backgroundColor = "#0000FF";
}
else{
cell[j].style.backgroundColor = "#00008B";
}
row[i].appendChild(cell[j]);
}
}
tbo.appendChild(row[i]);
}
tab.appendChild(tbo);
document.getElementById('mytable').appendChild(tab);
}
Inside of my <body> tag I have:
<div id="body">
<div id="mytable"></div>
</div>
However, when I load the page, I expect to see the pop up box when I hover the mouse over the table's cell, however something happens. Also, when I execute that $(document).ready part from firebug's terminal, then the program starts to execute as suppose to. I also made sure the library is being loaded into my page before I used it. I also don't see any errors in the firebug's terminal.
<script src="http://localhost/heatmap/javascript/jquery.qtip.js">
Could someone please give me a clue why is this happening?
The main function of my javascript is
function OnLoad() {
$.post('index.php/heatmap/getDatalines',
function(answer){
var data = eval('(' + answer + ')');
var list = [];
makeTable(data);
});
}
Thanks
whis is called on load: google.setOnLoadCallback(OnLoad);
You need to create the qtip after you have loaded the table like this:
function OnLoad() {
$.post('index.php/heatmap/getDatalines',
function(answer){
var data = eval('(' + answer + ')');
var list = [];
makeTable(data);
$('#mytable td').qtip({
overwrite : false, // make sure it can't be overwritten
content : {
text : function(api){
return "Time spent: " + $(this).html();
}
},
position : {
my : 'top left',
target : 'mouse',
viewport : $(window), // keep it on-screen at all time if possible
adjust : {
x : 10, y : 10
}
},
hide : {
fixed : true // Helps to prevent the tooltip from hiding occassionaly when tracking!
},
style : 'ui-tooltip-tipsy ui-tooltip-shadow'
});
});
}

Categories