Datatables Offset.top and scrollTop set to zero - javascript

I have a datatables table with infinite scrolling and no paging. When the user clicks a row, I insert a child row with details, and scroll the clicked row to the top.
This is all working perfectly.
However, I have a button on the child row that shows a bootstrap modal.
When the user dismisses the modal, the offset() and scrolltop() values for the dataTables_scrollBody are set to zero.
This causes the datatable to scroll incorrectly.
So I saved the values before showing the modal. Then after the model is hidden, I attempted to set the offset and scrolltop to the saved values.
I get no error, but the values stay zero.
Here is the code I am using to scroll the grid:
var container = $('#MainContent_grdBrowse,div.dataTables_scrollBody');
var scrollTo = $('.shown');
container.animate({
scrollTop: scrollTo.offset().top - container.offset().top + container.scrollTop()
});
Here is the code to restore the values:
container.offset({ top: dt_OffSetTop, left: dt_OffSetLeft });
container.scrollTop(dt_Scrolltop);
I get the same results in Firefox & IE.
Edit:
Here is the code where I save, and restore the values.
I save the values to hidden fields in the datatables click event:
document.getElementById('MainContent_dt_OffSetTop').value = container.offset().top;
document.getElementById('MainContent_dt_OffSetLeft').value = container.offset().left;
document.getElementById('MainContent_dt_Scrolltop').value = container.scrollTop();
document.getElementById('MainContent_rw_OffSetTop').value = scrollTo.offset().top;
document.getElementById('MainContent_rw_OffSetleft').value = scrollTo.offset().left;
I restore the values in the hidden.bs.modal event:
$('#ModalDisplayNotes').on('hidden.bs.modal', function (e) {
var dt_OffSetTop = document.getElementById('MainContent_dt_OffSetTop').value;
var dt_OffSetLeft = document.getElementById('MainContent_dt_OffSetLeft').value;
var dt_Scrolltop = document.getElementById('MainContent_dt_Scrolltop').value;
var rw_OffSetTop = document.getElementById('MainContent_rw_OffSetTop').value;
var rw_OffSetleft = document.getElementById('MainContent_rw_OffSetleft').value;
var container = $('#MainContent_grdBrowse,div.dataTables_scrollBody');
var scrollTo = $('.shown');
container.offset({ top: dt_OffSetTop, left: dt_OffSetLeft });
container.scrollTop(dt_Scrolltop);
scrollTo.offset({ top: rw_OffSetTop, left: rw_OffSetleft });
})
I displayed the values when I saved them and they were correct. I displayed the values returned from the hidden fields in the hidden-bs-modal event, and they were correct. Then I set the values to the datatable body. Then when I query the values from the datatables body, they are zero.

Related

Kendo Grid jumps to top after onSave

I have a grid that i need to set:
scrollable: {
virtual: true
},
When users edit a cell then updates (or onSave(e)) their changes. The grid resets back to the top of the page. I don't know why. Users lose their place every time they try to change a cells contents.
When i make
scrollable: false,
it stays put. I think this is a huge bug in Telerik Kendo. Has anyone figured out how to stay in place on the grid after saving changes?
UPDATE
This problem only occurs in IE 11. Unfortunately my client can only use IE11.
I think this works for you:
Use GridViewRowInfo to get row info of selected row and set scroll to your custom row and column.
if (this.radGridView1.SelectedCells.Count > 0)
{
GridViewRowInfo row = this.radGridView1.SelectedCells[0].RowInfo;
radGridView1.TableElement.ScrollTo(row.Index, 0);
}
The answer is to save your current location before you bind.
in
onGridBinding(){
_currentLeftPosition = $(".k-virtual-scrollable-wrap").scrollLeft();
}
in onGridBound(){
//Go Back to previous position
var vs = mainGrid.wrapper.find('.k-grid-content').data('kendoVirtualScrollable');
var scrollGridContentOffsetTop = mainGrid.wrapper.find('.k-grid-content').offset().top;
var selectContentOffsetTop = mainGrid.content.offset().top;
var distanceTop = selectContentOffsetTop - scrollGridContentOffsetTop;
var scrollTop = vs.verticalScrollbar.scrollTop();
$("#mainGrid div.k-virtual-scrollable-wrap").animate({scrollTop: distanceTop + scrollTop,scrollLeft: _currentLeftPosition}, 0);
$("#mainGrid div.k-scrollbar-vertical").animate({scrollTop: distanceTop + scrollTop}, 0);
}

Get position of table cell within overflow element

