stop tabulator ajax calls from scrolling window to top of page - javascript

I have the tabulator plugin set up and working with my data. Currently, using the remote pagination feature but whenever the pagination buttons are clicked it loads the data and then scrolls to the top of the page. The pagination buttons do not contain href="#" so it shouldn't be trying to load a browser state.
The really odd thing is it is doing this behavior on any ajax call I make relative to tabulator. I used the setData function to load updated data and it scrolled to the top of the page again.
Here's a very simplified version of my code:
<div id="#tabulator"></div>
<script>
$("#tabulator").tabulator({
movableColumns: true,
layout: "fitColumns",
pagination: "remote",
paginationSize: 10,
ajaxURL: "rosterusers_tabulator_data-json.cfm",
ajaxParams: {/* url params here */},
columns: [/* columns set here*/]
});
/*then I have a modal dialog update event which calls the following*/
$("#tabulator").tabulator(
"setData",
"rosterusers_tabulator_data-json.cfm",
{/*url params here*/}
);
</script>
I don't think I'm doing anything bizarre here but each time the table data gets updated via ajax in anyway (page change, data change, filter change, etc.) it scrolls to the top of the page.

Here is solution for various scroll to top related issues. It involves extending the tabulator.js with two functions:
Tabulator.prototype.getVerticalScroll = function () {
var rowHolder = this.rowManager.getElement();
var scrollTop = rowHolder.scrollTop;
return scrollTop;
}
Tabulator.prototype.setVerticalScroll = function (top) {
var rowHolder = this.rowManager.getElement();
rowHolder.scrollTop = top;
}
Then get and set like this:
let pos = table.getVerticalScroll();
// do table management e.g. setColumns
table.setVerticalScroll(pos);

The replaceData function can be used to set data in the table without changing the scroll position:
$("#example-table").tabulator("replaceData", "rosterusers_tabulator_data-json.cfm")

Related

How to add msnry.reloadItems() to vanilla JS script

