jqueryUI selectable with AngularJS not working for me - javascript

i'm trying to know why my code isn't working with the selectable, im including the libraries
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script src="http://code.jquery.com/ui/1.10.3/jquery-ui.js"></script>
<link rel="stylesheet" href="http://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css">
This is the code that would have the selectable items in the list
<div class="modal-wrapper">
<ul id="selectable" class="data-list">
<li class="list-item" ng-repeat="data in testData">
<div class="row">
<div class="col-md-4">
<div class="container-title">
<span class="inner-title">{{data.name}}</span>
</div>
</div>
</div>
<div class="row">
<div class="col-md-4">
<div class="container-subtitle">
<span class="subtitle">{{data.title}}</span>
</div>
</div>
</div>
</li>
</ul>
<div class="bottom-buttons">
<button class="btn btn-primary btn-wizard" ng-click="alertSelected()">NEXT</button>
</div>
</div>
Then this is the little piece of code for the selectable:
$(function() {
$("#selectable").selectable({
selected: function(event, ui) {
console.log('im there');
}
});
});
And this is my current css for this test:
body{
background-color: #231f20 !important;
color: #fff;
}
.modal-wrapper {
width: 564px;
height: 650px;
background-color: #eee;
overflow: hidden;
color: #fff;
position: relative;
}
.list-item {
background-color: #555;
width: 250px;
height: 150px;
float: left;
margin: 20px 16px 10px 15px;
}
.container-title {
width: 250px;
height: 150px;
text-align: center;
}
.inner-title {
position: relative;
top: 54px;
font-size: 30px;
}
.container-subtitle {
text-align: center;
width: 250px;
}
.subtitle {
position: relative;
color: #333;
}
.bottom-buttons {
position: absolute;
bottom: 0;
height: 70px;
background-color: #eee;
width: 564px;
}
.btn-wizard {
position: relative;
left: 230px;
top: 17px;
width: 100px !important;
}
#selectable .ui-selecting { background: #FECA40; }
#selectable .ui-selected { background: #F39814; color: white; }
Any ideas on what's going? is it a CSS problem? or the <li> structure?
Thanks in advance,

Edit js/controllers/myWorkController.js
portfolioApp.controller('myWorkController', function($scope) {
$scope.testData = [
{
name : "Test 1",
title : "Home"
},
{
name : "Test 2",
title : "About"
},
{
name : "Test 3",
title : "Contact"
},
{
name : "Test 4",
title : "Join"
},
{
name : "Test 4",
title : "Join"
},
{
name : "Test 4",
title : "Join"
},
{
name : "Test 4",
title : "Join"
},
{
name : "Test 4",
title : "Join"
},
];
$scope.alertSelected = function() {
/* alert it ! */
};
$('#selectable').selectable();
});

According to the Jqueryui documentation regarding selectable you can only implement your code in the meaning of <li> wrapped by <ul> or <ol> syntax as shown here
<ol id="selectable">
<li class="ui-widget-content">Item 1</li>
<li class="ui-widget-content">Item 2</li>
<li class="ui-widget-content">Item 3</li>
<li class="ui-widget-content">Item 4</li>
<li class="ui-widget-content">Item 5</li>
<li class="ui-widget-content">Item 6</li>
<li class="ui-widget-content">Item 7</li>
</ol>
if you want to add any hover event to the <li> elements add this code to your script:
$(function() {
$( "#selectable" ).selectable();
$(".list-item").hover(function() {
alert("hovered!")
}, function() {
alert("unhovered!")
});
});

You must know selectable will select the nested child
$("#selectable").selectable();
will select "li", I find your code have one "li", you must add more li to ul
if you want select div class "row", try that:
$(".list-item").selectable();

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
change to:
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>

Related

Change which image is displayed on hover and click

