offset is undefined in Header Fixed - javascript

I now have a code to fixed the header of my tables and it works fine. But this function have a warning :
Error: TypeError: $(...).offset(...) is undefined
My code (I use bootstrap):
function goheadfixed(classtable) {
$(classtable).wrap('<div class="fix-inner">');
$('.fix-inner').wrap('<div class="fix-outer" style="position: relative;"></div>'); //this is relative cause the header will be absolute
$('.fix-outer').append('<div class="fix-head"></div>');
$('.fix-head').prepend($('.fix-inner').html()); // agrego la tabla
$('.fix-head table').find('caption').remove();
//$('.fix-head table').removeAttr('style');
$('.fix-head table').css('width','100%');
$('.fix-head').css('width', $('.fix-inner table').outerWidth(true)+'px');
$('.fix-head').css('height', $('.fix-inner table thead').outerHeight(true)+'px');
var ithead = parseInt($('.fix-inner table thead').offset().top);
var divfix = parseInt($('.fix-inner').offset().top);
var itop = ithead-divfix;
$('.fix-head').css({'position':'absolute', 'overflow':'hidden', 'top': itop+'px', 'left':0, 'z-index':100 });
$(window).scroll(function () {
var vscroll = $(window).scrollTop();
if(vscroll >= ithead)
$('.fix-head').css('top',(vscroll-divfix)+'px');
else
$('.fix-head').css('top', itop+'px');
});
/* If the windows resize */
$(window).resize(goresize);
}
function goresize() {
$('.fix-head').css('width', $('.fix-inner table').outerWidth(true)+'px');
$('.fix-head').css('height', $('.fix-inner table thead').outerHeight(true)+'px');
}
I call my function:
goheadfixed('table.fixed');
Then when I put other code javascript below, my code doesn't work but when put above, it works fine! :
How can I delete this warninng?
EDIT (adding details posted as an answer):
Oh. I'm sorry, I forgot say the "warning" only appears when I don't use the function.
If I call the funcion goheadfixed('table.fixed'); all right, but if I don't call this function, the warning is showed.

On line 14, $('.fix-inner table thead') is either referring to elements that do not exist or are hidden. It sounds as if you are finding at least one element with display:none set, and it's returning an undefined number because of that.
To fix this, you can add the visible selector $("thead:visible") with each element.

Related

jquery click-function is executed when page loads but not when clicked

I use jQuery to get the height of a div #img-copyright when the page is loaded, write in the var copyrightHeight and set the height of the div to 0.
When a different div is clicked, the function showImgCopyright() should set the max-height of the div #img-copyright to the content of the var.
I made two tries.
First one:
var copyrightHeight;
$(document).ready(function () {
copyrightHeight = $("#img-copyright").height();
console.log(copyrightHeight);
// just used to see if the height got written in the var - it is
$("img-copyright").css("max-height", 0);
$("#show-img-copyright").click(showImgCopyright());
function showImgCopyright() {
$("#img-copyright").css("max-height", copyrightHeight);
}
});
Second one:
var copyrightHeight;
$(document).ready(function () {
copyrightHeight = $("#img-copyright").height();
console.log(copyrightHeight);
// just used to see if the height got written in the var - it is
$("img-copyright").css("max-height", 0);
$("#show-img-copyright").click(function (){
$("#img-copyright").css("max-height", copyrightHeight);
});
});
In the first example the function is directly executed after the page is loaded and NOT when clicking the div (not the way I wanted it to be).
In the second example it works as I wanted it - the function just is executed when clicking the div.
But I don't get why.
How can I make it work with an extra function like in the first example?
Thank you very much.
I also found out, I forgot a # in the line $("img-copyright").css("max-height", 0);.
So the right code would be:
var copyrightHeight;
$(document).ready(function () {
copyrightHeight = $("#img-copyright").height();
$("#img-copyright").css("max-height", 0);
$("#show-img-copyright").click(showImgCopyright);
function showImgCopyright() {
$("#img-copyright").css("max-height", copyrightHeight);
}
});