I am very new in js, javascript, ajax, etc., I am using php and build only wordpress sites. Today I trying make to my site the hybrid pagination, what someone call it the "HolyScroll or Holy Scroll", the target this:
http://scrollsample.appspot.com/items
So I working on the infinite-scroll.com with Desandro's Masonry and my code now it looks like this (I did this in the last 5 hours...):
var grid = document.querySelector('.container');
var msnry;
imagesLoaded( grid, function() {
// init Isotope after all images have loaded
msnry = new Masonry( grid, {
itemSelector: '.item'
});
});
// -----------
var elem = document.querySelector('.container');
var infScroll = new InfiniteScroll( elem, {
// options
path: 'page/{{#}}/',
append: '.item',
history: 'push',
historyTitle: true,
prefill: true,
// load pages on init until user can scroll
scrollThreshold: 1000,
// trigger scrollThreshold event when viewport is <100px from bottom of scroll area
status: '.page-load-status',
});
// element argument can be a selector string
// for an individual element
var infScroll = new InfiniteScroll( '.container', {
// options
});
So finally works the infinite scroll, the history, the masonry (only on the first call) and the imagesLoaded, And now need paste to this the reloadItems option, but dont working...
Here is the guide: https://masonry.desandro.com/methods.html#reloaditems
Please, someone could help me? I can not find a simple tutorial to this with Vanilla JS, in turn the JQuery versions not working for me...
*Unfortunately MarkovskI drew my attention not everyone can click on a link, so I copy here, what Desandro write on his site:
"For frameworks like Angular and React, reloadItems may be useful to apply changes to the DOM to Masonry."
// vanilla JS
msnry.reloadItems()
So here is the "Holy Scroll", the hybrid, ajax / js loaded infinite scroll WITH pagination, what search engines loves, so this totally user and SEO friendly:
Source sites:
https://infinite-scroll.com/
https://masonry.desandro.com/
https://imagesloaded.desandro.com/
So, I just now learning php, I am only webdesigner and after I realized, the ALL wordpress plugins what promises you "infinite scroll" (like Ajax Load More, Ajax Pagination & infinite Scroll, DMD Infinite Scroll, Jetpack, YITH Infinite Scroll and etc.) rip-off and KILL YOUR ALL SEO if you using these plugins without LICENSE, I started looking the solution on the net. The first what it comes face to face the Google' Webmaster Central Blog:
https://webmasters.googleblog.com/2014/02/infinite-scroll-search-friendly.html
So after this article I knew what I wanted, but by the time, what I found it the keywords (thus: the browser history about infinite scroll) and the simple fact, that now need building my masonry layout (because up to now I using the Ajax Load More plugin, and this did it the masonry to me), so I never learning JS... I worked on this in the last ~35 hours, but you can instantly learn to do it yourself, as you read it all along. (The long introductory serving the keywords, to find you here too.)
So, you can modify your infinite scroll options off this official guide:
https://infinite-scroll.com/options.html
The VERY IMPORTANT THING, WHAT NEED FOR YOU, IS THIS:
https://infinite-scroll.com/options.html#history
So, put these links (or follow these steps: https://infinite-scroll.com/#install) to your footer (Or header, but Google recommend that call .js and .css files in footer, thus reduce it you pageload.):
<script src="https://unpkg.com/infinite-scroll#3/dist/infinite-scroll.pkgd.min.js"></script>
<script src="https://unpkg.com/masonry-layout#4/dist/masonry.pkgd.min.js"></script>
<script src="https://unpkg.com/imagesloaded#4/imagesloaded.pkgd.min.js"></script>
And here is so the full "Holy Scroll" code with masonry layout what using images Loaded (imagesLoaded), so never more overlapping your images.
Just Put This code to your footer between: <script></script>
var grid = document.querySelector('.container');
var msnry = new Masonry( grid, {
itemSelector: '.youritem', // select none at first
});
// initial items reveal
imagesLoaded( grid, function() {
msnry.options.itemSelector = '.youritem';
var items = grid.querySelectorAll('.youritem');
msnry.reloadItems( items ); // This reload the masonry layout after the first call
msnry.layout(); // This restrain the overlapping on the first call
});
//-------------------------------------//
// init Infinte Scroll
var infScroll = new InfiniteScroll( grid, {
// options
path: 'page/{{#}}/', // YOUR PAGINATION STRUCTURE !!!IMPORTANT!!! REPLACE IT
append: '.youritem',
history: 'push',
historyTitle: true,
prefill: true,
// load pages on init until user can scroll
scrollThreshold: 1000,
// trigger scrollThreshold event when viewport is <100px from bottom of scroll area
// (I using 1000, that my users never have to wait for the loading of the next page...
// The calling it will start to working, before the screen shows the bottom of the page...)
status: '.page-load-status',
outlayer: msnry,
});
Okay, so replace it the .container to YOUR site container what includes the items (items = posts, images, anything) and replace it the .youritem to your grid item (so the div what include ONE item)!
Very important, that you replace the value of the path: to your pagination structure, where the current page's number is {{#}}! (So if your site works thus: yourdomain.com/page/2/ your path value is: 'page/{{#}}/')
Finally you make your design with .css (Included the masonry parameters (width, etc.)!)

Show loading gif when DataTable has been cleared

I have several options for my JQuery datatable which will clear the DataTable and load new data via WebSockets. Therefore I clear the Table contents with fnClearTable()and a few moments later I get the new data via my WebSocket.
This can last up to a few seconds and in the meantime I would like to display a loading image in my DataTable. How can I achieve this?
My event handler which clears the DataTable:
/* On Daterange change (e.g. Last 3 Days instead of Last 24h) */
$('#profitList_dateRange').change(function() {
var dateRangeHours = $("#profitList_dateRange").val();
var jsonParamObject = JSON.parse(dateRangeHours);
// Clear table
var profitList = $('#profitList').dataTable();
profitList.fnClearTable(); // Now I want to show the loading image!
socket.emit('load-statistics', (jsonParamObject));
});
One way to achieve it is if you have 2 divs (I assume that your divs are properly styled to the content inside of them):
<div id="profitList"> your table content </div>
<div id="profitListLoading"> show loading here </div>
Then in your handler:
$('#profitList_dateRange').change(function() {
var dateRangeHours = $("#profitList_dateRange").val();
var jsonParamObject = JSON.parse(dateRangeHours);
// Clear table
var profitList = $('#profitList').dataTable();
profitList.fnClearTable(); // Now I want to show the loading image!
$('#profitList').hide();
$('#profitListLoading').show();
socket.emit('load-statistics', (jsonParamObject));
});
In your handling of loaded data you should ofc. revert the change
$('#profitList').show();
$('#profitListLoading').hide();
Make sure you have processing: true
$('#example').dataTable({
processing: true
});
Then add:
$('.dataTables_processing', $('#example').closest('.dataTables_wrapper')).show();
If you want to add a GIF image you can change the markup as follows:
$('#example').dataTable({
oLanguage: {
sProcessing: "<img src='https://d13yacurqjgara.cloudfront.net/users/12755/screenshots/1037374/hex-loader2.gif'>"
},
processing: true
});
DEMO: http://jsfiddle.net/0m6uo54t/2
processing:
Enable or disable the display of a 'processing' indicator when the
table is being processed (e.g. a sort). This is particularly useful
for tables with large amounts of data where it can take a noticeable
amount of time to sort the entries.
https://datatables.net/reference/option/processing
[UPDATE] bProcessing is the legacy option, the new DT code uses processing

Reinitialize jQuery on Window Load event after AJAX

I have the following jQuery code that adjusts the product grid on the Window Load event:
$j(window).load(function(){
// Remove list class if thumbview
if ( $j("ul#products-list").hasClass("thumb_view") ) {
$j("ul#products-list").removeClass("list") };
// Equalize all thumb heights on switch if list view default
var maxHeight = 0;
$j('ul.thumb_view div.product-container').each(function() { maxHeight = Math.max(maxHeight, $j(this).height()); }).height(maxHeight +8);
// Undo equalized heights for list
$j('ul.list div.product-container').css("height","auto");
});
On the page we have a way of filtering the products based on for example price. When the price range is adjusted by the customer an AJAX call takes care of the actual filtering of products. However the jQuery script is not run again and the product grid fails to load correctly. I've done a lot of research and found to solutions that could solve this issue; use an "m-ajax-after" event, or use a jQuery delegate function.
The first option would involve this piece of code:
jQuery(document).bind('m-ajax-after', function (e, selectors, url, action) {
// reinitialize your script
});
Which I haven't managed to get it working. Knowledge on this function is very limited.
In my opinion the second option has the most chance on actual success however I haven't been able to reproduce this into code that actually works. Many topics are to be found I just can combine this with the (window).load function. What would be the right way to do this?
It's hard to say without seeing the complete code, but here's an idea:
function formatGrid() {
// Remove list class if thumbview
if ( $j("ul#products-list").hasClass("thumb_view") ) {
$j("ul#products-list").removeClass("list") };
// Equalize all thumb heights on switch if list view default
var maxHeight = 0;
$j('ul.thumb_view div.product-container').each(function() { maxHeight = Math.max(maxHeight, $j(this).height()); }).height(maxHeight +8);
// Undo equalized heights for list
$j('ul.list div.product-container').css("height","auto");
}
$j(window).load(function(){
formatGrid();
});
And then call this function on Ajax success:
$.ajax({
//your current ajax code
//and then call the formatting function
success: function() {
formatGrid();
}
});

Windows 8 Grid Template JS App, CSS manipulations dont show on all selected items in groupedItems view

I'm using the Win8 Grid View Template to display infos from a news site. In the lower menu bar i have implemented a function wich shuts off the titles, so that only the pictures are still visible.
This function is in a "global.js" file which is included in the "default.html" so it's available everywhere and it looks like this:
//function to turn titles off and on
function titleToggle() {
var titles = document.getElementsByClassName("item-overlay");
for (var i = 0; i < titles.length; i++) {
if (Global.titlesAreOn) {
titles[i].style.display = "none";
}
else {
titles[i].style.display = "";
}
}
Global.titlesAreOn = !Global.titlesAreOn;
};
So when i call this function from the menu bar it works for the first items, but when i scroll the end of the groupedItems view (hubview) the titles are still there. When i then scroll back to the beginning the titles are there again too.
I'm also calling the titleToggle function from the ready() function of the "groupedItems.js" to check whether or not to display the titles depending on a global variable. When i do that (whenever i come back to the hubpage) it works all the way, just as expected.
ui.Pages.define("/pages/groupedItems/groupedItems.html", {
navigateToGroup: function (key) {
nav.navigate("/pages/groupDetail/groupDetail.html", { groupKey: key });
},
ready: function (element, options) {
appbar.winControl.disabled = false;
appbar.winControl.hideCommands(["fontSizeBt"]);
appbar.winControl.showCommands(["titleToggle"]);
if (Global.titlesAreOn == false) {
Global.titlesAreOn = true;
Global.titleToggle();
}
I made a short video to show the problem, because its kinda hard to explain --> http://youtu.be/h4FpQf1fRBY I hope you get the idea?
Why does it work when i call it from the ready() function?
Does anyone have an idea? Is it some kind of automatic item caching in order to have better performance? And how could this be solved?
Greets and thanks!
First, here is why this might be happening - WinJS is using single page navigation for the app experience. This means that when you navigate to a new page, actually you don't. Instead the content is removed from the page and the new content is loaded in the same page. It is possible that at the moment you press the button not all elements have been loaded in the DOM and therefore they cannot be manipulated by your function. This is why when you call it from the ready() function it works - all contents are loaded in the DOM. It is generally better to do things in the ready() function.
About the behavior when you slide back left and the items are again reloaded with titles - for some reason the listView items are reloading. Maybe you are using live data from the news site and they are refreshing with the listView control's template again. I cannot know, but it doesn't matter. Hiding the elements is not the best approach I think. It is better to have two templates - one with a title element and one without. The button click handler should get the listView controls(they have to be loaded) and change their templates.
ready: function (element, options) {
var button = document.getElementById('btn');
button.addEventListener("click", btnClickHandler);
}
And the handler:
function btnClickHandler(e) {
var listView = document.getElementById("listView").winControl;
var template2 = document.getElementById("template2");
listView.itemTemplate = template2;
};

When Jquery jScrollPane is reinitialized, it goes back to the top. Why?

I'm using jquery library jScrollPane to set the custom scroll bar for the whole page.
scroll_bar = $('body>div').jScrollPane(
{
autoReinitialise: true,
showArrows: true,
maintainPosition: false
}).data('jsp');
When new content is added at the bottom of the page (while user is at the bottom of the page), I call:
scroll_bar.getContentPane().find(".content").append(some_content);
scroll_bar.reinitialise();
This reinitializes the scroll bar, but it takes the user to the top of the page. I would like the window to stay at the same spot. Any solutions?
Are you sure you're getting the data needed, I have no idea if this works, but have you tried:
scroll_bar = $('body>div').jScrollPane(
{
autoReinitialise: true,
showArrows: true,
maintainPosition: false
});
scroll_bar.data('jsp');
And would'nt you normally use the .scroll-pane class for this, and not the body>div selector ?
I would think maybe it should be something like this:
var api = scroll_bar.data('jsp');
api.reinitialise();
If you want the scroll bar to retain its position, you should set the
maintainPosition: true
Also, try reconstruct the code like this:
// Use jscrollpane api function to enable reinitialization
var scrollelement = $('body>div').jScrollPane({ maintainPosition: true});
var api = scrollelement.data('jsp');
api.getContentPane().html(result);
// Needed to apply jscrollpane after change new container type
api.reinitialise();
Hope this help :)
From the docs:
maintainPosition [boolean] - Whether you want the contents of the scroll pane to maintain it's position when you re-initialise it - so it doesn't scroll as you add more content (default true)
You set it to false.
For people who have issues re-initializing after the above:
function reinitialiseScrollpane() {
var settings = {
maintainPosition: true,
// add your settings here, below are examples
arrowButtonSpeed: 1,
showArrows: true,
animateScroll: true
};
pane.jScrollPane(settings);
var api = pane.data('jsp');
api.getContentPane().append();
api.reinitialise();
}
The important part is using the settings. Without re-initialising the settings, it can be glitchy. I have put it in a function call, so you simply call this whenever content is altered in any of your scroll panes (assuming you kept the .scroll-pane class with all regions)

Categories