I'm not a developer. I've been however tasked with coming up with a solution for a small project at work with jQuery and I have no clue where to begin. Here's my codepen: https://codepen.io/axo1/pen/mdBLRjL
What I need to is this (all graphics and texts are placeholders):
What I managed to achieve
Image item1 is supposed to be the first visible,
Hovering on the buttons below the graphic changes which image is displayed,
What I don't know how to achieve
The buttons below should be clickable. Clicking on a button changes the "active" graphic above. For example: if I click on the Second item button, the item2 image will be displayed even after I unhover the button, and so forth.
Any tips of what I should look into?
Unfortunately jQuery is heavily preferred here.
$(document).on({
mouseenter: function() {
$(".item1").toggleClass("active hidden");
$(".item2").toggleClass("hidden");
},
mouseleave: function() {
$(".item1").toggleClass("active hidden");
$(".item2").toggleClass("hidden");
}
}, ".item2btn");
$(document).on({
mouseenter: function() {
$(".item1").toggleClass("active hidden");
$(".item3").toggleClass("hidden");
},
mouseleave: function() {
$(".item1").toggleClass("active hidden");
$(".item3").toggleClass("hidden");
}
}, ".item3btn");
img {
max-width: 15%;
position: absolute;
top: 0;
left: 0;
}
.hidden {
visibility: hidden;
}
.active {
visibility: visible;
}
#container {
display: flex;
justify-content: flex-start;
align-items: center;
color: white;
position: absolute;
top: 250px;
}
#container ul {
padding: 1em;
}
#container ul>li {
background: black;
margin: 1em;
padding: 1em;
list-style-type: none;
display: inline;
}
#container ul>li:hover {
cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<img src="https://www.models-resource.com/resources/big_icons/13/12406.png" class="active items item1">
<img src="https://banner2.cleanpng.com/20180410/rce/kisspng-the-legend-of-zelda-majora-s-mask-hyrule-warriors-the-legend-of-zelda-5acc7b7a4870f6.4303262815233503942967.jpg" class="hidden items item2">
<img src="https://i.pinimg.com/originals/4a/a5/df/4aa5df83115df6c96732a2d76ccb4f1b.jpg" class="hidden items item3">
<div id="container">
<ul>
<li class="item1btn">First item</li>
<li class="item2btn">Second item</li>
<li class="item3btn">Third item</li>
</ul>
</div>
Here is a working version
I kept your style - I think it can be shortened to be more DRY
const $images = $(".items")
let $currentItem = $(".items").eq(0)
$("#container li").on({
"click": function() {
const id = $(this).data("id").replace("btn", "");
$images
.removeClass("active")
.addClass("hidden")
$currentItem = $(`.${id}`)
.removeClass("hidden")
.addClass("active");
},
"mouseover": function() {
const id = $(this).data("id").replace("btn", "");
$images
.removeClass("active")
.addClass("hidden")
$(`.${id}`)
.removeClass("hidden")
.addClass("active");
},
"mouseout": function() {
$images
.removeClass("active")
.addClass("hidden")
$currentItem
.removeClass("hidden")
.addClass("active");
}
})
img {
max-width: 15%;
position: absolute;
top: 0;
left: 0;
}
.hidden {
visibility: hidden;
}
.active {
visibility: visible;
}
#container {
display: flex;
justify-content: flex-start;
align-items: center;
color: white;
position: absolute;
top: 250px;
}
#container ul {
padding: 1em;
}
#container ul>li {
background: black;
margin: 1em;
padding: 1em;
list-style-type: none;
display: inline;
}
#container ul>li:hover {
cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<img src="https://www.models-resource.com/resources/big_icons/13/12406.png" class="active items item1">
<img src="https://banner2.cleanpng.com/20180410/rce/kisspng-the-legend-of-zelda-majora-s-mask-hyrule-warriors-the-legend-of-zelda-5acc7b7a4870f6.4303262815233503942967.jpg" class="hidden items item2">
<img src="https://i.pinimg.com/originals/4a/a5/df/4aa5df83115df6c96732a2d76ccb4f1b.jpg" class="hidden items item3">
<div id="container">
<ul>
<li data-id="item1">First item</li>
<li data-id="item2">Second item</li>
<li data-id="item3">Third item</li>
</ul>
</div>

