ExtJs grid.Panel store: keep scrollbar position after load/reload - javascript

I'm using grid.Panel in Sencha ExtJs 4.0.2a and I reload a Json Store every 60 seconds.
I was wondering if there is a way to preserve the position of the scrollbar after a data load.
So that the user can continue to look at the records he was looking before the load..
I reload the data in the grid using a Task:
var task = {
run: function(){
Ext.getCmp(panelGridId).getStore().load({
//Callback function after loaded records
callback: function(records) {
//Hide grid if empty records
if (Ext.isEmpty(records)) {
Ext.getCmp(panelGridId).setVisible(false);
}
else {
if (Ext.getCmp(panelGridId).isHidden()) {
Ext.getCmp(panelGridId).setVisible(true);
Ext.getCmp(panelGridId).doComponentLayout();
}
}
}
});
},
interval: 60000 //60 seconds
};
Ext.TaskManager.start(task);
After the data load the scrollbar position is reset to the top..
Q: Is there a way to maintain the scrollbar position after the data load?
Thanks in advance!

Try this bad boy to preserve scroll position on refresh:
http://docs-devel.sencha.com/extjs/4.2.1/#!/api/Ext.grid.View-cfg-preserveScrollOnRefresh
This works for me on my tree view.
viewConfig: {
preserveScrollOnRefresh: true
}