jQuery slideDown not working on element with dynamically assigned id

EDIT: I cleaned up the code a bit and narrowed down the problem.
So I'm working on a Wordpress site, and I'm trying to incorporate drop-downs into my menu on mobile, which means I have to use jQuery to assign classes and id's to my already existing elements. I have this code that already works on premade HTML, but fails on dynamically created id's.
Here is the code:
...
var menuCount = 0;
var contentCount = 0;
//find the mobile menu items
var submenus = $('[title="submenu"]');
if (submenus.length && submenus.parent('.fusion-mobile-nav-item')) {
console.log(submenus);
submenus.addClass('dropdown-title').append('<i id="dropdown-angle" class="fa fa-angle-down" aria-hidden="true"></i>');
submenus.each(function() {
$(this).attr("href", "#m" + menuCount++);
})
var content = submenus.parent().find('ul.sub-menu');
content.addClass('dropdown-content');
content.each(function() {
$(this).attr("id", "m" + contentCount++);
})
}
$(document).on('click', '.dropdown-title', function(e) {
var currentAttrValue = $(this).attr('href');
if ($(e.target).is('.d-active') || $(e.target).parent('.dropdown-title').is('.d-active')) {
$(this).removeClass('d-active');
$(currentAttrValue).slideUp(300).removeClass('d-open');
} else {
$('.dropdown-title').removeClass('d-active');
$('.dropdown-content').slideUp(300).removeClass('d-open');
$(this).addClass('d-active');
console.log($(currentAttrValue));
//THIS LINE FAILS
$(currentAttrValue).slideDown(300).addClass('d-open');
}
e.preventDefault();
});
I've registered the elements with the class dropdown-title using $(document).on(...) but I can't figure out what I need to do to register the elements with the custom ID's. I've tried putting the event callback inside the .each functions, I've tried making custom events to trigger, but none of them will get the 2nd to last line of code to trigger. There's no errors in the console, and when I console log the selector I get this:
[ul#m0.sub-menu.dropdown-content, context: document, selector: "#m0"]
0
:
ul#m0.sub-menu.dropdown-content
context
:
document
length
:
1
selector
:
"#m0"
proto
:
Object[0]
So jQuery knows the element is there, I just can't figure out how to register it...or maybe it's something I'm not thinking of, I don't know.
If you are creating your elements dynamically, you should be assigning the .on 'click' after creating those elements. Just declare the 'on click' callback code you posted after adding the ids and classes instead of when the page loads, so it gets attached to the elements with .dropdown-title class.
Check this jsFiddle: https://jsfiddle.net/6zayouxc/
EDIT: Your edited JS code works... There also might be some problem with your HTML or CSS, are you hiding your submenus? Make sure you are not making them transparent.
You're trying to call a function for a attribute, instead of the element. You probably want $(this).slideDown(300).addClass('d-active'); (also then you don't need $(this).addClass('d-active'); before)
Inside submenus.each loop add your callback listener.
As you are adding the class dropdown-title dynamically, it was not available at dom loading time, that is why event listener was not attached with those elemnts.
var menuCount = 0;
var contentCount = 0;
//find the mobile menu items
var submenus = $('[title="submenu"]');
if (submenus.length && submenus.parent('.fusion-mobile-nav-item')) {
console.log(submenus);
submenus.addClass('dropdown-title').append('<i id="dropdown-angle" class="fa fa-angle-down" aria-hidden="true"></i>');
submenus.each(function() {
$(this).attr("href", "#m" + menuCount++);
// add callback here
$(this).click( function(e) {
var currentAttrValue = $(this).attr('href');
if ($(e.target).is('.d-active') || $(e.target).parent('.dropdown-title').is('.d-active')) {
$(this).removeClass('d-active');
$(currentAttrValue).slideUp(300).removeClass('d-open');
} else {
$('.dropdown-title').removeClass('d-active');
$('.dropdown-content').slideUp(300).removeClass('d-open');
$(this).addClass('d-active');
console.log($(currentAttrValue));
$(currentAttrValue).slideDown(300).addClass('d-active');
}
e.preventDefault();
});
})
var content = submenus.parent().find('ul.sub-menu');
content.addClass('dropdown-content');
content.each(function() {
$(this).attr("id", "m" + contentCount++);
})
}
Turns out my problem is that jQuery is adding to both the mobile menu and the desktop menu, where the desktop menu is being loaded first when I search for that ID that's the one that jQuery finds. So it turns out I was completely wrong about my suspicions.

