I have built a drop-down menu here http://dev.driz.co.uk/jsonmenu/ that uses JSON to dynamically build the menus. The reason for doing this insead of putting the HTML in the page itself is for performance (only load what you need) and so that I can position the menu outside of the table.
I have begun implementing a way to position the menu based on its height and proximity to the window (browser window NOT the scrollable container). The problem is that when the height of the menu is bigger than the space below the link and viewport then it should move the menu above and vice-versa. Parts of it are working just not quite correctly.
NOTE: The reason the positioning is done after the HTML is inserted rather than in a callback if user moves the window etc is because the menu is removed if the user scrolls or anything like that so it would be pointless to do it then.
Code as requested:
$(document).ready(function () {
$('a.buildMenu').click(function (event) {
// Prevent normal behaviour
event.preventDefault();
// Stops it bubbling to the document
event.stopPropagation();
var link = $(this);
// If the menu already exists remove it and exit the request
if($(document).find('div#' + $(link).data('id')).length){
$('.buildMenu').removeClass('selected');
$('.menu').remove();
return false;
}
// Remove any other menus from the DOM
$('.buildMenu').removeClass('selected');
$('.menu').remove();
// Get the position of the link
var offset = link.offset();
var top = offset.top;
var left = offset.left;
var bottom = top + link.height();
var right = $(window).width() - link.width();
top = top + link.height();
bottom = bottom + link.height();
// Append the menu to the DOM in position
var menuInstance = $('<div class="menu loading">loading...</div>').appendTo('body').css({'position':'absolute','top':top,'left':left});
// Add the instance id
$(menuInstance).attr('id', $(link).data('id'));
// Add class of selected to clicked link
$(this).addClass('selected');
// Request JSON data
$.ajax({
url: 'menu.json',
timeout: 5000,
dataType: 'JSON',
success: function (data) {
// Build the menu
var ul = $("<ul/>").attr("id", data.menu.id).addClass(data.menu.class);
// For each menu item
$.each(data.menu.content.menuitem, function () {
var li = $("<li/>").appendTo(ul).addClass(this.liClass);
var anchor = $("<a/>").appendTo(li).attr("href", this.href).attr("title", this.title);
var span = $("<span/>").appendTo(anchor).addClass(this.icon).html(this.text)
});
// Remove the loading class and insert menu into instance
$(menuInstance).removeClass('loading').html(ul);
// If the menu is taller than the bottom space
if(menuInstance.height() > bottom) {
menuInstance.css({'top':'auto','bottom':bottom,'left':left});
}
// If the menu is taller than the top space
else if(menuInstance.height() > top) {
menuInstance.css({'top':top,'left':left});
}
// Default position...
else {
menuInstance.css({'top':top,'left':left});
}
},
error: function (jqXHR, textStatus, errorThrown) {
console.log(jqXHR, textStatus, errorThrown);
}
});
});
// Remove menu from DOM if anything except the menu is clicked
$(document).bind('click', function (event) {
var clicked = $(event.target);
if (!clicked.parents().hasClass('menu')) {
$('.buildMenu').removeClass('selected');
$('.menu').remove();
}
});
// Remove menu if user scrolls panel
$(window).bind('resize', function() {
$('.buildMenu').removeClass('selected');
$('.menu').remove();
});
$('div').bind('scroll', function() {
$('.buildMenu').removeClass('selected');
$('.menu').remove();
});
});
Here is a screenshot of the issue (the code should make that menu appear above the link because its height is bigger than the offset space below the link)

Looks like the problem is with Line 71-74.
bottomis being calculated as the distance from the top of the window to bottom of the menu link … and you’re saying “if the menu height is bigger than that”.I think what you’re wanting to check is the if the menu height is bigger than the distance from the bottom of the menu link to the bottom of the window. So…
This should take the distance from the bottom of the link to the bottom of the window and compare that to the height of the menu.
Then you need to correct how you’re position
menuInstance.Here’s the full code…