I want to get the position/offset of a table cell and then using this data I want to append and position a new element in the exact same position.
The code to achieve this is as follows:
function addBlock()
{
// get the cell position
var cellPosition = $('.item').position(),
cellPositionTop = cellPosition.top,
cellPositionLeft = cellPosition.left;
// append the overlay
var blockOverlay = $('<div class="blockOverlay"></div>').appendTo('.container').hide();
// set the overlay width and height to the same as the cell
blockOverlay.css({
'background-color':'blue',
'width': $('.item').outerWidth(),
'height': $('.item').outerHeight()
});
// position the overlay in the same place as the cell
blockOverlay.css({
'position': 'absolute',
'top': cellPositionTop,
'left': cellPositionLeft
});
// show the overlay
blockOverlay.show();
}
The table containing the cell is quite big and sits inside an overflowing element meaning that the table cell may be offscreen. If the above code is run without scrolling then it works fine, however if I scroll and then run it, the offset is incorrect. This is because even though I am using position() and not offset() it is getting the cell position relative to its parent (.container) at the time of calling the function, rather that its position regardless of the scroll position.
How can I solve this?
Here is a fiddle that shows the problem: https://jsfiddle.net/25e6qmnh/
Try clicking the button at various scroll positions and you will see that blue box only ever overlays the red cell when at the start position. It should ALWAYS overlay the red cell regardless of the scroll position.
You need to add $('.container').scrollLeft() to your cellPositionLeft, so the new line will look like this:
cellPositionLeft = cellPosition.left + $('.container').scrollLeft();
Your are not calculating the position with the scroll width, so you need to add it. You will also need to do the same with scrollTop(), but that will be left for you.
Here is a working example: https://jsfiddle.net/qorpucwq/
You can initialize the value of the element .item once and then it works fine.
function addBlock()
{
// get the cell position
var
cellPositionTop = cellPosition.top,
cellPositionLeft = cellPosition.left;
// append the overlay
var blockOverlay = $('<div class="blockOverlay"></div>').appendTo('.container').hide();
// set the overlay width and height to the same as the cell
blockOverlay.css({
'background-color':'blue',
'width': $('.item').outerWidth(),
'height': $('.item').outerHeight()
});
// position the overlay in the same place as the cell
blockOverlay.css({
'position': 'absolute',
'top': cellPositionTop,
'left': cellPositionLeft
});
// show the overlay
blockOverlay.show();
}
var cellPosition;
$(document).ready(function(){
cellPosition = $('.item').position();
$('.clickme').on('click', function(e){
e.preventDefault();
addBlock();
});
});
Here is the working fiddle.

How to get correct div innerHeight the first time?

