JavaScript/HTML - Set selected tab based on url variable - javascript

I have a search page, and I found a script for a tab component which seperates the TV-Show search page and Movie search page. When a user clicks on lets say the "Movie" tab, and perform a search from there, I make the form add ?type=movie&... to the url. But, when they perform the search, the tab that's selected is the the "TV-Show" tab, and the have to click over to get to the other tab which has the results they want.
Here is the code, and in it is some of what I tried:
the HTML looks like this:
<article class="first">
<h2>Search</h2>
<hr/>
<div id="tabWrapper">
<div id="tabContainer">
<div class="tabs">
<ul>
<li id="tabHeader_1">TV Shows</li>
<li id="tabHeader_2">Movies</li>
</ul>
</div>
<div class="tabContent">
<div class="tabpage" id="tabpage_1">
<?php
if (isset($sortFilt['year']))
unset($sortFilt['year']);
if ($sortField=="year")
$sortField==" ";
DisplaySearchPage("shows", $terms, $sortField, $sortDir, $sortFilt, $page, $perPage);
?>
</div>
<div class="tabpage" id="tabpage_2">
<?php
DisplaySearchPage("movies", $terms, $sortField, $sortDir, $sortFilt, $page, $perPage);
?>
</div>
</div>
</div>
</div>
</article>
<script src="tabs.js"></script>
And this is the the tabs.js script:
window.onload=function() {
// get tab container
var container = document.getElementById("tabContainer");
// set current tab
var navitem = container.querySelector(".tabs ul li");
//store which tab we are on
var ident = navitem.id.split("_")[1];
navitem.parentNode.setAttribute("data-current",ident);
//set current tab with class of activetabheader
navitem.setAttribute("class","tabActiveHeader");
//hide two tab contents we don't need
var pages = container.querySelectorAll(".tabpage");
for (var i = 1; i < pages.length; i++) {
pages[i].style.display="none";
}
//this adds click event to tabs
var tabs = container.querySelectorAll(".tabs ul li");
for (var i = 0; i < tabs.length; i++) {
tabs[i].onclick=displayPage;
}
// This below is is what I tried.
var selTab = (getUrlVars()["type"] == "movies") ? 2 : 1;
var selTab = (getUrlVars()["type"] == "movies") ? 1 : 0; // Tried this too.
tabs[selTab].click();
// its seems like it should have worked, what am I doing wrong.
}
// on click of one of tabs
function displayPage() {
var current = this.parentNode.getAttribute("data-current");
//remove class of activetabheader and hide old contents
document.getElementById("tabHeader_" + current).removeAttribute("class");
document.getElementById("tabpage_" + current).style.display="none";
var ident = this.id.split("_")[1];
//add class of activetabheader to new active tab and show contents
this.setAttribute("class","tabActiveHeader");
document.getElementById("tabpage_" + ident).style.display="block";
this.parentNode.setAttribute("data-current",ident);
}
How can I adapt this script to let me decide which tab is displayed when the page is loaded based on what the type variable is in the URL parameters?

I found the answer. My problem was with getUrlVars["type"], it failed to give me the value of the 'type' url variable, so I created my own function for it. Here is the working code if anyone else is wondering how to get variables from the url.
function getURLParameter(name)
{
return decodeURI(
(RegExp(name + '=' + '(.+?)(&|$)').exec(location.search)||[,null])[1]
);
}
window.onload = function()
{
// Get tab container
var container = document.getElementById("tabContainer");
// Set the current tab.
var navitem = container.querySelector(".tabs ul li");
// Store which tab is selected.
var ident = navitem.id.split("_")[1];
navitem.parentNode.setAttribute("data-current", ident);
// Set the current tab with a class of 'activetabheader'.
navitem.setAttribute("class", "tabActiveHeader");
// Hide the tab contents we don't need.
var pages = container.querySelectorAll(".tabpage");
for (var i = 1; i < pages.length; i++) {
pages[i].style.display = "none";
}
// This adds the click event handler to the tabs.
var tabs = container.querySelectorAll(".tabs ul li");
for (var i = 0; i < tabs.length; i++) {
tabs[i].onclick = displayPage;
}
// Selects tab based on 'type' url variable.
if (getURLParameter("type") == "movies") {
tabs[1].click();
}
}
// OnClick() event handler for tabs.
function displayPage()
{
var current = this.parentNode.getAttribute("data-current");
// Remove class of 'activetabheader' and hide the old contents.
document.getElementById("tabHeader_" + current).removeAttribute("class");
document.getElementById("tabpage_" + current).style.display = "none";
var ident = this.id.split("_")[1];
// Add a class of 'activetabheader' to new active tab and show contents.
this.setAttribute("class", "tabActiveHeader");
document.getElementById("tabpage_" + ident).style.display = "block";
this.parentNode.setAttribute("data-current", ident);
}

