I am Using a Wordpress, and I would like users to open a specific tab directly from a link in the navbar. So I want to disable the default active tab (15 Nov) and activate the tab with the value in url.
I have tried domain.com/agenda/#16-nov but it did not work!
Can anyone advise how this is done?
<ul class="scheduleday_wrapper tab">
<li data-tab="15-nov" class="scheduleday_title active">
<div class="scheduleday_title_content">
<h4 style="">15 Nov</h4>
</div>
<br class="clear">
</li>
<li data-tab="16-nov" class="scheduleday_title">
<div class="scheduleday_title_content">
<h4 style="">16 Nov</h4>
</div>
<br class="clear">
</li>
<li data-tab="17-nov" class="scheduleday_title">
<div class="scheduleday_title_content">
<h4 style="">17 Nov</h4>
</div>
<br class="clear">
</li>
</ul>
And here the class code of content:
<ul id="15-nov" class="scheduleday_wrapper themeborder tab_content"></ul>
<ul id="16-nov" class="scheduleday_wrapper themeborder tab_content hide"></ul>
<ul id="17-nov" class="scheduleday_wrapper themeborder tab_content hide"></ul>
A Link could be an anchor tag Link, something that simulates anchor behavior (e.g. using a JavaScript routing library), a clickable element with an Event Listener, etc.. It is not clear if you must use URL hashes (/agenda/#16-nov), or if they are just something you experimented with. If you must use URL hashes (e.g. because a request must go the server first for processing before re-rendering the page), I can provide another solution.
The JavaScript below uses clickable elements (your <li class="scheduleday_title"/> tabs) to trigger event listeners. It assumes one tab is always active. The function updateActiveStatus is called within the tab event listener with the selected date as its argument in the format 17-nov.
You can make adjustments and test them with JSFiddle.
updateActiveStatus function
/**
* Update the active state of tab elements and the hide state of content elements.
*
* #param {string} currentDate - Date from the clicked tab.
*
*/
function updateActiveStatus (currentDate) {
// currentDate: e.g. 17-nov
let previousTabElement = document.querySelector('.active');
if (previousTabElement != null) {
previousTabElement.classList.remove('active');
// Hide all content elements.
let contentElements = document.querySelectorAll('.content .scheduleday_wrapper');
for (let contentElement of contentElements) {
contentElement.classList.add('hide');
}
// Activate the new tabElement and show the new content element.
let tabElements = document.querySelectorAll('.scheduleday_title');
for (let tabElement of tabElements) {
if (tabElement.dataset.tab == currentDate) {
tabElement.classList.add('active');
let contentElement = document.getElementById(currentDate);
contentElement.classList.remove('hide');
break;
}
}
}
}
Add Event Listeners
let tabs = document.querySelectorAll('.scheduleday_title');
for (let tab of tabs) {
tab.addEventListener('click', function() {
updateActiveStatus(tab.dataset.tab);
});
}
Related
Basically I'm trying to make a todo list app similar to Trello. I have a button that when pressed turns into an input element, gets a "To Do Task" item and adds that to a list. This is achieved by this piece of code:
function createCardBoxNode(title){
/*HTML looks like:
<div class="task-card">
<div class="writings">
<p class="title">Tasks To Do</p>
<ul id="tasks">
<li>Task 1</li>
</ul>
</div>
<button class="btn-add-task">
Add New Task...
</button>
<input....>
</div>
*/
var containerBox = createElement('div', {class:'task-card'});
var writingPartBox = createWritingAreaNode(title);
var newTaskBtn = createElement('button', {class:'btn-add-task show'},'Add New Task...');
var newTaskInput = createElement('input', {class:'new-task hide', type:'text', placeholder:'New Task'});
//When 'add new task' is clicked, make it an input area
newTaskBtn.addEventListener('click', function(){
newTaskBtn.classList.remove('show');
newTaskBtn.classList.add('hide');
newTaskInput.classList.remove('hide');
newTaskInput.classList.add('show');
newTaskInput.focus();
});
// when input is entered, that's a new "To Do Task" so add it to the list
newTaskInput.addEventListener('keyup', function(e){
if (e.keyCode === 13){
// If Enter is pressed
var newTask = createListItems(newTaskInput.value);
var listArea = document.getElementById('tasks');
listArea.appendChild(newTask);
newTaskInput.classList.remove('show');
newTaskInput.classList.add('hide');
newTaskInput.value = '';
newTaskBtn.classList.remove('hide');
newTaskBtn.classList.add('show');
}
});
containerBox.appendChild(writingPartBox);
containerBox.appendChild(newTaskBtn);
containerBox.appendChild(newTaskInput);
return containerBox;
}
This works fine until I add another Card at the same time and decide to add new tasks to the second card. Then every task gets added to the first card. I wonder if there is any way to check if the "input" that's being sent is going to a specific card checking the card's title. I don't have any limits on how many tasks can be added to each card, and don't want to add that. I also want the user to be able to work on two separate cards at the same time. As a beginner, I also want to fix this using only JavaScript. I hope I've explained the issue well enough.
Edit:
I have tried doing this:
if (document.querySelector('.title').innerText === title){
var newTask = createListItems(newTaskInput.value);
var listArea = document.getElementById('tasks');
listArea.appendChild(newTask);
newTaskInput.classList.remove('show');
newTaskInput.classList.add('hide');
newTaskInput.value = '';
newTaskBtn.classList.remove('hide');
newTaskBtn.classList.add('show');
But then I cannot add anything new to the second box.
I think your main problem is that you use the <ul> with the same id for different cards.
First of all, change your markup and replace <ul id="tasks"> with <ul class="tasks-list">
<div class="task-card">
<div class="writings">
<p class="title">Tasks To Do</p>
<ul class="tasks-list"> <!-- !!! here !!! -->
<li>Task 1</li>
</ul>
</div>
<button class="btn-add-task">
Add New Task...
</button>
<input....>
</div>
and then change that selector in your keyup handler:
//...
var listArea = containerBox.querySelector('.tasks-list');
// ...
Also, it would be better to declare
var listArea = containerBox.querySelector('.tasks-list');;
outside your handler.
I solved it on my own.
The trick is to not select anything at all. Everytime you queryselect anything, or get an element using it's ID - it will select the first element with that id or class.
What I ended up doing is to combine two of my functions, have a function generate my and then just straight up append the list items into that ul. No selection whatsoever.
I'm fairly new to .js and have been working on a dropdown nav menu. I've got most of it functioning, but I was asked to include a specific snippet for the menu activation.
I'd like to figure out how to make the other subnav items hide or scroll up when a different subnav is opened.
What am I doing wrong here?
<div id="nav_mob">
<div id="nav-toggle"><span></span></div>
<div class="dropdown_mob">
<ul>
<a class="dropdown_btn">
<li>Overview</li>
</a>
<div class="subnav_mob">
<ul>
<li>Introduction</li>
<li>Research</li>
<li class="padded">Planning & Preparation</li>
<li>International</li>
</ul>
</div>
<a class="dropdown_btn"><li>Profile</li></a>
<div class="subnav_mob">
<ul>
<li>My Account</li>
<li>My Cart</li>
<li>Check Out</li>
<li>Log Out</li>
</ul>
</div>
<a class="dropdown_btn"><li>Search</li></a>
<div class="subnav_mob">
<ul>
<li><div id="smallsearch"><input type="text"></div></li>
</ul>
</div>
</div>
</ul>
</div>
</div>
the snippet I was given:
var dropdown = document.getElementsByClassName('dropdown_btn');
var i;
for (i = 0; i < dropdown.length; i++) {
dropdown[i].addEventListener('click', function() {
this.classList.toggle('active');
var dropdownContent = this.nextElementSibling;
if (dropdownContent.style.display == 'block') {
dropdownContent.style.display = 'none';
} else {
dropdownContent.style.display = 'block';
}
});
}
and the fix I tried to implement:
$(document).ready(function() {
$('.dropdown_btn').on('click', function() {
var state = $('.dropdown_btn').is('.active');
if(state) {
$('.dropdown_btn').removeClass('active').next('.subnav_mob')
.slideUp();
} else {
$('.dropdown_btn').addClass('active').next('.subnav_mob').slideDown();
$.closest('.dropdown_btn').siblings('.dropdown_btn')
.find('.dropdown_mob').slideUp().end();
$.find('.dropdown_btn').not(this).removeClass('active');
}
})
})
Your first problem is that $('dropdown_button') selects every element with that same class, not just the one you clicked on. Operating on it will thus operate on every dropdown at once. You may have noticed that clicking one button causes every dropdown to open, and clicking another button causes them all to close again. This is why.
Your second problem is that $.closest is not a thing. If you press F12 and check out the console, you'll notice an error being thrown from that line, saying that '$.closest' is not a function. It's actually 'undefined', and attempting to invoke it as a function with () causes this error. This prevents any code after this point from being run, though even if you fix this that code still won't work for similar reasons. $.find is not a function, either, for example. closest and find, like next and slideup, are methods on jQuery instances, not on the global jQuery object itself.
This should work. Note that $(this) refers to the clicked element wrapped in a JQuery instance:
$(document).ready(function() {
$('.dropdown_btn').on('click', function() {
var state = $(this).is('active');
if(state) {
$(this).removeClass('active')
.next('.subnav_mob').slideUp();
} else {
$(this).addClass('active')
.next('.subnav_mob').slideDown();
$(this).siblings('.dropdown_btn').removeClass('active')
.next('.subnav_mob').slideUp();
}
})
})
I would recommend stepping through each call in this, compare it with the jQuery documentation, to really make sure you understand it. I'd also might recommend trying to do it without jQuery-- using the native DOM API like the original snippet was doing. Such an exercise might be frustrating, but valuable.
I'm working with three tabs called 'Monday', 'Tuesday' and 'Favorites'. I have a toggle icon which is an empty heart at start 'favorite i'. If I'm in Monday and click on the icon, the empty heart turns to be filled out and its parent is cloned and added to the '#fav' tab. When this happens the clone is saved to local storage. So if people refresh the page, they can still see their preferences.
When the heart is clicked in one of those cloned divs that specific div is removed from '#fav' and is also removed from the array.
Everything works well, except when I refresh the browser and local storage is detected.
So, in this case if I'm in Monday and click on a filled heart it doesn't remove the clone from #fav and still adds a new clone to #fav. Also, if I'm in #fav tab, when clicking in one of the hearts, it should erase the index from the array, but in fact, it erases the full array.
How to overcome this issue? Many thanks.
HTML:
<section id="speakers-programme">
<div class="container">
<div class="tabs_main">
<div class="col-md-5"><a data-target="#mon" class="btn active" data-toggle="tab">Monday</a></div>
<div class="col-md-5"><a data-target="#tue" class="btn active" data-toggle="tab">Tuesday</a></div>
<div class="col-md-2"><a data-target="#fav" class="btn active" data-toggle="tab"><i class="fa fa-heart" aria-hidden="true"></i></a></div>
</div>
<div class="tab-content">
<div class="tab-pane active" id="mon">
<br>
<div class="spaces">
<div class="box-container">
<div class="box not-selected" id="box1">
<span>1</span>
<i class="fa fa-heart-o" aria-hidden="true"></i>
</div>
</div>
<div class="box-container">
<div class="box not-selected" id="box2">
<span>2</span>
<i class="fa fa-heart-o" aria-hidden="true"></i>
</div>
</div>
</div>
</div>
<div class="tab-pane active" id="tue">
<br>
<div class="spaces">
</div>
</div>
<div class="tab-pane active" id="fav">
<br>
<div class="spaces">
</div>
</div>
</div>
</div>
</section>
JS
console.clear();
//localStorage.setItem('sessions', "");
var tempArray = [];
// Clones
$('div.tab-pane').on('click', '.favorite', function(e) {
e.preventDefault();
// Elements we play with... Having significative variable names.
var heartLink = $(this);
var box = heartLink.parent('.box');
var container = box.parent('.box-container');
var favoriteTab = $("#fav .spaces");
// I don't know what is the use for those 3 lines below.
var idFind = box.attr("id");
var idComplete = ('#' + idFind);
console.log(idComplete);
//TOGGLE FONT AWESOME ON CLICK
heartLink.find('i').toggleClass('fa-heart fa-heart-o'); // .selected or not, you need those 2 classes to toggle.
box.toggleClass("selected not-selected"); // Toggle selected and not-selected classes
// Clone div
var boxContent = container.clone(true, true);
// Change the id
var thisID = boxContent.attr("id")+"_cloned";
boxContent.attr("id", thisID);
// Get the html to be saved in localstorage
var get = boxContent.wrap('<p>').parent().html();
get = get.replace(/\r?\n/g, "").replace(/>\s*</g, "><"); // remove line feeds and spaces
console.log(get);
boxContent.unwrap();
// Decide to add or remove
if(box.hasClass("selected")){
console.log("Add to array")
tempArray.push(get);
// Add to favorites tab
favoriteTab.append(boxContent);
}else{
console.log("Remove from array");
var index = tempArray.indexOf(get);
tempArray.splice(index);
// Remove from favorite tab
favoriteTab.find("#"+thisID).remove();
}
// Save array
localStorage.setItem('sessions', tempArray.join(""));
console.log(tempArray);
// save this current toggle state
localStorage.setItem(box.attr("id"), $(this).find("i").attr("class"));
console.log($(this).find("i").attr("class"));
});
// Append item if localstorage is detected
if (localStorage["sessions"]) {
console.log("storage exist");
// Load
$(".box").each(function(){
console.log( $(this).attr("id") );
console.log( localStorage.getItem($(this).attr("id")) );
if(localStorage.getItem($(this).attr("id")) != null){
$(this).find("i").removeClass().addClass( localStorage.getItem($(this).attr("id")) );
}
});
$("#fav .spaces").append(localStorage["sessions"]);
console.log( localStorage["sessions"] );
}
Fiddle: https://codepen.io/Bes7weB/pen/bobjdv?editors=1011
I twisted your code in a way that deserves explanations.
First, you finally don't need to save the HTML of your favorited elements. You just need the heart icon states, which you already do. I added a counter, just to know how many favorited there is in storage.
Now, on page load... If there is more than zero favorites in storage, Apply the icon states by loading their classes from storage. You already had this part right. THEN cycle throught all hearts to target the filled ones and clone them in the favorite tab. I made a "named function" to do this.
On icon click now... Clicking on a cloned element or on an original element are two different situations.
On an original element, you want to toggle its classes and clone it to the favorite tab. So here, just do the togglings and for the favorite tab, just call the previous named function to clone them all!
On a cloned element, you want to remove it from favorites and toggle the original element classes. See the code to get this twist I made! I redefined some variables in this case.
Notice there no more tempArray in use.
;)
var favoriteTab = $("#fav .spaces");
// Named function to load the favorites tab
function loadFav(){
// First, clear old favorites.
favoriteTab.empty();
// Look for filled hearts
var favCount = 0;
$(".tab-content").find("i.fa-heart").each(function(){
// Count them
favCount++;
// Clone its box
var favClone = $(this).closest(".box").clone();
// Change the id
favClone.attr("id", favClone.attr("id")+"_clone");
// Append to favorites
favoriteTab.append(favClone);
});
console.log("favCount: "+favCount);
localStorage.setItem("favAmount", favCount);
}
// Click handler
$('div.tab-pane').on('click', '.favorite', function(e) {
e.preventDefault();
// Elements we play with... Having significative variable names.
var heartLink = $(this);
var box = heartLink.parent('.box');
var thisID = box.attr("id");
var container = box.parent('.box-container');
if(thisID.split("_")[1] == "clone"){
console.log("You clicked a clone!");
// Remove that clone
box.remove();
// Use the original element for the rest of the function.
heartLink = $("#"+thisID.split("_")[0]).find("a.favorite");
box = heartLink.parent('.box');
thisID = box.attr("id");
}
//TOGGLE FONT AWESOME ON CLICK
heartLink.find('i').toggleClass('fa-heart fa-heart-o'); // .selected or not, you need those 2 classes to toggle.
box.toggleClass("selected not-selected"); // Toggle selected and not-selected classes
// Clone div
loadFav();
// Save this current toggle state
localStorage.setItem(box.attr("id"), heartLink.find("i").attr("class"));
console.log(heartLink.find("i").attr("class"));
});
// ON PAGE LOAD
// Append item if localstorage is detected
if (localStorage["favAmount"]>0) {
console.log("storage exist");
// Load heart's element states
$(".box").each(function(){
console.log( $(this).attr("id") );
console.log( localStorage.getItem($(this).attr("id")) );
if(localStorage.getItem($(this).attr("id")) != null){
$(this).find("i").removeClass().addClass( localStorage.getItem($(this).attr("id")) );
}
});
// Load favorites
loadFav();
}else{
console.log("no storage");
}
CodePen v6
I am not able to save active class for a div on page reload, when I click button in first div then its active class is removed and next class is made active. But when the page reloads in second div, how to save active class for second div when page is reloaded . i tried using local storage but i dunno that.
<div class="divs active" id="first">
<h1> first div</h1>
<a class="btn-link" href="javascript:void(0);" id="btn-first">Next - 2</a>
</div>
<div class="divs" id="second">
<h1> second div</h1>
<a class="btn-link" href="javascript:void(0);" id="btn-second"/>Next -3 </a>
</div>
<div class="divs" id="third">
<h1> third div</h1>
<a class="btn-link" href="javascript:void(0);" id="btn-third"/>Next -1</a>
</div>
<script>
$(document).ready(function(){
$('#btn-first').click(function(){
$('.divs').removeClass('active');
var activeID = $('#second').addClass('active');
console.log(activeID);
localStorage.setItem("activeDIV", activeID);
//var reloadactiveDIV = localStorage.getItem("activeDIV");
// var activeID = $('#second');
// localStorage.setItem('activeTab', $activeID );
// var activeTab = localStorage.getItem('activeTab');
// if (activeTab) {
// $('.divs').removeClass('active');
// $('#second').addClass('active');
// }
});
$('#btn-second').click(function(){
$('.divs').removeClass('active');
$('#third').addClass('active');
});
$('#btn-third').click(function(){
$('.divs').removeClass('active');
$('#first').addClass('active');
});
});
</script>
To achieve this you can store the index of the active div in local storage, instead of the entire jQuery object, and then re-set the active class on the element within the index of localStorage when the page is next loaded.
Also note that you can DRY up the logic by using a single event handler for all the buttons. You can find the parent .divs and retrieve the next one, looping back to the first if there is no next sibling. Try this:
$(document).ready(function() {
// set active on click:
$('.btn-link').click(function(e) {
e.preventDefault();
var $parentDiv = $(this).closest('div');
var $nextDiv = $parentDiv.next('div');
var $divs = $('.divs').removeClass('active');
if (!$nextDiv.length)
$nextDiv = $divs.first();
$nextDiv.addClass('active');
localStorage.setItem("activeDiv", $nextDiv.index('.divs'));
});
// set active on load:
var activeIndex = localStorage.getItem("activeDiv");
if (activeIndex)
$('.divs').removeClass('active').eq(activeIndex).addClass('active')
});
Working Example
Note that I couldn't place a working example in a SO Snippet as it has restrictions in place on accessing localStorage.
I have this list-group (bootstrap) and I want to move the "disabled" class between those links,
<div class="list-group">
<a href="#" onclick="form1()" class="list-group-item disabled">
Particular
</a>
Distribuidores
Incidencias
Grandes cantidades
</div>
i.e. if I click on the second link, the "disabled" should move from the first link to the second, so we will have something like:
<div class="list-group">
Particular
Distribuidores
Incidencias
Grandes cantidades
</div>
You could use a method like this:
function setDisabled(index) {
var links = document.querySelectorAll(".list-group-item")
for (var i = 0, link; (link = links[i]) != undefined; i++) {
link.className = "list-group-item" + (i == index ? " disabled" : "");
}
}
This method could be called from the methods you're using to handle the clicks with the index parameter being the zero based index of the element. You could also add an id to each of the links and use that instead to find the link that was clicked.
Basically, it creates an array of all elements with the "list-group-item" class and resets their class attribute to only have that class. For the link that was clicked it also adds the "disabled" class.