I have a hidden sub nav with height set to 0. Inside of that div are several sections of sub navs.
I get the name of the section that is clicked, then get the innerHeight of that div. Then using that height, I animate the .sub_navigation height from 0 to the value. However for some reason the first time you click (get the value) it's off, too high, the 2nd time it's perfect.
How would you fix this?
Angular (converted from jQuery)
// Controller for Nav
app.controller('NavController', function(){
// Property of Controller
this.clicked = function(menuItem) {
console.log(menuItem);
var contentHeight = $('.'+menuItem+'-content').innerHeight();
var content_height = $('.'+menuItem+'-content').innerHeight();
$('.sub_navigation').css({'height' : '0px'});
$('.'+menuItem+'-content').siblings().css({'display' : 'none'});
$('.'+menuItem+'-content').css({'display':'block', 'height':'auto'});
$('.sub_navigation').animate({
height: contentHeight
});
console.log('content_height = '+content_height);
console.log(contentHeight);
};
});
jQuery
$(document).delegate(".navigation-links a", "click", function(){
var myContent = $(this).attr("data-content");
var contentHeight = $("."+myContent+"-content").innerHeight();
$("."+myContent+"-content").siblings().css({"display":"none"});
$("."+myContent+"-content").css({"display":"block", "height":"auto"});
$(".subNavigation").animate({
height: contentHeight
});
});
If you click on Grow, the first time height is 400, the 2nd time it's 266 :(
The innerHeight documentation says that:
The value reported by .innerHeight() is not guaranteed to be accurate
when the element's parent is hidden. To get an accurate value, you
should show the parent first, before using .innerHeight().
So although the parent is visible, maybe the fact that the element itself is invisible makes the height value to be inaccurate.
Have you tried, changing the order?
//Make the sub menu visible first
$('.'+menuItem+'-content').siblings().css({'display' : 'none'});
$('.'+menuItem+'-content').css({'display':'block', 'height':'auto'});
var contentHeight = $('.'+menuItem+'-content').innerHeight();
var content_height = $('.'+menuItem+'-content').innerHeight();
$('.sub_navigation').css({'height' : '0px'});
....
Try to show the menuItem while getting the height:
this.clicked = function(menuItem) {
var menu = $('.'+menuItem+'-content');
menu.show();
var contentHeight = menu.outerHeight();
menu.hide();
...

Making nav bar effects using scroll AND click in jQuery

I want a nav to highlight (or something similar) once a user clicks on it AND when a user scrolls to the corresponding section.
However, on my computer when one clicks on any of the nav events after3, only nav event 3 changes. I'm guessing this is because after one clicks on 4 or 5, the scroll bar is already at the bottom of the page, so 4 and 5 never reach the top. The only div at the top is post 3, so my code highlights nav event 3 and ignores the click.
Is there any way I can fix this? Ive tried if statements (only highlight nav event if it's at the top AND the scrollbar isn't at the bottom or the top isn't the last item).
Here is a more accurate fiddle, using a fix below showing what I am talking about. The fix now highlights on scroll, but if you click option 5, it will not highlight.
$('.option').children('a').click(function() {
$('.option').css('background-color', '#CCCCCC;');
$(this).css('background-color', 'red');
var postId = $($(this).attr('href'));
var postLocation = postId.offset().top;
$(window).scrollTop(postLocation);
});
$(window).scroll(function() {
var scrollBar = $(this).scrollTop();
var allPosts = [];
var post = $('.content').offset();
var lastPost = allPosts.legnth-1
var windowHeight = $(window).height();
var bottomScroll = windowHeight-scrollBar;
$(".content").each(function(){
allPosts.push($(this).attr('id'));
});
i = 0;
for(i in allPosts){
var currentPost = "#"+allPosts[i];
var postPosition = $(currentPost).offset().top;
if (scrollBar >= postPosition){
$('.option').css('background-color', '#CCCCCC');
$('#nav'+allPosts[i]).css('background-color', 'red');
};
};
});
I think you've overdone your scroll() handler, to keep it simple you just needs to check if the scrollbar/scrollTop reaches the '.contents' offset top value but should not be greater than its offset().top plus its height().
$(window).scroll(function () {
var scrollBar = $(this).scrollTop();
$(".content").each(function (index) {
var elTop = $(this).offset().top;
var elHeight = $(this).height();
if (scrollBar >= elTop - 5 && scrollBar < elTop + elHeight) {
/* $(this) '.content' is the active on the vewport,
get its index to target the corresponding navigation '.option',
like this - $('.Nav li').eq(index)
*/
}
});
});
And you actually don't need to set $(window).scrollTop(postLocation); because of the default <a> tag anchoring on click, you can omit that one and it will work fine. However if you are looking to animate you need first to prevent this default behavior:
$('.option').children('a').click(function (e) {
e.preventDefault();
var postId = $($(this).attr('href'));
var postLocation = postId.offset().top;
$('html, body').animate({scrollTop:postLocation},'slow');
});
See the demo.
What you are trying to implement from scratch, although commendable, has already been done by the nice folks at Bootstrap. It is called a Scrollspy and all you need to do to implement it is include Bootstrap js and css (you also need jquery but you already have that) and make some minor changes to your html.
Scrollspy implementation steps.
And here is a demonstration. Notice only one line of js. :D
$('body').scrollspy({ target: '.navbar-example' });

jQuery sliding table header

My ASP.Net application generates an <asp:Table> from the codebehind. What I need is for the header row of that table to slide down the page as the user scrolls past it.
I've tried the following approach using JavaScript:
window.onscroll = function () {
//grab the current scroll position
var scrollY = document.body.scrollTop;
if (scrollY == 0) {
if (window.pageYOffset)
scrollY = window.pageYOffset;
else
scrollY = (document.body.parentElement) ? document.body.parentElement.scrollTop : 0;
}
//grab the position of the header row I want to slide
var head = $("tr[name='headerrow']").offset();
var headtop = head.top;
var headleft = head.left;
//if the user has scrolled past the top of the header row
if (scrollY > headtop) {
//code correctly reaches this point as alerts show
//alert('got here');
//position the header row to the same as the scroll position
$("tr[name='headerrow']").offset({ top: scrollY, left: headleft });
}
}
I can't get the row to move. There are no error message to be seen on the various browsers developer tools.
Any help would be appreciated.
EDIT: I tried calling the offset() function on the children of the row (i.e. all of the <th> elements) like this:
$("tr[name='headerrow']").children().offset({ top: scrollY, left: headleft });
This now works but of course, they're all pushed over to the left because I'm using the left value of the header row itself... I'll keep this updated with my progress but in the meantime any assistance is appreciated as always.
Solution:
Use the children() method on the table row to allow you to change the offset of each of the <th> elements. The left value can be omitted from the offset() method, i.e.
$("tr[name='headerrow']").children().offset({ top: scrollY });
You cannot set the offset to any element. You should use css method and set the top and left parameters.

Categories

Resources