Animating the active item background in a nav fails - javascript

I have the following markup:
<ul>
<li>first</li>
<li>largerWord</li>
<li class="active">third</li>
</ul>
The items have transparent background except the active class, that has a blue color.
The idea is that when user clicks (not the active) instead of switching the backgrounds i want to move the background, you can see the result almost done here, but it fails the first click (see end of question for error log):
http://jsfiddle.net/FeV55/26/
What i do is to dynamically create a lower z-index <li> and animate the left according the (clicked) item offset and the width according the (clicked) item width
The jquery code:
$(document).ready(function(){
$('ul li a').not('.active').click(function(){
/*caching*/
var activa = $('li.active');
var bg = $('li.back');;
var list = $(this).closest('ul');
/*when it's first click the background item doesnt exist*/
if(bg.length>0 == false){
list.append('<li class="back"></li>');
}
var width = $(this).outerWidth(true);
var leftUL = list.offset().left;
var leftThis = $(this).offset().left;
var left = leftThis - leftUL;
/*Remove class to previous active*/
activa.removeClass('active');
/*Cancel background even if parent is active*/
$(this).addClass('noBg');
/*Update active class*/
$(this).parent().addClass('active');
/*Move the background to its offset*/
bg.animate({'left':left,'width':width});
/*logs*/
$('#oUl').text(leftUL);
$('#ocl').text($(this).offset().left);
$('#odf').text(left);
$('#obg').text(bg.offset().left);
});
});
But it fails on first click, firebug logs:
bg.offset() is null
[Parar en este error]
$('#obg').text(bg.offset().left);
Question is why? the item should exist by then in any case..

Be sure to select the element you've assigned to bg after you create it:
var bg = $('li.back');
if (bg.length == 0) {
list.append('<li class="back"></li>');
bg = $('li.back');
}
Even better, create the element into bg:
if (bg.length == 0) {
bg = $('<li class="back"></li>');
list.append(bg);
}

Related

Make first menu item red on load with scrollspy an jQuery

Can someone help me with my code? This code below makes my menu items red on scroll within the div where a "scrollspy" is added. But there is something missing so my first menu item (Home) does not get red when page is loaded, only when I scroll a bit below. I need to have this 1st item red on load. How can I fix this?
An example code to make first menu item active on load?
window.onload = function() {
//code?
};
This makes menu item red when added "scrollspy" class on a row in admin
var elems = $('.scrollspy');
$(window).bind('scroll', function() {
var currentActive = null;
var currentActiveDistance = -1;
var currentTop = $(window).scrollTop();
elems.each(function(index) {
var elemTop = $(this).offset().top - 102
var id = $(this).attr('id');
var navElem = $('.menu a[href="#' + id + '"]');
navElem.removeClass('active');
if (currentTop >= elemTop) {
var distance = currentTop - elemTop;
if (currentActiveDistance > distance || currentActiveDistance == -1) {
currentActive = navElem;
}
}
});
if (currentActive) {
currentActive.addClass('active');
}
});
Why not use just CSS?
.nav li a.active {
background-color: red;
}
jQuery can be used as below to make first menu item link RED i.e by applying class active.
$(document).ready(function(){
$(".menu:first a").addClass('active');
});
Please post your HTML markup if it does not work with your HTML.

Updating underline-slider position on resize