Transfer data from one page to another jQuery Mobile

I using PhoneGap to create a Geolocation App following this excellent tutorial (link). Unfortunatelly, I'm having an issue that I can't figure out. The relevant parts that are giving me a headache are these:
//Section 1
$('#history').on('pageshow', function () {
tracks_recorded = window.localStorage.length;
$("#tracks_recorded").html("<strong>" + tracks_recorded + "</strong> workout(s) recorded");
$("#history_tracklist").empty();
for (i = 0; i < tracks_recorded; i++) {
$("#history_tracklist").append("<li><a href='#track_info' data-ajax='false'>" + window.localStorage.key(i) + "</a></li>");
}
$("#history_tracklist").listview('refresh');
});
//Section 2
$("#history_tracklist li a").on('click', function () {
$("#track_info").attr("track_id", $(this).text());
});
//Section 3
$('#track_info').on('pageshow', function () {
var key = $(this).attr("track_id");
$("#track_info div[data-role=header] h1").text(key);
var data = window.localStorage.getItem(key);
data = JSON.parse(data);
});
Section 1 works just fine, the data is stored, and the list is created without any issues. But then in Section 2 is when everything goes to hell. By clicking on the element, a new attribute (track_id) is supposed to be created, but it doesn't. Therefore, in Section 3, the "var key" won't get a value, and as a consequence, "var data" will be null also. As you can imagine, nothing works from there. What am I doing wrong here? I only included what I considered the relevant code, but if more is needed I'll do so. Thansk!
In section 2, I think you just need to delegate click handling to the "#history_tracklist" container, as follows :
$("#history_tracklist").on('click', "li a", function () {
$("#track_info").attr("track_id", $(this).text());
});
Without delegation you have a rule saying :
when any existing li a element within #history_tracklist is clicked execute my function
With delegation, you have a rule saying :
when any existing or future li a element within #history_tracklist is clicked execute my function

Making editable table work cross-browser