Iterating over multiple <ul> items to make a jQuery script work without repeating code

I have implemented a jQuery 'magic line' in my multi-level navigation menu and it seems to work with the first sub-navigation, but if I add more it breaks.
My question is: How do I iterate over the other sub-navigation menus to get it to work across however many sub-level items I may add? ( <ul class="sy__list__secondary"> )
Please take a look at my code below. To reproduce my problem follow these steps:
Hover over the first child in the main navigation (HOME)
Then hover over the children of the 'HOME' item - the magic line will work perfectly.
Now hover over the second child in the main navigation (ABOUT)
Then hover over the children of the 'ABOUT' list - the magic line will not work.
My question is: How do I iterate over the other sub-navigation menus to get it to work across however many sub-level items I may add?
var $el, leftPos, newWidth;
$('.sy__list__secondary').each(function() {
$(this).append("<li id='magic-line'></li>");
});
/* Cache it */
var $magicLine = $("#magic-line");
function magicLinePref() {
$magicLine
.width($(".sy__list__secondary.active li:first-child").width())
.css("left", $(".sy__list__secondary.active li:first-child").position().left)
.data("origLeft", $magicLine.position().left)
.data("origWidth", $magicLine.width());
$(".sy__list__secondary li").find("a").hover(function() {
$el = $(this);
leftPos = $el.position().left;
newWidth = $el.parent().width();
$magicLine.stop().animate({
left: leftPos,
width: newWidth
});
}, function() {
$magicLine.stop().animate({
left: $magicLine.data("origLeft"),
width: $magicLine.data("origWidth")
});
});
}
$('.sy__list__primary > li').hover(function() {
magicLinePref();
});
.sy__navigation {
position: relative;
}
.sy__navigation__primary {
background: #333333;
}
.sy__navigation__secondary {
position: absolute;
background: #031f37eb;
left: 0;
top: 50px;
z-index: 10;
width: 100%;
display: none;
}
#magic-line {
position: absolute;
bottom: 0;
padding: 0 !important;
left: 0;
width: 100px;
height: 2px;
background: #31B2E7;
}
.sy__list__primary>li:hover .sy__navigation__secondary {
display: block;
}
ul.sy__list__secondary {
justify-content: space-around;
margin: auto;
padding: 0;
color: #ffffff;
}
ul.sy__list__primary {
margin: auto;
padding: 0;
box-sizing: border-box;
}
ul.sy__list__primary span,
a {
color: #ffffff;
}
ul.sy__list__primary li {
display: inline-block;
letter-spacing: 1px;
font-size: 10px;
box-sizing: border-box;
}
ul.sy__list__primary>li {
padding: 20px;
}
ul.sy__list__secondary li a {
padding: 15px;
display: inline-block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.5.2/animate.min.css">
<div class="sy__navigation">
<div class="sy__navigation__primary">
<div class="container">
<div class="row">
<ul class="sy__list__primary">
<li><span>HOME</span>
<div class="sy__navigation__secondary">
<ul class="sy__list__secondary active">
<li>SUB 1A</li>
<li>SUB 1A</li>
<li>SUB 1A</li>
</ul>
</div>
</li>
<li><span>ABOUT</span>
<div class="sy__navigation__secondary">
<ul class="sy__list__secondary">
<li>SUB 2A</li>
<li>SUB 2A</li>
<li>SUB 2A</li>
</ul>
</div>
</li>
</ul>
</div>
</div>
</div>
</div>
Updated magicLinePref() function and passed respective li object. Fetched .sy__list__secondary and .#magic-line using li.find.
Removed global declaration of var $magicLine = $("#magic-line");. As when jQuery select any object with id selector # it will only return first object found with given id.
Instead of that I have select element which are inside current li element which is passing from magicLinePref($(this));.
li.find("#magic-line"); find element with id magic-line inside current li. Similarly for class selector .sy__list__secondary.
var $el, leftPos, newWidth;
$('.sy__list__secondary').each(function() {
$(this).append("<li id='magic-line'></li>");
});
/* Cache it */
function magicLinePref(li) {
var $magicLine = li.find("#magic-line");
$magicLine
.width(li.find(".sy__list__secondary li:first-child").width())
.css("left", li.find(".sy__list__secondary li:first-child").position().left)
.data("origLeft", $magicLine.position().left)
.data("origWidth", $magicLine.width());
li.find(".sy__list__secondary li").find("a").hover(function() {
$el = $(this);
leftPos = $el.position().left;
newWidth = $el.parent().width();
$magicLine.stop().animate({
left: leftPos,
width: newWidth
});
}, function() {
$magicLine.stop().animate({
left: $magicLine.data("origLeft"),
width: $magicLine.data("origWidth")
});
});
}
$('.sy__list__primary > li').hover(function() {
magicLinePref($(this));
});
.sy__navigation {
position: relative;
}
.sy__navigation__primary {
background: #333333;
}
.sy__navigation__secondary {
position: absolute;
background: #031f37eb;
left: 0;
top: 50px;
z-index: 10;
width: 100%;
display: none;
}
#magic-line {
position: absolute;
bottom: 0;
padding: 0 !important;
left: 0;
width: 100px;
height: 2px;
background: #31B2E7;
}
.sy__list__primary>li:hover .sy__navigation__secondary {
display: block;
}
ul.sy__list__secondary {
justify-content: space-around;
margin: auto;
padding: 0;
color: #ffffff;
}
ul.sy__list__primary {
margin: auto;
padding: 0;
box-sizing: border-box;
}
ul.sy__list__primary span,
a {
color: #ffffff;
}
ul.sy__list__primary li {
display: inline-block;
letter-spacing: 1px;
font-size: 10px;
box-sizing: border-box;
}
ul.sy__list__primary>li {
padding: 20px;
}
ul.sy__list__secondary li a {
padding: 15px;
display: inline-block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.5.2/animate.min.css">
<div class="sy__navigation">
<div class="sy__navigation__primary">
<div class="container">
<div class="row">
<ul class="sy__list__primary">
<li><span>HOME</span>
<div class="sy__navigation__secondary">
<ul class="sy__list__secondary">
<li>SUB 1A</li>
<li>SUB 1A</li>
<li>SUB 1A</li>
</ul>
</div>
</li>
<li><span>ABOUT</span>
<div class="sy__navigation__secondary">
<ul class="sy__list__secondary">
<li>SUB 2A</li>
<li>SUB 2A</li>
<li>SUB 2A</li>
</ul>
</div>
</li>
</ul>
</div>
</div>
</div>
</div>

Read value from html menu?

How can I read the selected value of this menu, as if it were a dropdown list?
For a regular dropdown list like below, I use something like this to read the value:
<select id="ddl">
<option value="In" selected="selected">In</option>
<option value="Out">Out</option>
<option value="Ratio">Ratio</option>
</select>
With javascript I read the selected value:
var dropdown = document.getElementById("ddl");
var InOrOut = dropdown.options[dropdown.selectedIndex].value;
Is it possible to use something like this to read the selected value of the menu below:
function FillAll()
{
alert('I will read value');
// This is where menu value is read.
alert('Value read is');
}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<style type="text/css">
#wrapper {
width: 100%;
border: 1px solid black;
overflow: hidden; /* will contain if #first is longer than #second */
}
#first {
width: 400px;
float:left; /* add this */
border: 1px solid red;
}
#second {
border: 1px solid green;
text-align: right;
overflow: hidden; /* if you don't want #second to wrap below #first */
}
.bs-example{
margin: 20px;
}
.text
{
font-size: 15pt;
font-family: Helvetica;
color: #3d718b;
}
hr{
margin: 60px 0;
}
</style>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<div style="float:left;">
<ul class="nav nav-pills">
<li class="text" class="dropdown">
</b>
<ul class="dropdown-menu">
<li>Value1</li>
<li>Value2</li>
<li>Value3</li>
</ul>
</li>
</li>
</ul>
</div>
<button id="ButtonSearch" onclick="FillAll()">GO</button>
Since one can't do much to change the design of the regular dropdown list, I was thinking of using another approach, and use an html menu instead of the ddl.
Something I didn't mention is that the code to read the value would go inside the click event of a button that already exists. I didn't mention it before because I didn't know the click event would be used to read the value.
You can use getAttribute to scrape a value off of each li:
$('.dropdown-menu li').click( e => {
console.log(e.target.getAttribute('value'));
});
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<style type="text/css">
#wrapper {
width: 100%;
border: 1px solid black;
overflow: hidden; /* will contain if #first is longer than #second */
}
#first {
width: 400px;
float:left; /* add this */
border: 1px solid red;
}
#second {
border: 1px solid green;
text-align: right;
overflow: hidden; /* if you don't want #second to wrap below #first */
}
.bs-example{
margin: 20px;
}
.text
{
font-size: 15pt;
font-family: Helvetica;
color: #3d718b;
}
hr{
margin: 60px 0;
}
</style>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<div style="float:left;">
<ul class="nav nav-pills">
<li class="text" class="dropdown">
</b>
<ul class="dropdown-menu">
<li value="1">Value1</li>
<li value="2">Value2</li>
<li value="3">Value3</li>
</ul>
</li>
</li>
</ul>
</div>
This looks to do what you need using either jQuery or native JS.
<script>
// with jquery
$('.dropdown-menu li').click(function(el) {
console.log(el.target.textContent)
})
// native
const list = document.querySelectorAll('.dropdown-menu li');
list.forEach(el => el.addEventListener('click', function listClick() {
console.log(el.textContent);
}));
</script>
The short answer is, yes. The following code, following your example, uses an event handler which is triggered when one of the menu items are clicked. I've also included a working jsfiddle example below.
HTML
<ul class="nav nav-pills">
<li class="text" class="dropdown">
</b>
<ul class="dropdown-menu">
<li>Value 1</li>
<li>Value 2</li>
<li>Value 3</li>
</ul>
</li>
</ul>
<div class="col-xs-12 text-danger" id="result"></div>
Javascript / jQuery
$(document).on('click', '.dropdown-menu li a', function() {
var r = $('#result');
r.empty().append('You have clicked <strong>'+$(this).text()+'</strong> in the drop-down menu.');
});
https://jsfiddle.net/Xonos/z9jfa86r/
UPDATE: I have added another answer which shows a secondary example where you can select/de-select a menu item and then click a button to determine which of the menu items are selected. The JSFiddle link is below.
HTML
<div class="col-xs-12">
<ul class="nav nav-pills">
<li class="text" class="dropdown">
</b>
<ul id="myDropdown" class="dropdown-menu">
<li>Value 1</li>
<li>Value 2</li>
<li>Value 3</li>
</ul>
</li>
</ul>
</div>
<div class="col-xs-12 text-red" id="result"> </div>
<br>
<div class="col-xs-12">
<button id="checkBtn" class="btn btn-sm btn-success pull-right">Check Selected Menu Item</button>
</div>
<div class="col-xs-12 text-orange" id="check"> </div>
CSS
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
button {
background: #0084ff;
border: none;
border-radius: 5px;
padding: 8px 14px;
font-size: 15px;
color: #fff;
}
.text-red {
color:rgb(206, 35, 35);
}
.text-orange {
color:rgb(252, 144, 0);
}
.nav {
background-color:rgba(255,255,255,0.15);
}
.selected-item {
background-color:rgb(255,0,0);
}
Javascript / jQuery
$(document).on('click', '#myDropdown li a', function() {
var r = $('#result');
$(this).parent().parent().children().removeClass('selected-item');
if($(this).hasClass('selected-item')) {
$(this).removeClass('selected-item'); //De-select menu item.
} else {
$(this).parent().addClass('selected-item'); //Select menu item.
}
r.empty().append('You have selected <strong>'+$(this).text()+'</strong> in the drop-down menu.');
});
$(document).on('click', '#checkBtn', function() {
var selected = $('#myDropdown .selected-item');
if(selected.length > 0) { //If any of the menu items <li> have the "selected-item" class added.
$('#check').empty().append('Found a selected menu item. The value of it is: <strong>'+selected.text()+'</strong>');
} else {
$('#check').empty().append('You have not selected an item from the menu.');
}
});
https://jsfiddle.net/Xonos/74pwyL1m/