I have an underline slider for my navigation links that get the specific width and position based on the clicked element, <li>, using the getBoundingClientRect(). This works as expected, but on resizing the browser window I would like to update the underline-slider's position.
As it is right now I'm only grabbing the width and position of the first <li>. What I need and want to do is to target the specific <li> that currently has the underline-slider and update its width and position on resizing so the slider follows along during resize with the right <li> element.
Any tip how I could grab the currently active <li>??
This is the codepen where I have the example in where I only grab the first <li> everytime on resize:
https://codepen.io/Shenden/pen/PELbOM
the script looks like this:
const lists = document.querySelectorAll('.dropdown > li');
const slider = document.querySelector('.slider');
function handleEnter() {
// from current li
const dropCoords = this.getBoundingClientRect();
//get the current li's width and height
//apply coords of li's to the slider-div elem
slider.style.setProperty('opacity', '1');
slider.style.setProperty('width', `${dropCoords.width}px`);
slider.style.setProperty('transform', `translate(${dropCoords.left}px)`);
}
//for each li-elem clicked trigger handleEvent function
lists.forEach(listLink => listLink.addEventListener('click', handleEnter));
window.addEventListener('resize', function(){
const elem = document.querySelector('.dropdown > li').getBoundingClientRect();
slider.style.setProperty('transform', `translate(${elem.left}px)`);
slider.style.setProperty('width', `${elem.width}px`);
});
You could keep track of which item should be active by flagging it with a class like this :
const lists = document.querySelectorAll('.dropdown > li');
const slider = document.querySelector('.slider');
function handleEnter() {
//remove active item indicator class if it is present
document.querySelector(".activeItem").classList.remove("activeItem");
//add the active item indicator class to the current item
this.classList.add("activeItem");
//perform the move code for the underline
const dropCoords = this.getBoundingClientRect();
//get the current li's width and height
//apply coords of li's to the slider-div elem
slider.style.setProperty('opacity', '1');
slider.style.setProperty('width', `${dropCoords.width}px`);
slider.style.setProperty('transform', `translate(${dropCoords.left}px)`);
}
//for each li-elem clicked trigger handleEvent function
lists.forEach(listLink => listLink.addEventListener('click', handleEnter));
window.addEventListener('resize', function(){
//select the correct item using the activeItem indicator class
const elem = document.querySelector('.dropdown > li.activeItem').getBoundingClientRect();
slider.style.setProperty('transform', `translate(${elem.left}px)`);
slider.style.setProperty('width', `${elem.width}px`);
});
CodePen fork : right here

JQuery mobile changing color to clicked list view

I have a list view where its data is being loaded from JSON string. Refer to the below code. It will show the item name and quantity.
function loadItemsForList2(){
//load items in page for list 2
//empty existing items from shoppinglist2
$("#shoppingList2").empty();
//regenerate listTwoItems
var lstTwo = localStorage.getItem("listTwo");
if (lstTwo!=null) listTwoItems = JSON.parse(lstTwo);
for (var key in listTwoItems) {
item2 = key; //+ ":" + listTwoItems[key];
item2Qty = listTwoItems[key];
$('#shoppingList2').append('<li class="list"><a class="itemList2"><div><span class="itemInList">' + item2 + '</span><span class="itemInListQty">'+ item2Qty+'</span></div></a><a class="removalLst2"></a></li>');
}
//goto to the page
$.mobile.changePage("#finalShoppingList2");
$("#shoppingList2").listview('refresh');
}
I wish that when the user clicks on an item in a list (li> ), it changes the background color. And when it is re-clicked again, it will go to the original color. Below is the function being called when list item is clicked. Note that only the outside line background is being changed to yellow. I need to change whole background to yellow.
What I'm doing wrong. Kindly refer to the image List view showing yellow line background
Please how can I solve this problem
$("#shoppingList2").delegate(".itemList2", "click", function() {
selectedItem = $(this).text();
//alert(selectedItem);
selectedItem = selectedItem.replace(/\d+/g, '');
alert(selectedItem);
$(this).parent().css("background-color", "yellow");
});
You can change the backcolor of the 2 anchor tags in the list item:
$("#shoppingList2").on("click", ".itemList2", function() {
selectedItem = $(this).text();
selectedItem = selectedItem.replace(/\d+/g, '');
$(this).css("background-color", "yellow");
$(this).next("a").css("background-color", "yellow");
});
DEMO
You are changing the background color of parent of .itemList2 which is li. But that li contains anchor tag and a div tag inside it. So Change the background color of that div tag.