I've been working on an ASP.NET page containing a ListView. When the user clicks a row, the content of the last (visible) column of this (once parsed) HTML table is replaced with a textbox (by means of jQuery), making the value editable.
So far, this works like a charm in Chrome but no joy in IE10.
In this jsfiddle, the value becomes editable but then the Save button doesn't work as expected.
In IE the textbox doesn't appear. Funny detail: if I comment out the four vars (invNr, newInvNr, oldHtml and spanWidth), the input element DOES appear in IE10 but of course I have no data to work with. Really REALLY weird.
The jQuery:
$(document).ready(function () {
$('tr[id*="itemRow"]').click(function () {
$clickedRow = $(this);
//this makes sure the input field isn't emptied when clicked again
if ($clickedRow.find('input[id$="editInvNr"]').length > 0) {
return;
}
var invNr = $clickedRow.find('span[id$="InvoiceNumber"]').text(),
newInvNr = '',
oldHtml = $clickedRow.find('span[id$="InvoiceNumber"]').html(),
spanWidth = $clickedRow.find('span[id$="InvoiceNumber"]').width();
$clickedRow.find('span[id$="InvoiceNumber"]').parent('td').html('<input type="text" ID="editInvNr"></input>');
$clickedRow.find('input[id="editInvNr"]').val(invNr).focus().on('input propertychange', function () {
$clickedRow.find('span[id$="SaveResultMsg"]').hide();
$clickedRow.find('td[id$="SaveOption"]').show();
$clickedRow.find('input[id*="btnSaveInvNrFormat"]').show();
newInvNr = $(this).val();
if (newInvNr == $clickedRow.find('span[id$="InvoiceNumber"]').text()) {
$clickedRow.find('td[id$="SaveOption"]').hide();
}
});
});
$('tr[id*="itemRow"]').focusout(function () {
$rowLosingFocus = $(this);
var previousValue = $rowLosingFocus.find('input[id$="editInvNr"]').val();
$rowLosingFocus.find('input[id$="editInvNr"]').closest('td').html('<asp:Label ID="lblInvoiceNumber" runat="server" />');
$rowLosingFocus.find('span[id$="InvoiceNumber"]').text(previousValue);
});
});
function UpdateInvoiceNrFormat(leButton) {
$buttonClicked = $(leButton);
$buttonClicked.focus();
var companyName = $buttonClicked.closest('tr').find('span[id$="lblCompanyName"]').text(),
invoiceType = $buttonClicked.closest('tr').find('span[id$="lblInvoiceType"]').text(),
invNrFormat = $buttonClicked.closest('tr').find('span[id$="lblInvoiceNumber"]').text();
PageMethods.UpdateInvoiceNumberFormat(companyName, invoiceType, invNrFormat, onSuccess, onError);
function onSuccess(result) {
$buttonClicked.hide();
$buttonClicked.siblings('span[id$="SaveResultMsg"]').text(result).show();
}
function onError(result) {
$buttonClicked.hide();
$buttonClicked.siblings('span[id$="SaveResultMsg"]').text('Error:' + result).show();
}
}
I've tried various combinations of jQuery statements, chaining and avoiding chaining, placing it at the bottom of the page as someone suggested, commenting out various parts of the code out of sheer desperation. Still nada.
There was no way to make the html() method replace the html correctly in IE10, although I never did find out exactly why. I ended up writing both elements into the table cell, set style="display:none" for one of them and use show() / hide() and that's good enough for me (and apparently for IE10 as well).
For anyone encountering the same issue: this is a workaround, not a solution in the strictest sense.

IE javascript error - possibly related to setAttribute?