jQuery find an element

I have a div as so:
<div class="country">
<div class="cty_popover">
<p>TITLE</p>
<ul>
<li>NAME 1</li>
<li>NAME 2</li>
</ul>
</div>
<img src="resources/images/map-marker.png" alt=" ">
</div>
And this jQuery:
$(document).ready(function(){
$('.country img').hover(function() {
$(this).parents('.cty_popover').fadeIn(800);
},
function() {
$('.cty_popover').fadeOut(300);
});
});
I know this line is wrong in the jQuery:
$(this).find('.cty_popover').fadeIn(800);
I need to target:
.cty_popover
from within the function:
$('.country img').hover
So basically my question is:
How do I target .cty_popover using $(this)? I need to move up from the 'img' to target it, but not sure how?
I have a lot of these .cty_popover divs and that's why I want to use $(this) so I don't target them all.
Anyone any ideas why I can't get this working?
Thanks
As the img is a sibling of the cty_popover, you can target it using the prev() function - see a demo below:
$(document).ready(function() {
// hide all `cty_popover` sections initially
$('.cty_popover').hide();
// hover listener
$('.country img').hover(function() {
$(this).prev('.cty_popover').fadeIn(800);
}, function() {
$(this).prev('.cty_popover').fadeOut(300);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="country">
<div class="cty_popover">
<p>TITLE</p>
<ul>
<li>NAME 1</li>
<li>NAME 2</li>
</ul>
</div>
<img src="http://placehold.it/200x200">
</div>
Since the img node is a sibling of the cty_popover node, replacing this line
$(this).parents('.cty_popover').fadeIn(800);
with this should work
$(this).siblings('.cty_popover').fadeIn(800);
Here's an example
You should use siblings: https://api.jquery.com/siblings/
See this example working on your HTML:
$(document).ready(function(){
$('.country').children('img').hover(function() {
$(this).siblings( '.cty_popover').fadeIn(800);
},
function() {
$('.cty_popover').fadeOut(300);
});
});
.country {
position. relative;
width: 300px;
}
.country > img {
width: 100%;
display: block;
}
.country .cty_popover {
display: none;
position: absolute;
left: 10px;
top: 10px;
background: rgba(255,255,0,.9);
padding: 5px;
border-radius: 5px;
width: 285px;
}
.country .cty_popover:after {
content: "";
width: 0;
height: 0;
border-left: 20px solid transparent;
border-right: 20px solid transparent;
border-top: 20px solid rgba(255,255,0,.9);
position: absolute;
bottom: -20px;
left: 50%;
margin-left: -10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="country">
<div class="cty_popover">
<p>TITLE</p>
<ul>
<li>NAME 1</li>
<li>NAME 2</li>
</ul>
</div>
<img src="https://placeimg.com/300/200/tech" alt=" ">
</div>

how to implement css horizontal menu with variable width submenus

I have a menu I would like to implement. It can sometimes drill down 3 or 4 layers so I'm trying to optimize space taken up by each menu. I'd like to have each ul set to width: auto, the only problem is I can't set the right/left property reliably for where the next submenu should appear. Here's some code:
HTML
<ul class="top-level-menu horizontal-multimenu">
<li>L360 Home</li>
<li>
Liquidity Risk Monitor
<ul class="second-level-menu">
<li>Indicators</li>
<li>Stress Levels</li>
</ul>
</li>
<li>
Sources and Assumptions
<ul class="second-level-menu">
<li>Source of Funds</li>
<li>Funding Assumptions</li>
</ul>
</li>
<li>
Data
<ul class="second-level-menu">
<li>Transfer</li>
<li>Table</li>
</ul>
</li>
<li>
Reports
<ul class="second-level-menu">
<li>
Risk Monitor
<ul class="subsecond-level-menu">
<li>Scorecard</li>
<li>DCG ALCO Data</li>
<li>Historical</li>
<li>
Prior Values
<ul class="subsecond-level-menu">
<li>Conditional Item</li>
<li>Conditional Item</li>
<li>Conditional Item</li>
<li>Conditional Item</li>
<li>Conditional Item</li>
<li>Conditional Item</li>
</ul>
</li>
</ul>
</li>
<li>
Stress Reports
<ul class="subsecond-level-menu">
<li>Footnotes</li>
<li>
Liquidity Availability Analysis
<ul class="subsecond-level-menu">
<li>Base Case</li>
<li>Level 1</li>
<li>Level 2</li>
<li>Level 3</li>
</ul>
</li>
<li>Exexcutive Summary</li>
<li>Liquidity Forecast</li>
</ul>
</li>
<li>
Worksheets
<ul class="subsecond-level-menu">
</ul>
</li>
<li>Package Creator</li>
<li>
Memoranda
<ul class="subsecond-level-menu">
</ul>
</li>
</ul>
</li>
<li>Support</li>
</ul>
CSS
/* Menu Styles */
.subsecond-level-menu
{
position: absolute;
top: 0;
right: 999px;
width: 300px;
list-style: none;
padding: 0;
margin: 0;
opacity: 0;
transition: opacity .3s;
}
.subsecond-level-menu>li
{
height: 30px;
background: #999999;
padding: 0 1em;
}
.subsecond-level-menu>li:hover { background: #CCCCCC; }
.second-level-menu
{
position: absolute;
top: 30px;
left: 0;
width: 150px;
list-style: none;
padding: 0;
margin: 0;
display: none;
}
.second-level-menu>li
{
position: relative;
height: 30px;
background: #999999;
padding: 0 1em;
}
.second-level-menu>li:hover { background: #CCCCCC; }
.top-level-menu
{
list-style: none;
padding: 0;
margin: 0;
}
.top-level-menu>li
{
position: relative;
float: left;
height: 30px;
width: /*150px*/auto;
background: #999999;
padding: 0 1em;
}
.top-level-menu>li:hover { background: #CCCCCC; }
.top-level-menu li:hover>ul
{
/*On hover, display the next level's menu */
display: block;
right: -300px;
opacity: 1;
}
/* Menu Link Styles */
.top-level-menu a /* Apply to all links inside the multi-level menu */
{
font: bold 14px Arial, Helvetica, sans-serif;
color: #FFFFFF;
text-decoration: none;
/*padding: 0 0 0 10px;*/
margin: 0 auto;
/* Make the link cover the entire list item-container */
display: inline;
line-height: 30px;
}
.top-level-menu a:hover { color: #000000; }
.top-level-menu li{whitespace: no-wrap;}
This should work, but all the .subsecond-level-menu's are required to be x px wide so I know where to put them.
Do you think it would be better to assign id's to each submenu and then just assign static widths/right's to each or try to make it happen with some javascript?
I've been wrestling with the js attempt for a while, but it doesn't quite seem to the submenu widths. Here's that code that I've been working on if you're curious:
JS
$(document).ready(function(){
$('.top-level-menu').find('li').hover(
function(e){
$(e.target).css('background-color', 'red');
var item = $(this);
console.log('The child list is considered hidden: ' + $(e.target).children('ul').is(':hidden') + ', Child width: '+$(e.target).children('ul').outerWidth() + 'px');
$(e.target).children('ul').css({
'right': (-1 * $(e.target).children('ul').outerWidth()) + 'px',
'opacity': '1',
'display': 'block'
});
},
function(e){
$(e.target).css('background-color', '');
var item = $(this),
emptyCss = {
'right' : '',
'opacity' : '',
'display': ''};
item.children('ul').css(emptyCss);
}
);
});

Categories

Resources