Related

Eventlisteners not being added in the following js code

I am building a todo app where I am dynamically generating tasks using javascript.[]
I generate following equivalent html from js whenever I click on the add button:
<div class="row datasection">
<div class="todo">
<div class="databox col s6 offset-s1 waves-effect">
<p class="checkglyph1 checkglyph2">Task no 1</p>
<a>
<i class="material-icons checkglyph checkglyph1 checkglyph2 glyphcolor">check</i>
</a>
</div>
</div>
</div>
Now what I want is whenever I click event on the task created it should become yellow in colour.I have written the code to this. below.However it works fine only when there is one task created.If there is multiple then the last task works well but actionlistener on the first one does not seem to be working.I am not able to figure out where the code is breaking.
var glyph= document.querySelectorAll(".glyphcolor");
for (var i = 0; i < glyph.length; i++) {
glyph[i].addEventListener('click', function(event) {
this.classList.toggle("checkglyph1");
});
}
The actual snippet
//declaration
var calendardata = document.getElementById('date1');
var addbutton = document.querySelector('.addbutton');
var todo = document.querySelector('.todo');
addbutton.addEventListener('click', function() {
/* body to return the html */
if (data.value) {
var newdiv = document.createElement("div"); // Create a <button> element
newdiv.classList.add("databox", "col", "s6", "waves-effect");
//console.log(newdiv);
todo.appendChild(newdiv);
//console.log(newdiv.parentNode);
var newpar = document.createElement("p");
newpar.classList.add("checkglyph1", "checkglyph2");
var node = document.createTextNode(data.value + "." + " " +
calendardata.value);
var newa = document.createElement("a");
newdiv.appendChild(newa)
var newglyph = document.createElement("i");
newglyph.classList.add("material-icons", "checkglyph", "checkglyph1",
"checkglyph2", "glyphcolor");
var node1 = document.createTextNode("check");
newa.appendChild(newglyph);
newglyph.append(node1);
newpar.appendChild(node);
newdiv.appendChild(newpar);
data.value = "";
calendardata.value = "";
created = true;
// console.log("before glyh created");
//code to perform action on the click of the tick symbol
var glyph = document.querySelectorAll(".glyphcolor");
var par = document.getElementsByClassName('checkglyph2');
for (var i = 0; i < glyph.length; i++) {
//console.log("Inside the loop");
glyph[i].addEventListener('click', function.bind(event) {
this.classList.toggle("checkglyph1");
//console.log('Inside the click');
//console.log(i);
});
}
}
})
What's happening that when they other tasks are created they aren't being collected in the Node Collection, thus they have no event listener. What you can do is instead add the event listener to the container and change whichever item that was clicked in:
document.querySelector('ul').addEventListener('click', changeClass);
document.querySelector('#button').addEventListener('click', addLi);
function changeClass(e){
e.target.closest('li').classList.toggle('checkglyph1');
}
function addLi(e){
const new_li = document.createElement('li');
new_li.textContent = document.querySelectorAll('li').length + 1;
new_li.classList.add('checkglyph1');
document.querySelector('ul').appendChild(new_li);
}
li:not(.checkglyph1) {
background: #f00;
}
<button id="button">Add li</button>
<ul>
<li class="checkglyph1">1</li>
<li class="checkglyph1">2</li>
<li class="checkglyph1 red">3</li>
<li class="checkglyph1">4</li>
<li class="checkglyph1">5</li>
<li class="checkglyph1">6</li>
<li class="checkglyph1">7</li>
<li class="checkglyph1">8</li>
<li class="checkglyph1">9</li>
<li class="checkglyph1">10</li>
</ul>
The problem with your code is that everytime you click on ".addbutton", you're going through all of the ".glyphcolor"s element's in your DOM and adding a new onclick event listener. The last one created will work, but the others will have multiple event listeners repeated (yes, this is possible). So, when you click on an element that has two events telling it to toggle the "checkglyph1" class, it will do it twice. And of course, it will not change at all. You can easily see this happening, because all the odd elements in your page must work (they will toggle the class by odd times), while the even ones must not.
This can be corrected by adding the event listener directly on the element when you create it on the page. The code below must work fine:
//declaration
var calendardata = document.getElementById('date1');
var addbutton = document.querySelector('.addbutton');
var todo = document.querySelector('.todo');
addbutton.addEventListener('click', function() {
if (data.value) {
var newdiv = document.createElement("div"); // Create a <button> element
newdiv.classList.add("databox", "col", "s6", "waves-effect");
//console.log(newdiv);
todo.appendChild(newdiv);
//console.log(newdiv.parentNode);
var newpar = document.createElement("p");
newpar.classList.add("checkglyph1", "checkglyph2");
var node = document.createTextNode(data.value + "." + " " +
calendardata.value);
var newa = document.createElement("a");
newdiv.appendChild(newa)
var newglyph = document.createElement("i");
newglyph.classList.add("material-icons", "checkglyph", "checkglyph1",
"checkglyph2", "glyphcolor");
var node1 = document.createTextNode("check");
newa.appendChild(newglyph);
newglyph.append(node1);
newpar.appendChild(node);
newdiv.appendChild(newpar);
data.value = "";
calendardata.value = "";
created = true;
newglyph.addEventListener('click', function(event) {
event.preventDefault(); // Just to prevent non desired effects of click
newglyph.classList.toggle('checkglyph1');
}
}
}
And just small clarifications: you don't need the "bind" in your actual code.
glyph[i].addEventListener('click', function.bind(event) { // just type function(event)
this.classList.toggle('checkglyph1');...

Showing / Hiding nested divs

Hi and I hope someone can help.
I'm building a website which will have a main horizontal tabbed menu and a secondary horizontal tabbed menu when one of the items above is clicked. Off the second tabbed menu there will be another sub menu which bring up links where, once clicked, will reveal content to the right. Pictorially this is shown below.
To try and get the logic working I've built some very simple test pages to try out showing and hiding divs but I only seem to be able to get the equivalent of the first sub menu showing.
Because (ultimately) this will be a large site with multiple pages I've organised the first menu in the root folder of the site, the sub menu in a sub folder called 'pages' and the sub sub menu in a folder called 'pages/resource_pages'.
Here's my test code, 1 the top level - nest.html in the root folder
<body onload="openLevel2();"> <!-- done to initially hide unwanted divs -->
<div id="home">Nested Div Test</div>
</br>
<div id="div1"> Nest 1 - located in root folder </div>
<div id="nest1" class="level1HiddenDiv">
<script>$( "#nest1" ).load( "pages/nest2.html" );</script>
</div>
</body>
Second level code - nest2.html in the pages folder
<body>
<div id="div2"> Nest 2 - located in root/pages folder </div>
<div id="nest2" class="level2HiddenDiv">
<script>
$( "#nest2" ).load( "pages/resource_pages/nest3.html" );
</script>
</div>
</body>
Third level code - nest3.html in the pages/resource_pages sub folder
<body>
<div id="div3"> Nest 3 - located in root/pages/resource_pages folder </div>
<div id="nest3" class="level3HiddenDiv">
<script>
$( "#nest3" ).load( "ca_nearby.html" );
</script>
</div>
</body>
Here' my javascript
function openLevel2(evt, scriptName) {
// Declare all variables
var i, level1Hyperlink, level1HiddenDiv;
// Get all elements with class="level1HiddenDiv" and hide them
level1HiddenDiv = document.getElementsByClassName("level1HiddenDiv");
for (i = 0; i < level1HiddenDiv.length; i++) {
level1HiddenDiv[i].style.display = "none";
}
// Get all elements with class="level1Hyperlink" and remove the class "active"
level1Hyperlink = document.getElementsByClassName("level1Hyperlink");
for (i = 0; i < level1Hyperlink.length; i++) {
level1Hyperlink[i].className = level1Hyperlink[i].className.replace(" active", "");
}
// Show the current tab, and add an "active" class to the link that opened the tab
document.getElementById(scriptName).style.display = "block";
evt.currentTarget.className += " active";
}
// Script for showing resource letter menu tabs
function openLevel3(evt, resourceName) {
// Declare all variables
var i, level2Hyperlink, level2HiddenDiv;
// Get all elements with class="level2Hyperlink" and hide them
level2HiddenDiv = document.getElementsByClassName("level2HiddenDiv");
for (i = 0; i < level2HiddenDiv.length; i++) {
level2HiddenDiv[i].style.display = "none";
}
// Get all elements with class="level2Hyperlink" and remove the class "active"
level2Hyperlink = document.getElementsByClassName("level2Hyperlink");
for (i = 0; i < level2Hyperlink.length; i++) {
level2Hyperlink[i].className = level2Hyperlink[i].className.replace(" active", "");
}
// Show the current tab, and add an "active" class to the link that opened the tab
document.getElementById(resourceName).style.display = "block";
evt.currentTarget.className += " active";
}
// Script for showing resource letter sub menu tabs
function openLevel4(evt, letterName) {
// Declare all variables
var i, level3Hyperlink, level3HiddenDiv;
// Get all elements with class="level3HiddenDiv" and hide them
level3HiddenDiv = document.getElementsByClassName("level3HiddenDiv");
for (i = 0; i < level3HiddenDiv.length; i++) {
level3HiddenDiv[i].style.display = "none";
}
// Get all elements with class="level3Hyperlink" and remove the class "active"
level3Hyperlink = document.getElementsByClassName("level3Hyperlink");
for (i = 0; i < level3Hyperlink.length; i++) {
level3Hyperlink[i].className = level3Hyperlink[i].className.replace(" active", "");
}
// Show the current tab, and add an "active" class to the link that opened the tab
document.getElementById(letterName).style.display = "block";
evt.currentTarget.className += " active";
}
Can anyone spot what I'm doing wrong?
Thanks for your interest.
Messing around with a lot js and html, you can run into problems concerning readability, so i would prefer a pure js solution, wich will make it more readable /better debuggable:
var structure={
name:"level1",
links:[
{
name:"level2-1",
links:[
{
name:"level3-1",
links:[]
},
{
name:"level3-2",
links:[]
}
]
},
{ name:"level2-2", ...
}
]
};
function show(element){
//add the name to header
document.GetElementById("header").innerHTML=element.name;
linkcontainer=document.getElementById("linkcontainer");
linkcontainer.innerHTML="";
counter=0;
element.links.forEach(function(link){
l=document.createElement("span");
l.onclick=(function(element,counter){
//this should create an onclick element
return function(){show(element.links[counter])};
})(element,counter);
l.innerHTML=element.links[counter].name;
linkcontainer.appendChild(l);
counter++;
}
}
window.onload=function(){show(structure);}
</script>
<div id="header">should contain name</header>
<div id="linkcontainer">should contain links</div>
This should create:
Level1
Level2.1
Level2.2
And if you click on level 2.1:
Level2.1
Level3.3
Level3.4
I had problems with the onclick statement: http://www.howtocreate.co.uk/referencedvariables.html

Multiple Functions with one Code

so I'm using this code, to slideToggle a box on my webpage.
// OPEN CERTAIN BOX
$(function() {
var sliding = false;
var mq = window.matchMedia( "(min-width: 700px)" );
if (mq.matches) {
var time = 500;
} else {
var time = 0;
}
var id = ('1');
var div = ('#toggle-content-' + id);
var img = ('#toggle-img-' + id);
var toggler = ('toggler-' + id);
$(div).hide()
$(toggler).click(function() {
if (sliding == false) {
sliding = true;
// Open / Close
$( div ).slideToggle(time,"swing");
// ...
As you can see, I'm using the var id, to use the toggle function for a certain box, which has its own css and html code.
I have 7 more boxes. Until now, i copied the code 7 times and changed the id at each copy from 2 - 8. Is there a way to make it with one code?
I tried a for loop, that goes from 1 - 8 but this obviously didnt work.
Has someone an idea? Or do I have to make that 8 copies and changed the id.
Edit:
My approach with the for-loop:
$(function() {
var sliding = false;
var mq = window.matchMedia( "(min-width: 700px)" );
if (mq.matches) {
var time = 500;
} else {
var time = 0;
}
for(i = 1; i <= 8; i++){
var id = (i.toString());
var div = ('#toggle-content-'+id);
var img = ('#toggle-img-'+id);
var toggler = ('toggler-'+id);
$( div ).hide()
$( toggler ).click(function(){
if (sliding == false){
sliding = true;
// Open / Close
$( div ).slideToggle(time,"swing");
...
And this is my html code for one box:
<tr><td cellspacing="0" cellpadding="0" height="50px" class="upper">
<toggler-1><area-head-text><img id="toggle-img-1" src="images/box_opener.png"/>Starterpaket</area-head-text></toggler-1>
</td></tr>
<tr><td>
<div id="toggle-content-1">
<area-head-text>
<img class="text-image" src="images/arrow.png"/>3 individuelle Entwürfe<br>
<img class="text-image" src="images/arrow.png"/>3 Korrekturzeichnungen<br>
<img class="text-image" src="images/arrow.png"/>Internationale Nutzungsrechte<br>
<img class="text-image" src="images/arrow.png"/>400€<br><br>
</area-head-text>
</div>
</td></tr>
I'm not sure why you put "Obviously" a loop doesn't work, because that's pretty much exactly what you should do. Something like this:
for(var i = 1; i <= 8; i++)
{
var div = $('#toggle-content-' + i);
var img = $('#toggle-img-' + i);
var toggler = $('toggler-' + i);
$(div).hide()
$(toggler).click(function() {
if (sliding == false) {
sliding = true;
// Open / Close
$( div ).slideToggle(time,"swing");
// ...
}
This is 2 options.
(and my preference) -
Instead of using an ID to add the click event onto each individual toggle button, use the same class on each, and add the click event on that class. When the user clicks a toggle button traverse the DOM from the clicked toggle button to perform your toggle on the relevant <div>.
This would look something like:
$(function() {
$('.toggleBtn').click(function() {
var sliding = $(this).data('sliding'); //use data attr to store sliding status
if (sliding == false) {
$(this).data('sliding') = true;
}else {
return; //don't toggle we're sliding
}
// navigate to element and toggle
$(this).parent('.someParentElement').children('.theDiv').slideToggle(time,"swing");
//clear sliding status
$(this).data('sliding', false);
}
}
The reason this is my preference, is because although it's faster to target an ID for a click event than a class for a single event, using 7 click events on 7 different IDS in my opinion (I don't know for sure) is less efficient than using a single click event on 1 class. That's my perceived purpose of using events on classes rather than IDS.
Also this way, when you want to add another box in, or remove a box, you don't need to modify any Javascript, the only thing you would need to maintain this code for is if you decide to change the structure of the HTML, and therefore the navigation of the DOM to perform your toggle.
using your method:
var ids = ["id1","id2","id3"];
for(var id in ids) {
var $div = $('#toggle-content-' + id);
var $img = $('#toggle-img-' + id);
var $toggler = $('toggler-' + id);
$div.hide()
$toggler.click(function() {
if (sliding == false) {
sliding = true;
// Open / Close
$div.slideToggle(time,"swing");
// ...
}

Jquery - Toggle Image Src if Parent Class is Clicked Hide/Show

I have a program that is configured to hide/show table rows when a +/- icon is clicked. The functionality is working, however, I need to figure out a way to reset all hide/show icons when the parent category is toggled closed.
$(function(){
//src vars
var hide_src = "http://www.synchronizeddesigns.com/filter_hide.gif",
reveal_src = "http://www.synchronizeddesigns.com/filter_reveal.gif",
s = '';
//hide all sublevel elements
$(".subsub, .subsubsub").hide();
$("a").click(function(e){
e.preventDefault();
var tID = e.target.id,
tClass = '.' + tID.replace('HS', '');
$(tClass).toggle();
if(!$(tClass).is(':visible')){
s = hide_src;
//for each subcategory
$(tClass).each(function(){
//get class names into classes array
var classes = $(this).attr('class').split(' '),
parentClass = '';
//search classes array for class that begins with 'cat'
for (var j=0; j<classes.length; j++) {
if (classes[j].match("cat")){
parentClass = classes[j];
}
}
//find subsubsub elements that have a class that begins with 'cat#sub'
var subs = $('[class*=' + parentClass + 'sub]');
//if there are sub elements, hide them too
if(subs){
subs.hide();
/*****************************************************
NEED HELP HERE !!!!!!!!!!
Need a way to reset all hide/show images icon
when 'parentClass' hide/show is clicked to close.
*****************************************************/
}
});
} else {
s = reveal_src;
}
//Change image src
$("#" + tID).attr('src', s);
});
});
To replicate: Toggle open all parents and subs, then close one of the parents, then reopen the parent. You'll notice that the +/- icon remains in it's previous state
jsFiddle link
You can find the img nodes for the subcategories under the current one and then change their src attr.
I've updated your jsfiddle: http://jsfiddle.net/nTyWv/12/
The code could be something like:
if(subs){
innerIcons = jQuery.find("a > img[id*="+tID+"sub]");
if (innerIcons) {
$(innerIcons).attr('src', s);
};
subs.hide();
}

Fade effect on display="block" action in Javascript

I have some javascript that is switching between 3 divs on click of 1 of 3 tabs.
Here is my Javascript:
(function($){
$.fn.acidTabs = function(options) {
var settings = {
'style' : 'one'
};
options = $.extend( settings, options );
return this.each (function () {
var o = options;
container = this;
container.setAttribute("class",o.style);
var navitem = container.querySelector("li");
//store which tab we are on
var ident = navitem.id.split("_")[1];
navitem.parentNode.setAttribute("data-current",ident);
//set current tab with class of activetabheader
navitem.setAttribute("class","tabActiveHeader");
//hide two tab contents we don't need
var pages = container.querySelectorAll(".tabpage");
for (var i = 1; i < pages.length; i++) {
pages[i].style.display="none";
}
//this adds click event to tabs
var tabs = container.querySelectorAll("li");
for (var i = 0; i < tabs.length; i++) {
tabs[i].onclick=displayPage;
}
});
// on click of one of tabs
function displayPage() {
var current = this.parentNode.getAttribute("data-current");
//remove class of activetabheader and hide old contents
document.getElementById("tabHeader_" + current).removeAttribute("class");
document.getElementById("tabpage_" + current).style.display="none";
var ident = this.id.split("_")[1];
//add class of activetabheader to new active tab and show contents
this.setAttribute("class","tabActiveHeader");
document.getElementById("tabpage_" + ident).style.display="block";
this.parentNode.setAttribute("data-current",ident);
}
};
})(jQuery);
I cant seem to modifiy this to accept fading effects. Or maybe there is a better way to do this?
Would love your help!
Thank you.
it's not easy because you can't do it.
You need to split the two css statements.
New div with opacity:0 and display:none
change display to block
and then change opacity using setTimeout (even a 10ms delay will do).
do the opposite for the div that will hidden.
something like this:
var newdiv=document.getElementById("tabpage_" + ident);
newdiv.style.display="block";
setTimeout(function(){newdiv.style.opacity="1";},10);
OK figured it out with some help from the asp.net forum. Replace the function displayPage() with this:
var current = this.parentNode.getAttribute("data-current");
//remove class of activetabheader and hide old contents
$('#tabHeader_' + current).removeClass('tabActiveHeader');
$('#tabpage_' + current).hide();
var ident = this.id.split("_")[1];
//add class of activetabheader to new active tab and show contents
$(this).addClass("tabActiveHeader");
$('#tabpage_' + ident).fadeIn();
this.parentNode.setAttribute("data-current",ident);

Categories

Resources