I am using Safalra's javascript to create a collapsible list. The script works across several browsers with no problem. However, when I apply the javascript to my own list, it fails to act as expected when I use IE (I'm using 7 at the moment). It simply writes the list, without the expand and contract images.
I copied the Safalra's javascript precisely, so I assume the error must be in my own list. This is how I generated my list:
<body onLoad="makeCollapsible(document.getElementById('libguides'));">
<ul id="libguides">
<script type="text/javascript" src="http://api.libguides.com/api_subjects.php?iid=54&more=false&format=js&guides=true&break=li"></script>
</ul>
(Yes, I do close the body tag eventually.) When I run this in IE, it tells me that line 48 is causing the problem, which appears to be:
node.onclick=createToggleFunction(node,list);
Here's the entire function:
function makeCollapsible(listElement){
// removed list item bullets and the sapce they occupy
listElement.style.listStyle='none';
listElement.style.marginLeft='0';
listElement.style.paddingLeft='0';
// loop over all child elements of the list
var child=listElement.firstChild;
while (child!=null){
// only process li elements (and not text elements)
if (child.nodeType==1){
// build a list of child ol and ul elements and hide them
var list=new Array();
var grandchild=child.firstChild;
while (grandchild!=null){
if (grandchild.tagName=='OL' || grandchild.tagName=='UL'){
grandchild.style.display='none';
list.push(grandchild);
}
grandchild=grandchild.nextSibling;
}
// add toggle buttons
var node=document.createElement('img');
node.setAttribute('src',CLOSED_IMAGE);
node.setAttribute('class','collapsibleClosed');
node.onclick=createToggleFunction(node,list);
child.insertBefore(node,child.firstChild);
}
I confess I'm too much of a javascript novice to understand why that particular line of code is causing the error. I looked at some of the other questions here, and was wondering if it might be a problem with setAttribute?
Thanks in advance.
Edited to add:
Here's the code for the createToggleFunction function. The whole of the script is just these two functions (plus declaring variables for the images).
function createToggleFunction(toggleElement,sublistElements){
return function(){
// toggle status of toggle gadget
if (toggleElement.getAttribute('class')=='collapsibleClosed'){
toggleElement.setAttribute('class','collapsibleOpen');
toggleElement.setAttribute('src',OPEN_IMAGE);
}else{
toggleElement.setAttribute('class','collapsibleClosed');
toggleElement.setAttribute('src',CLOSED_IMAGE);
}
// toggle display of sublists
for (var i=0;i<sublistElements.length;i++){
sublistElements[i].style.display=
(sublistElements[i].style.display=='block')?'none':'block';
}
}
}
Edited to add (again):
Per David's suggestion, I changed all instances of setAttribute & getAttribute...but clearly I did something wrong. IE is breaking at the 1st line (which is simply the doctype declaration) and at line 49, which is the same line of code where it was breaking before:
node.onclick=createToggleFunction(node,list);
Here's the first function as written now:
function makeCollapsible(listElement){
// removed list item bullets and the sapce they occupy
listElement.style.listStyle='none';
listElement.style.marginLeft='0';
listElement.style.paddingLeft='0';
// loop over all child elements of the list
var child=listElement.firstChild;
while (child!=null){
// only process li elements (and not text elements)
if (child.nodeType==1){
// build a list of child ol and ul elements and hide them
var list=new Array();
var grandchild=child.firstChild;
while (grandchild!=null){
if (grandchild.tagName=='OL' || grandchild.tagName=='UL'){
grandchild.style.display='none';
list.push(grandchild);
}
grandchild=grandchild.nextSibling;
}
// add toggle buttons
var node=document.createElement('img');
node.src = CLOSED_IMAGE;
node.className = 'collapsibleClosed';
node.onclick=createToggleFunction(node,list);
child.insertBefore(node,child.firstChild);
}
child=child.nextSibling;
}
}
And here's the second function:
function createToggleFunction(toggleElement,sublistElements){
return function(){
// toggle status of toggle gadget
// Use foo.className = 'bar'; instead of foo.setAttribute('class', 'bar');
if (toggleElement.className == 'collapsibleClosed') {
toggleElement.className = 'collapsibleOpen';
toggleElement.src = OPEN_IMAGE;
} else {
toggleElement.className = 'collapsibleClosed';
toggleElement.src = CLOSED_IMAGE;
}
// toggle display of sublists
for (var i=0;i<sublistElements.length;i++){
sublistElements[i].style.display=
(sublistElements[i].style.display=='block')?'none':'block';
}
}
}
Internet Explorer (until version 8, and then only in best standards mode) has a very broken implementation of setAttribute and getAttribute.
It effectively looks something like this:
function setAttribute(attribute, value) {
this[attribute] = value;
function getAttribute(attribute, value) {
return this[attribute];
}
This works fine iif the attribute name matches the property name, and the property takes a string value.
This isn't the case for the class attribute, where the matching property is className.
Use foo.className = 'bar'; instead of foo.setAttribute('class', 'bar');
node.onclick=createToggleFunction(node,list);
That is probably not what you want. Does createToggleFunction return a function? If it doesn't, then I bet you meant this:
node.onClick = function() { createToggleFunction(node, list); };
If my guess is right then the way you have it will set the onClick event handler to be the result of createToggleFunction, not a function like it needs to be.

Categories

Resources