Function when Elements className change

I am trying to change the background image of a section based on whatever slide has a particular classname.
I have an unordered list that is genereated with a loop
<ul class="tes-image-links">
<li>http://exampleimg1.jpg</li>
<li>http://exampleimg2.jpg</li>
<li>http://exampleimg3.jpg</li>
</ul>
I also have some javascript to change the background image of the section the unorderd list is contained in. The url for the background image depends on which div has the class name cycle-slide-active
var cycleSlide = $('.cycle-slideshow').find('.cycle-slide');
for (i = 0; i < cycleSlide.length; i++) {
if (cycleSlide.eq(i).hasClass('cycle-slide-active')){
var apimglink = $('.tes-image-links').children('li').eq(i).text();
apimglink = apimglink.replace("http://localhost", "");
$('.ap-testimonial').css('background-image', 'url(' + apimglink + ')');
console.log(apimglink);
} //End If
}; //End For
The above code gives me the right background image for whatever slide is first loaded, but after the slide changes nothing else happens.
I need help Executing the above code whenever cycleSlide.className for any cycleSlide element is changed.
Thank you all in advanced.

Z-index doesn't seem to change anything

I am building some custom dropdown controls and the z-index isn't working properly.
// Add the empty class to the container div if no check boxes are checked.
$('.qx-container').each(function ()
{
var container = $(this);
if (!container.find('input[type="checkbox"]').is(':checked'))
{
container.find('.qx-content').text($('.qx-content').attr('empty-message'));
container.find('.qx-content').addClass('qx-empty-content');
}
else
{
handleCheckBoxToggle(container.find('input[type="checkbox"]'));
}
});
// Wire a mouse enter event to the container div. Turns the drop-down list's colors to gray if the slider isn't visible.
$('.qx-container').mouseenter(function ()
{
var container = $(this);
if (!container.find('.qx-slider').is(':visible'))
{
container.find('.qx-container-border-outer').addClass('qx-container-border-outer-hover');
container.find('.qx-container-border-inner').addClass('qx-container-border-inner-hover');
container.find('.qx-container-border-background').addClass('qx-container-border-background-hover');
}
container.data('hoverState', true);
});
// Wire a mouse leave event to the container div. Turns the drop-down list's colors to white if the slider isn't visible and
// sets the container div's empty class if no check boxes are checked.
$('.qx-container').mouseleave(function ()
{
var container = $(this);
if (!container.find('.qx-slider').is(':visible'))
{
container.find('.qx-container-border-outer').removeClass('qx-container-border-outer-hover');
container.find('.qx-container-border-inner').removeClass('qx-container-border-inner-hover');
container.find('.qx-container-border-background').removeClass('qx-container-border-background-hover');
}
if (container.text() == '')
{
container.text($(this).attr('empty-message'));
container.addClass('qx-empty-content');
}
container.data('hoverState', false);
});
// Wire a click event to the content div. Shows or hides the slider and changes the drop-down list's colors based on the slider's visibility.
$('.qx-container-border-outer').click(function ()
{
var outer = $(this);
var inner = $(this).find('.qx-container-border-inner');
var background = $(this).find('.qx-container-border-background');
var container = outer.closest('.qx-container');
var slider = container.find('.qx-slider');
var sliders = $('.qx-container').find('.qx-slider').not(slider);
// Close any other open sliders.
sliders.each(function ()
{
$(this).hide();
var containerDiv = $(this).closest('.qx-container');
var outerBorder = containerDiv.find('.qx-container-border-outer');
var innerBorder = containerDiv.find('.qx-container-border-inner');
var backgroundDiv = containerDiv.find('.qx-container-border-background');
outerBorder.removeClass('qx-container-border-outer-selected');
outerBorder.removeClass('qx-container-border-outer-hover');
innerBorder.removeClass('qx-container-border-inner-selected');
inner.removeClass('qx-container-border-inner-hover');
backgroundDiv.removeClass('qx-container-border-background-selected');
background.removeClass('qx-container-border-background-hover');
});
// Toggle the slider.
slider.slideToggle(50, function ()
{
if (!container.data('hoverState'))
{
outer.removeClass('qx-container-border-outer-hover');
inner.removeClass('qx-container-border-inner-hover');
background.removeClass('qx-container-border-background-hover');
}
if (slider.is(':visible'))
{
outer.addClass('qx-container-border-outer-selected');
inner.addClass('qx-container-border-inner-selected');
background.addClass('qx-container-border-background-selected');
}
else
{
outer.removeClass('qx-container-border-outer-selected');
inner.removeClass('qx-container-border-inner-selected');
background.removeClass('qx-container-border-background-selected');
}
});
});
// Wire a change event to the check boxes. Stores the user's selection in the content element & displays the text of which check box is checked.
$('.qx-slider').find($('input[type="checkbox"]')).click(function (event)
{
event.stopPropagation();
handleCheckBoxToggle($(this));
});
// Wire a mouse enter event to the slider row so the background color changes to gray.
$('.qx-slider-row').mouseenter(function ()
{
$(this).find('td').addClass('qx-slider-cell-hover');
});
// Wire a mouse leave event to the slider row so the background color changes to white.
$('.qx-slider-row').mouseleave(function ()
{
$(this).find('td').removeClass('qx-slider-cell-hover');
});
// Wire a mouse click event to the slider row to toggle the check box's checked attribute.
$('.qx-slider-row').click(function ()
{
var checkBox = $(this).find('input[type="checkbox"]');
checkBox.attr('checked', !checkBox.is(':checked'));
handleCheckBoxToggle(checkBox);
});
// Handles the checked event for each check box.
function handleCheckBoxToggle(checkBox)
{
// Reference to the containing content div.
var content = checkBox.closest('.qx-container').find('.qx-content')
// Holds the checked values (data is associated with the content div).
var checkBoxData = content.data('checkBoxData');
// Reference to all the check boxes in the slider.
var checkBoxes = checkBox.closest('table').find('input[type="checkbox"]');
// Create an array of check box values (associated with the content div) if it doesn't exist.
if (checkBoxData == undefined)
{
checkBoxData = new Array();
checkBoxes.each(function ()
{
checkBoxData[$(this).attr('interest-level-description')] = 0;
});
}
// Store the checked values of each check box.
checkBoxes.each(function ()
{
checkBoxData[$(this).attr('interest-level-description')] = $(this).is(':checked') ? 1 : 0;
});
// Create a commo-delimited string from the checked values.
content.data('checkBoxData', checkBoxData);
var output = '';
for (var property in checkBoxData)
{
if (checkBoxData[property] == 1)
{
output += property + ", ";
}
}
// Remove the trailing comma.
if (output.match(",") != null)
{
output = output.substr(0, output.length - 2);
}
// Set the content text and class based on the checked values.
if (output == '')
{
content.text(content.attr('empty-message'));
content.addClass('qx-empty-content');
}
else
{
content.text(output);
content.removeClass('qx-empty-content');
}
}
http://jsfiddle.net/heray/1/
If you click the items you'll notice the dropdown menu appears behind subsequent dropdowns. I've added z-indexes and position relative to every element I can think of.
Just so you understand how to use z-index, never assign a z-index to something unless you want it to be displayed over top of another element. The best practice is not to define a z-index (especially not assigning a value of 0) until you need to. In your example, the class you have after clicking the button (the actual dropdown) should have a z-index of 1 or greater, and nothing else in your document should have any z-index definition. if you have an element with z-index of 1, and then you put another element in the same physical spot with a z-index of 2 -- the container with the higher z-index will overlap the one's with the lower.
Remove the z-indexes from the dropdowns. Also, what makes you think that setting a z-index of 0 on them will make things better?
Updated fiddle.

Categories

Resources