This is not a jQuery question. I'm not using an <anchor> or list for my menu. I want the menu (tab) item to be a different color when that menu (tab) is active. I've tried using CSS :active and :selection, but they don't work. I'm using a <label> inside a <p> tag for my menu:
<div id="MainMenu">
<p class="floatLeftP" id="SiteName">Site Name Here</p>
<p class="floatLeftP"><label id="ViewLink1" onclick="mainMenuChg('Home')">HOME</label></p>
<p class="floatLeftP"><label id="ViewLink2" onclick="mainMenuChg('Offered')">OFFERED</label></p>
<p class="floatLeftP"><label id="ViewLink3" onclick="mainMenuChg('Input')">INPUT</label></p>
<p class="floatLeftP"><label id="ViewLink4" onclick="mainMenuChg('Wanted')">WANTED</label></p>
<p class="floatLeftP"><label id="ViewLink5" onclick="mainMenuChg('MyAccount')">My Account</label></p>
<p class="floatLeftP"><label id="ViewLink6" onclick="openHTTPS()">Sign Up!</label></p>
<p class="floatRightP"><label id="ViewLink7" onclick="openHTTPS()">Sign In</label></p>
</div>
The CSS :active is for a link, but I'm not using a link.
When most of the menu items are clicked a function named mainMenuChg('argHere') runs.
function mainMenuChg(argPage) {
window.location.href = "#" + argPage;
};
This changes the URL in the browser, which then causes an angularJs router to trigger.
I don't want to use angularJs for this. I only want to use JavaScript. I can get a menu item to change color using:
document.getElementById(theID).style.color = "yellow";
But then it stays that color. If I click another menu item, then two menu items have turned yellow. I need to set the current <label> to a different color, then turn the last one back to it's original color. The menu items are different colors, so I need a way to set it back to the default.
I need a way to store the old id in a variable that doesn't loose it's value. But if I define a variable inside the function, it seems to loose it value.
I've seen a couple of questions that show a solution in jQuery, but not JavaScript.
First you can give a class to all labels.
For example, class="this-is-a-tab".
Then you can edit a little the function and add another parameter.
function mainMenuChg(argPage,tabId).
And on the labels...
onclick="mainMenuChg('Home',this.id)">
Now back to the function...
function mainMenuChg(argPage,tabId) {
//First We Remove the Yellow from all Tabs
var tabs = document.getElementsByClassName("this-is-a-tab");
//Then go through them
for(var i=0; i< tabs.length; i++)
{
tabs[i].style.color = "blue";
}
//Then we give yellow to the tab we clicked on.
document.getElementById(tabId).style.color = "yellow";
window.location.href = "#" + argPage;
};
Check if following pseudo code helps you
prevObj; // global variable.
if(prevObj != undefined) {
precObj.style.color = original_color;
}
this.style.color = "yellow";
prevObj = this;
Thanks to everyone's kind answers, I've been able to come up with a working solution. There is a full working version at jsFiddle, the link is at the bottom of the page. Here is the HTML.
<div id="menu">
<ul>
<li><a class="myMenu" id="xyz1" href="#" title="Update"><span>Home</span></a>
</li>
<li><a class="myMenu" id="abc2" href="#" title="Save"><span>Save</span></a>
</li>
<li><a class="myMenu" id="hij9" href="#" title="User"><span>User</span></a>
</li>
</ul>
</div>
And here is the code:
var menuHome = document.getElementById('xyz1');
var menuSave = document.getElementById('abc2');
var menuUser = document.getElementById('hij9');
menuHome.addEventListener('mouseup', clickedHome, false);
menuSave.addEventListener('mouseup', clickedSave, false);
menuUser.addEventListener('mouseup', clickedUser, false);
var currentMenuItem = '';
function clickedHome() {
if (menuHome === currentMenuItem) {
return;
};
//alert("home menu clicked: ");
menuHome.style.background = 'blue';
//alert('currentMenuItem: ' + currentMenuItem);
if (currentMenuItem !== undefined && currentMenuItem !== "") {
//alert("it ran: ");
currentMenuItem.style.background = '';
}
setCurrent(menuHome);
}
function clickedSave() {
if (menuSave === currentMenuItem) {
return;
};
//alert("home menu clicked: ");
menuSave.style.background = 'cyan';
if (currentMenuItem !== undefined && currentMenuItem !== "") {
//alert("it ran: ");
currentMenuItem.style.background = '';
}
setCurrent(menuSave);
}
function clickedUser() {
//alert("home menu clicked: ");
if (menuUser === currentMenuItem) {
return;
};
menuUser.style.background = 'blue';
if (currentMenuItem !== undefined && currentMenuItem !== "") {
//alert("it ran: ");
currentMenuItem.style.background = '';
}
setCurrent(menuUser);
}
function setCurrent(argMenu) {
//alert("set current ran: ");
currentMenuItem = argMenu;
//alert('currentMenuItem: ' + currentMenuItem);
};
Here is a working example at jsFiddle.
Highlight Active Menu Item on Menu Bar
Related
I am creating a to-do-list in javascript and everything was good until I had to deal with the local storage. I want to be able to refresh the page without losing what I put in my list just before.
I searched in many forums but I didn't find a similar case.
Here is a part of my HTML code : Just an ul and an input
Here is a part of my JS code : My function which creates li inside my ul
And here is a preview of my to do list : Hope it helps
So if I didn't explain my problem well enough, let me know and I will bring more precisions.
Thank for reading !
PS : I should specify that I already read the documentation on MDN and others websites and I understood the principle of localStorage but I'm struggling with the integration of this in my code. I saw lot of examples of its use but they are often too simple or on the contrary too different/hard to understand.
This is why I ask your help to have a little bit more personal response.
window.addEventListener('load', function()
{
var yourToDo = document.getElementById('myInput');
yourToDo.addEventListener('keydown', myFunction);
function myFunction(e)
{
if (e.keyCode == 13)
{
var line = document.createElement('div'); //This is my div which contains the 3 items which constitute a line
line.classList.add('myLine');
document.getElementById('myUl').appendChild(line);
var circle = document.createElement('i'); //The first item is a circle which can be check or unchecked
circle.id = 'myCircle';
document.querySelector('.myLine:last-child').appendChild(circle);
circle.addEventListener('click', function()
{
this.classList.toggle('fas');
this.classList.toggle('fa-check-circle');
this.classList.toggle('unstyled');
task.classList.toggle('crossedOut')
});
var task = document.createElement('li'); //The second item is a <li> which contains the value of the input
task.innerHTML = yourToDo.value.charAt(0).toUpperCase() + yourToDo.value.slice(1);
document.querySelector('.myLine:last-child').appendChild(task);
var trash = document.createElement('i'); //The third item is a trash which suppresses the whole line
trash.classList.add('fas');
trash.classList.add('fa-trash-alt');
document.querySelector('.myLine:last-child').appendChild(trash);
trash.addEventListener('click', function()
{
this.parentNode.remove();
});
yourToDo.value = '';
}
}
<section>
<ul id="myUl"></ul>
<label>
<input id="myInput" type="text" placeholder="Add your to do task" onfocus="this.placeholder = ''" onblur="this.placeholder = 'Add your to do task'">
</label>
</section>
I don't think that localStorage works in the code-snippets but try this in your own code.
I added a function to your code that gets all localStorage items and creates a list item for each on page load. Also added where you should save it to localStorage in your original function.
Comments are added throughout.
Hope this helps
window.addEventListener('load', function() {
var yourToDo = document.getElementById('myInput');
yourToDo.addEventListener('keydown', myFunction);
function myFunction(e) {
if (e.keyCode == 13) {
var line = document.createElement('div'); //This is my div which contains the 3 items which constitute a line
line.classList.add('myLine');
document.getElementById('myUl').appendChild(line);
var circle = document.createElement('i'); //The first item is a circle which can be check or unchecked
circle.id = 'myCircle';
document.querySelector('.myLine:last-child').appendChild(circle);
circle.addEventListener('click', function() {
this.classList.toggle('fas');
this.classList.toggle('fa-check-circle');
this.classList.toggle('unstyled');
task.classList.toggle('crossedOut')
});
var task = document.createElement('li'); //The second item is a <li> which contains the value of the input
task.innerHTML = yourToDo.value.charAt(0).toUpperCase() + yourToDo.value.slice(1);
//Set loacl storage item
localStorage.setItem(yourToDo.value.charAt(0).toUpperCase() + yourToDo.value.slice(1), yourToDo.value.charAt(0).toUpperCase() + yourToDo.value.slice(1));
document.querySelector('.myLine:last-child').appendChild(task);
var trash = document.createElement('i'); //The third item is a trash which suppresses the whole line
trash.classList.add('fas');
trash.classList.add('fa-trash-alt');
document.querySelector('.myLine:last-child').appendChild(trash);
trash.addEventListener('click', function() {
this.parentNode.remove();
});
yourToDo.value = '';
}
}
});
function load() {
//Create each item (as you did above)
function create(item) {
var yourToDo = document.getElementById('myInput');
var line = document.createElement('div'); //This is my div which contains the 3 items which constitute a line
line.classList.add('myLine');
document.getElementById('myUl').appendChild(line);
var circle = document.createElement('i'); //The first item is a circle which can be check or unchecked
circle.id = 'myCircle';
document.querySelector('.myLine:last-child').appendChild(circle);
circle.addEventListener('click', function() {
this.classList.toggle('fas');
this.classList.toggle('fa-check-circle');
this.classList.toggle('unstyled');
task.classList.toggle('crossedOut')
});
var task = document.createElement('li'); //The second item is a <li> which contains the value of the input
//Set innerHTML to item that you ar passing in for loop below
task.innerHTML = item;
document.querySelector('.myLine:last-child').appendChild(task);
var trash = document.createElement('i'); //The third item is a trash which suppresses the whole line
trash.classList.add('fas');
trash.classList.add('fa-trash-alt');
document.querySelector('.myLine:last-child').appendChild(trash);
trash.addEventListener('click', function() {
this.parentNode.remove();
});
yourToDo.value = '';
}
//Create an array to store all local storage items
var values = [],
keys = Object.keys(localStorage),
a = keys.length;
//Push items to array
while (a--) {
values.push(localStorage.getItem(keys[a]));
}
//Create a for loop and loop through all array items and pass each item value to the create funtion above
for (let i = 0; i < Object.keys(localStorage).length; i++) {
create(values[i])
}
}
//Call load on page load up (it would actually be better if you add this in your window "load" listener above )
load();
//Hope this helps!
<section>
<ul id="myUl"></ul>
<label>
<input id="myInput" type="text" placeholder="Add your to do task" onfocus="this.placeholder = ''" onblur="this.placeholder = 'Add your to do task'">
</label>
</section>
I work on a website, and I have a js problem.
I resume the situation:
I made a dynamic form with some tabs in.
I can switch tabs with a js click function
When I click on the "+" tab , it creates a new tab ( new <li> on the <ul>, and new <div> on main div )
But when I want to go on the new tab freshly created, the click function don't answer.
I put a console.log on the first line of the click function, and no log output.
the click function works well with static content, but with fresh content don't work.
How can I make it works with dynamic content ?
http://jsfiddle.net/npx2mes2/
http://jsfiddle.net/npx2mes2/1/
$("#tabs_menu_n1").on('click', 'a', function(e)
the problem was on registering the event, you should attach it to parent first, and then on every child.
change the line $(".tabs_menu_n1 a").click(function(e) { to $(document).on('click', ".tabs_menu_n1 a", function (e) {
Demo
Explanation.
when the elements are being added to DOM dynamically you must register the for the events every time the element is added. So instead of doing this process every time simply register events like below, therefore you don't want to register the events fro dynamically created elements
$(document).on('click', ".selector", function (e) {));
Now i can add elements with selector class dynamically and can handle click event on the element without registering the click event every time i add the element.
Note: You can use parent selector in place of document
A bit simplified sample without jQuery.
But idea same: add click handler to ul and check inside that clicked a tag.
var x = 2;
var original = document.getElementById('H1_n1');
function a(content, href) {
var link = document.createElement("a");
link.textContent = content;
link.setAttribute('href', href);
return link;
}
function li_a(id, content, href) {
var listItem = document.createElement("li");
listItem.setAttribute('id', id);
listItem.appendChild(a(content, href));
return listItem;
}
function div(id, textContent) {
var d = document.createElement("div");
d.setAttribute('class', 'tab_content_n1')
d.setAttribute('id', id)
d.textContent = textContent;
return d;
}
function add_rec() {
var i = x++;
var mdiv = document.getElementById("tab_n1");
mdiv.appendChild(div('H1_n' + i, '\nHello world from n' + i + '.\n'));
pbtn = document.getElementById('pbtn');
var ul = document.getElementById("tabs_menu_n1");
ul.insertBefore(li_a("hn" + i, "H" + i, "#H1_n" + i), pbtn);
}
document.getElementById('tabs_menu_n1').addEventListener('click', function(e) {
var el = e.target;
if (el.nodeName !== 'A') return;
if (el.hash == "#+") add_rec();
else {
e.preventDefault();
var current = document.querySelectorAll("#tabs_menu_n1 .current, #tab_n1 .current");
for (var i = 0, len = current.length; i < len; i++) {
current[i].classList.remove('current');
}
el.classList.add('current');
document.querySelector(el.hash).classList.add('current');
}
}, false);
.tab_content_n1 {
display: none;
}
.tab_content_n1.current {
display: block;
animation: fadeIn 1s;
}
a.current {
color: red;
}
#keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
<div class="tab_space">
<ul id="tabs_menu_n1" class="nav nav-tabs tabs_menu_n1 tab_body">
<li><a class="current" href="#M_n1">mai</a>
</li>
<li>red
</li>
<li id="hn1">hor
</li>
<li id="pbtn">+
</li>
</ul>
</div>
<div id="tab_n1" class="tab_n1">
<div class="tab_content_n1 current" id="M_n1">mai</div>
<div class="tab_content_n1" id="R_n1">red</div>
<div class="tab_content_n1" id="H1_n1">hor</div>
</div>
I have pasted the javascript below but also a link to my codepen so you can see exactly what I am talking about.
I would like the heading to be clicked and expose the text below. On another click I would like for the text to go back to hidden. Multiple headings can be opened at the same time. What is happening with my current setup is you can click once to show, click again to hide and then when you click again to show nothing shows, if you keep clicking the text and headings below are eaten/dissapear. I would prefer to do this without jquery. thanks for any help.
http://codepen.io/jrutishauser/pen/YPrrNa
var clickToShow = function () {
if (this.nextElementSibling.className === 'open'){
this.nextElementSibling.remove('open');
} else if (this.nextElementSibling.className != 'open') {
this.nextElementSibling.className = 'open';
}
};
var articleHeadings = document.getElementsByTagName('h3');
for (var index = 0; index < articleHeadings.length; index++){
articleHeadings[index].onclick = clickToShow;
}
var subArticleHeadings = document.getElementsByTagName('h4');
for (var index2 = 0; index2 < subArticleHeadings.length; index2++){
subArticleHeadings[index2].onclick = clickToShow;
}
Change this.nextElementSibling.remove('open') to this.nextElementSibling.className = ''. I believe remove() method removes the element, not the class.
You can do it like this also. This is the correct way of doing it.
var clickToShow = function () {
element=this.nextElementSibling;
if (element.className === 'open'){
element.className=element.className.replace('open','');
} else if (element.className != 'open') {
element.className = 'open';
}
};
I'm using jQuery hide and show function but I have a problem with the show one.
My javascript code is:
function toggle_visibility(idContent, idLien, question) {
var c = document.getElementById(idContent);
var l = document.getElementById(idLien);
var q = question;
if(c.style.display == 'block') {
$("#" + idContent).hide("blind") ;
l.innerHTML = '<h4><i class=\"icone-rouge icon-right-open-big\"></i>'+ q +'</h4>' ;
}
else {
$("#" + idContent).show("blind") ;
l.innerHTML = '<h4><i class=\"icone-rouge icon-down-open-big\"></i>'+ q +'</h4>' ;
}
}
The problem is that it doesn't work for the hide part when the div is hidden at the load of the page (with display='none'). I can display the block but then I cannot hide it.
I noticed that when I show a content, jQuery delete the display attr in my html style... Maybe there is a link.
Here a link for example : http://jsfiddle.net/29c4D/2/
Thank you.
DescampsAu, since you are using jQuery I rewrote your code to take full advantage of the powerful library. You can see the example in this fiddle.
Let jQuery do the heavy lifting of checking whether an element is hidden or not by making use of either the .toggle() or .slideToggle() methods.
Remove all of the onClick() code within your spans and use this jQuery instead:
jQuery
$(document).ready( function() {
//After the page has loaded, let jQuery know where all of the spans are.
var toggleThis = $(".toggleMe");
//Whenever you click one of the spans do this function.
toggleThis.click( function() {
//Register the span you clicked and the next div that holds the hidden stuffs.
var el = $(this),
nextDiv = el.next(".toggleMeDiv");
//Check if the span's partner div is hidden or showing by checking its css "display" value.
if(nextDiv.css("display") == "block") {
//Change the text of the span to be its title attribute plus whether its partner is showing or hidden.
el.html(el.attr("title")+" hidden");
} else {
el.text(el.attr("title")+" shown");
}
//Let jQuery toggle the partner's visibility.
nextDiv.slideToggle();
});
});
HTML
<span class="toggleMe" title="Quest 1">Quest 1</span>
<div class="toggleMeDiv">Boubou1</div>
<span class="toggleMe" title="Quest 2">Quest 2</span>
<div class="toggleMeDiv">Boubou2</div>
Making this too hard on yourself.
HTML
<span class="toggle" id="lien1" data-original-text="Quest 1">Quest 1</span>
<div id="content1">Boubou1</div>
<span class="toggle" id="lien2" data-original-text="Quest 1">Quest 2</span>
<div id="content2">Boubou2</div>
JS
$(document).ready( function () {
$('.toggle').on('click', function() {
$(this).next('div').toggle('blind', textToggle); // or slideToggle();
});
function textToggle() {
var $target = $(this).prev('span'); // "this" is the div that was toggled.
var originalText = $target.attr('data-original-text');
if ( $(this).is(':visible') ) {
$target.text( originalText + ' open' );
} else {
$target.text( originalText + ' closed' );
}
}
});
A fiddle: http://jsfiddle.net/29c4D/7/
EDIT to include label + effect.
I was taking a look at http://www.zenfolio.com/zf/features.aspx and I can't figure out how they are doing the accordion style expand and collapse when you click on the orange links. I have been using the Web Developer Toolbar add-on for firefox, but I have not been able to find anything in the source of the page like JavaScript that would be doing the following. If anyone knows how they are doing it, that would be very helpful.
This is actually unrelated, but if all you answers are good, who do I give the answer too?
They're setting the .display CSS property on an internal DIV from 'none' to '', which renders it.
It's a bit tricky, as the JS seems to be in here that's doing it:
http://www.zenfolio.com/zf/script/en-US/mozilla5/windows/5AN2EHZJSZSGS/sitehome.js
But that's basically how everyone does this. It's in there, somewhere.
EDIT: Here it is, it looks like:
//... (bunch of junk)
zf_Features.prototype._entry_onclick = function(e, index)
{
var cellNode = this.dom().getElementsByTagName("H3")[index].parentNode;
while (cellNode.tagName != "TD") cellNode = cellNode.parentNode;
if (this._current != null) this.dom(this._current).className = "desc";
if ("i" + index != this._current)
{
cellNode.className = "desc open";
cellNode.id = this.id + "-i" + index;
this._current = "i" + index;
}
else this._current = null;
zf_frame.recalcLayout();
return false;
};
Basically, what they're doing is a really roundabout and confusing way of making the div inside of TD's with a class "desc" change to the class "desc open", which reveals its contents. So it's a really obtuse roundabout way to do the same thing everyone does (that is, handling onclick to change the display property of a hidden div to non-hidden).
EDIT 2:
lol, while I was trying to format it, others found it too. =) You're faster than I ;)
Using jQuery, this effect can be built very easily:
$('.titleToggle').click(function() {
$(this).next().toggle();
});
If you execute this code on loading the page then it will work with any markup that looks like the following:
<span class="titleToggle">Show me</span>
<div style="display:none">This is hidden</div>
Notice that this code will work for any number of elements, so even for a whole table/list full of those items, the JavaScript code does not have to be repeated or adapted in any way. The tag names (here span and div) don't matter either. Use what best suits you.
It is being done with JavaScript.
When you click a link, the parent td's class changes from 'desc' to 'desc open'. Basically, the expanded text is always there but hidden (display: none;). When it gets the css class of 'open' the text is no longer being hidden (display: block;).
If you look in the sitehome.js and sitehome.css file you can get an idea about how they are doing that.
btw I used FireBug to get that info. Even though there is some feature duplication with Web Developer Toolbar it's worth the install.
They're using javascript. You can do it too:
<div id="feature">
Feature Name
<div id="desc" style=="display:none;">
description here...
</div>
</div>
<script type="text/javascript">
function toggle()
{
var el=document.getElementById('desc');
if (el.style.display=='none')
el.style.display='block'; //show if currently hidden
else
el.style.display='none'; //Hide if currently displayed
}
</script>
The function above can be written using Jquery for smooth fade in/fade out animations when showing/expanding the descriptions. It has also got a SlideUp and Slidedown effect.
There is a lot of obfuscated/minified JS in their master JS include. It looks like they are scraping the DOM looking for H3's and checking for table cells with class desc and then processing the A tags. ( or some other order, possibly ) and then adding the onclick handlers dynamically.
if (this._current != null) this.dom(this._current).className
= "desc"; if ("i" + index != this._current) { cellNode.className = "desc open"; cellNode.id = this.id
+ "-i" + index; this._current = "i" + index; }
http://www.zenfolio.com/zf/script/en-US/safari3/windows/5AN2EHZJSZSGS/sitehome.js
The script is here.
The relevant section seems to be (re-layed out):
// This script seems over-complicated... I wouldn't recommend it!
zf_Features.prototype._init = function()
{
// Get a list of the H3 elements
var nodeList = this.dom().getElementsByTagName("H3");
// For each one...
for (var i = 0; i < nodeList.length; i++)
{
// ... set the onclick to be the function below
var onclick = this.eventHandler(this._entry_onclick, i);
// Get the first <a> within the H3 and do the same
var node = nodeList[i].getElementsByTagName("A")[0];
node.href = "#";
node.onclick = onclick;
// And again for the first <span>
node = nodeList[i].getElementsByTagName("SPAN")[0];
node.onclick = onclick;
}
};
zf_Features.prototype._entry_onclick = function(e, index)
{
// Get the parent node of the cell that was clicked on
var cellNode = this.dom().getElementsByTagName("H3")[index].parentNode;
// Keep going up the DOM tree until we find a <td>
while (cellNode.tagName != "TD")
cellNode = cellNode.parentNode;
// Collapse the currently open section if there is one
if (this._current != null)
this.dom(this._current).className = "desc";
if ("i" + index != this._current)
{
// Open the section we clicked on by changing its class
cellNode.className = "desc open";
cellNode.id = this.id + "-i" + index;
// Record this as the current one so we can close it later
this._current = "i" + index;
}
else
this._current = null;
// ???
zf_frame.recalcLayout();
return false;
};
Edit: added some comments
Unfortunately their code is in-lined and hard to read (http://www.zenfolio.com/zf/script/en-US/mozilla5/windows/5AN2EHZJSZSGS/sitehome.js), but this looks quite simple to implement... something along these lines (using prototypejs):
<script>
var showHide = {
cachedExpandable: null
,init: function() {
var containers = $$(".container");
for(var i=0, clickable; i<containers.length; i++) {
clickable = containers[i].getElementsByClassName("clickable")[0];
Event.observe(clickable, "click", function(e) {
Event.stop(e);
showHide.doIt(containers[i]);
});
}
}
,doIt: function(container) {
if(this.cachedExpandable) this.cachedExpandable.hide();
var expandable = container.getElementsByClassName("expandable")[0];
if(expandable.style.display == "none") {
expandable.show();
} else {
expandable.hide();
}
this.cachedExpandable = expandable;
}
};
window.onload = function() {
showHide.init();
};
</script>
<div class="container">
<div class="clickable">
Storage Space
</div>
<div class="expandable" style="display: none;">
Description for storage space
</div>
</div>
<div class="container">
<div class="clickable">
Galleries
</div>
<div class="expandable" style="display: none;">
Description for galleries
</div>
</div>
Its also caching the earlier expandable element, so it hides it when you click on a new one.