Here's how you would use preserveScrollOnRefresh in your Grid :
Ext.define('js.grid.MyGrid', {
extend: 'Ext.grid.Panel',
viewConfig: {
preserveScrollOnRefresh: true
}
Here's a JSFiddle which demonstrates this :
http://jsfiddle.net/cdbm6r0o/7/
However when you select a row it doesn't seem to work quite right. I am not sure if this is a bug.
The 'refresh' event is triggered from this code :
grid.store.loadData(dataToLoad);
I'm unaware of any other events which trigger a 'refresh'
Additional Notes :
I had the Ext.toolbar.Paging as a require. Even though I didn't use it, it screwed up the scroll preserve when I had one or more rows selected, so make sure you remove the Paging from your requires.
The scroll preserve does not appear to work if I use the bufferedrenderer plugin on the table at the same time.
tablePanel.getView().focusRow(recrow) is also interesting to look at, but also does not work with bufferedrenderer.

You can use the preserveScrollOnReload view config property:
viewConfig: {
preserveScrollOnReload: true
},

Related

Bootstrap tooltip gets stuck if element changes when visible

I am using Bootstrap 5.1.3 (in Rails). Our application consists of dynamically loaded data, that is not always the fastest to load (some complicated SQL queries / huge amounts of data to make calculations with).
We use tooltips on different elements to show extra information / indicate (click)actions. Tooltips are added like this.
On the element that should get the tooltip:
data-bs-toggle="tooltip" data-bs-placement="top" title={question.questionDescription}
In that Bootstrap file:
componentDidUpdate(previousProps, previousState)
{
// Enable all tooltips.
TooltipHelper.enableTooltips([].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]')));
}
And then TooltipHelper:
static enableTooltips(targets)
{
var enabledTooltips = targets.map(function (target) {
return new bootstrap.Tooltip(target, { trigger: 'hover' });
});
}
The tooltips work, but don't always go away. My guess is that when a tooltip is shown (because hovering over something) and then that element (or a parent of that element) gets changed, for example the content of it, the tooltip stays there. No matter if I click somewhere of hover over other elements.
I've tried adding a delay within the enableTooltips()-function. This seems to work, but the needed delay is too big. Also, it still breaks when elements are dynamically added and content is loaded, when the page isn't reloaded.
My hacky solution:
static enableTooltips(targets)
{
setTimeout(function() {
var enabledTooltips = targets.map(function (target) {
return new bootstrap.Tooltip(target, { trigger: 'hover' });
});
}, 5000);
}
Anyone know of a solution? Thanks

Suspend panning in firefox

We use offset manipulation (script) to fix columns and rows in a table.
$(document).ready(function() {
$("#xTableDiv").scroll(function() {
setOffset($(this));
});
});
function setOffset($div) {
$div.find("td.fixedRow").css("top", $div.scrollTop());
$div.find("td.fixedColumn").css("left", $div.scrollLeft());
}
https://jsfiddle.net/fpbo1dsx/
In history that works fine.
Now is for vertical scrolling render html delayed.
https://developer.mozilla.org/en-US/docs/Mozilla/Performance/Scroll-linked_effects
The only known way to change this, is set apz.disable_for_scroll_linked_effects to true (about:config) :-(
Is there a better way?

jQuery: infinite scroll and the back button

OK so I know this causes problems with everyone, and it's causing problems with me too. I'm using the infinite scroll plugin on a client's site, in combination with the isotope plugin to load in their products sequentially, the problem is though as they have 1000's of products, anyone browsing the site then clicking into a product, when they click the back button they'll be returned back to the top (or just above the fold of page one), which is causing quite a lot of issues.
My markup is as follows below:
$(window).load(function () {
var $container = $('.products-grid-wrap');
$container.imagesLoaded(function () {
$container.isotope({
itemSelector: '.products-grid-block',
filter: '*:not(.hidden), .products-grid-block',
animationEngine: 'best-available',
layoutMode: "perfectMasonry",
perfectMasonry: {
columnWidth: 280,
rowHeight: 310
}
});
$container.infinitescroll({
navSelector: '#page_nav', // selector for the paged navigation
nextSelector: '#page_nav a', // selector for the NEXT link (to page 2)
itemSelector: '.regular-product-block, .products-grid-block', // selector for all items you'll retrieve
pixelsFromNavToBottom: Math.round($(window).height() * 1.5),
bufferPx: Math.round($(window).height() * 1.5),
loading: {
finishedMsg: 'No more products to load.',
img: 'http://www.by-form.net/wp-content/uploads/2014/11/ajax-loader-big.gif'
}
},
// call Isotope as a callback
function (newElements) {
var $newElems = $(newElements);
$newElems.imagesLoaded(function () {
$container.isotope('insert', $newElems);
$('.products-grid-rollover-block').hide();
if(newElements.length > 0){
setTimeout(function () {
$container.infinitescroll('retrieve');
$('.products-grid-wrap').isotope('reLayout');
//$('.products-grid-wrap').isotope({
//sortBy: 'category',
//sortAscending: false });
}, 1000);
}
});
});
setTimeout(function () {
$container.infinitescroll('retrieve');
}, 3000);
});
});
Any solutions or suggestions would be massively appreciated!
You can try scroll-frame.It is a bit old may be the answer for you. Here is a link to an infinite scroll demo using it.
scrollFrame will hijack the user's click for elements that match the query selector you pass in and instead of reloading the page it will append a modal-like iframe that sits on top of your viewport and points to the element's href. It then uses HTML5 history APIs to make the back-button function as expected.
This can be a bit new solution of such problems.
https://github.com/highrisehq/snapback_cache
This is what is say's ...
Many apps today have some concept of an infinite scrolling feed: Facebook, Twitter, LinkedIn and many more. Almost all of them suffer from the same problem. If you click on something in the feed that brings you to a new page, when you hit the back button or try to return to that original feed, your place is lost. All the scrolling is gone.
At Highrise we had that same problem. So this is the library we use to fix that. We call it our Snapback Cache, and it's made a big improvement to how people can use infinite scroll in our app and still get a lot of work done without losing their place.
We solved this problem with a combination of (1) opening the page linked to on the infinite scroll page in a new tab; (2) using javascript to return to the parent.
Since I have seen a lot of comment about the difficulty of returning to the parent, I am posting our code for that below. The two functions are put into onclick attributes in the anchor tags used for the navigation buttons.
Using the name of the parent window solves the problem of intervening tabs opened before returning to the parent; without this, the tab returned to could be the most recently opened tab, rather than the parent.
/**
* open url in separate tab
* saves name of parent window for easy return
* #param url
*/
function gotoTab(url)
{
window.name = 'parent';
window.open(url);
}
/**
* uses name of parent
*/
function returnToParent()
{
var goBack = window.open('', window.opener.name);
window.top.close();
goBack.focus();
}

Selecting row in kendo grid when virtualization is enabled

I'm using kendoUI grid widget to display dataset. Because size of dataset is quite large (200-400k) I'm using virtualization feature to improve performance and usability. When setting grid up I have faced with the following problem: because virtualization is enabled, grid DOM objects (i mean table rows here) are refreshed every time when page is changed. That implementation of grid results in the following behavior: I can select row but after scrolling down to next page and scrolling back selection disappears. Here is example where this problem can be reproduced: http://trykendoui.telerik.com/OkOg
Maybe someone has similar problem and can offer some workaround.
You can restore the selection in the grid's dataBound event, e.g. like this (note that this only works for single row selection, so you might need to adapt for other modes):
$("#grid").kendoGrid({
dataSource: dataSource,
change: function () {
this._lastSelectedItem = this.dataItem(this.select());
},
dataBound: function () {
var row;
if (this._lastSelectedItem) {
row = $(this.tbody).find("tr[data-uid='" + this._lastSelectedItem.uid + "']")
if ($(row).length > 0) {
// or this.select(row); if you don't mind the
// change event getting triggered again
$(row).addClass("k-state-selected");
}
}
},
height: 430,
scrollable: {
virtual: true
},
selectable: true,
columns: columns
});

Set the scroll position in WinJS.UI.ListView

I want to scroll my ListView on a specific item automatically. The ListView must auto-scroll to an item from his index.
listView.ensureVisible(itemIndex);
But it's not working. Another alternative:
yourListView.currentItem = { index: 8, hasFocus: true, showFocus: true }
And it's failed also.
How can this be solved?
Generally you have to wrap your call to ensureVisible(index) in a call to msSetImmediate. Not sure exactly why this is the case, probably a bug, but works for me. Example:
msSetImmediate(function (){ listView.ensureVisible(4);} );
If you look at the documentation for setImmediate (msSetImmediate being a Microsoft specific implentation), the function is described as:
Requests that a function be called when current or pending tasks are complete, such as events or screen updates.
This does make a bit of sense as it sounds like it ensures that all list view animating etc is completed before making your call to ensure an item is visible.
See this thread for a related post: http://social.msdn.microsoft.com/Forums/en-US/winappswithhtml5/thread/2f11e46f-9421-4e31-93d3-fca06563ec41/
I might have an answer for you. You can't set the scroll position of a ListView immediately because the layout for the ListView has not been done yet and so attempting to scroll it to a position is futile. So you have to wait until the ListView gets to that state where its layout has been calculated. Here's how...
myListView.onloadingstatechanged = function () {
if (app.sessionState.homeScrollPosition && myListView.loadingState == "viewPortLoaded") {
myListView.scrollPosition = app.sessionState.homeScrollPosition;
app.sessionState.homeScrollPosition = null;
}
};
You can see this in context by looking at the /pages/home/home.js file in my open source codeSHOW project.
Hope that helps.

Categories