Active menu item NOT based on URL but based on a variable - javascript

I want to have a Menu with active items on my website. It should be added a class to activate the item. Since the project has cryptic URLs, URL-based solutions are not possible. The text of the respective menu item is shown in the respective page title.
My idea was to compare the pagetitle id="navtopheader" with the text in the menu item. If it is equal, add the menuactive class to the respective menu item.
My HTML looks basically like this:
<div id="navtopheader" class="navtopheader">menu item 1</div>
...
<div class="nav_ebene_2">
<p>menu item 1</p>
</div>
<div class="nav_ebene_2">
<p>menu item 2</p>
</div>
...
I can do it actually in an inefficient way:
var headertext = document.getElementById("navtopheader").innerText
var menutext0 = document.getElementsByClassName("nav_ebene_2")[0].innerText
var navlist = document.getElementsByClassName("nav_ebene_2");
if (headertext == menutext0) {
navlist[0].classList.add("activemenu");
}
var menuitem1 = document.getElementsByClassName("nav_ebene_2")[1].innerText
if (headertext == menuitem1) {
navlist[1].classList.add("activemenu");
}
...
But since the number of menu items varies across the website, i would get an error message if i include too much/too few menu items.
Is there an appropriate solution? I tried the whole day but didn't solve the problem. Thank you!

Iterate over the collection of <p>s that are children of nav_ebene_2. When a match is found, add the class to its parent.
const headerText = document.querySelector('#navtopheader').textContent;
for (const p of document.querySelectorAll('.nav_ebene_2 p')) {
if (p.textContent === headerText) {
p.parentElement.classList.add('activemenu');
}
}

Related

Is There a More Efficient Way to Alter HTML Text with JavaScript

I am working on a building a website that has a drink menu. In this menu, there are 32 different menu options to select from. When the user clicks on a menu option, text above that menu item displays giving more information about the menu item, such as displaying the name, description, and cost of the drink, along with displaying a slideshow of three images related to the drink you selected. To update all of this information, I created a function for each of the drinks (when there were only 6 and I was testing). Although, given that there are 32 options, my method does not seem like a scalable solution to the problem. Is there a better way to go about doing this?
HTML:
<div class="box-container">
<!-- HOT DRINKS -->
<div class="menu-item hot-drink">
<img src="images/menu-1.png" alt="Menu item - Espresso">
<h4>Espresso (Hot)</h4>
<p class="menu-cost">$2.00 - $3.00</p>
Learn More
</div>
<div class="menu-item hot-drink">
<img src="images/menu-3.png" alt="Menu item - Cappuccino">
<h4>Cappuccino (Hot)</h4>
<p class="menu-cost">$3.00 - $4.00</p>
<a href="#" class="button" onclick="changeTextMenu_Two()>Learn More</a>
</div>
/* there are 32 of these div blocks */
</div>
JavaScript:
/* MENU ITEM ONE */
function changeTextMenu_One() {
document.getElementById("item-name").innerHTML = "Coffee Menu Item One";
document.getElementById("item-description").innerHTML = "This is a sample paragraph for Menu Item One";
document.getElementById("item-cost").innerHTML = "$3.99";
document.getElementById("menu-image-one").src="images/menu-slideshow/menu-one-one.png";
document.getElementById("menu-image-two").src="images/menu-slideshow/menu-one-two.png";
document.getElementById("menu-image-three").src="images/menu-slideshow/menu-one-three.png";
currentSlide(1);
}
/* MENU ITEM TWO */
function changeTextMenu_Two() {
document.getElementById("item-name").innerHTML = "Coffee Menu Item Two";
document.getElementById("item-description").innerHTML = "This is a sample paragraph for Menu Item Two";
document.getElementById("item-cost").innerHTML = "$4.99";
document.getElementById("menu-image-one").src="images/menu-slideshow/menu-two-one.png";
document.getElementById("menu-image-two").src="images/menu-slideshow/menu-two-two.png";
document.getElementById("menu-image-three").src="images/menu-slideshow/menu-two-three.png";
currentSlide(1);
}
If you rename images, you could use arrays and one function.
Image "images/menu-slideshow/menu-one-one.png" to "images/menu-slideshow/menu-1-one.png", for example.
const item_names = ["Coffee Menu Item Zero", "Coffee Menu Item One", "Coffee Menu Item Two"];
const item_descs = ["This is a sample paragraph for Menu Item Zero", "This is a sample paragraph for Menu Item One", "This is a sample paragraph for Menu Item Two"];
const item_costs = ["Free!", "$3.99", "$4.99"];
function changeTextMenu(numb) {
document.getElementById("item-name").innerHTML = item_names[numb];
document.getElementById("item-description").innerHTML = item_descs[numb];
document.getElementById("item-cost").innerHTML = item_costs[numb];
document.getElementById("menu-image-one").src="images/menu-slideshow/menu-" + numb + "-one.png";
document.getElementById("menu-image-two").src="images/menu-slideshow/menu-" + numb + "-two.png";
document.getElementById("menu-image-three").src="images/menu-slideshow/menu-" + numb + "-three.png";
currentSlide(1);
}
Learn More
As mentioned in the comments, you can take this a step further by creating MenuItem objects and then building an array of objects which will be easier to maintain as you add and/or remove items.
After that, you can take it a step further by writing code to import data, instantiate those objects, and build the array automatically... but, all of this might be beyond the reasonable scope to answer this question.

How click a link on one page and have a specific filter option chosen on linked page?

I've been searching all over the internet for this one, and either the suggestions don't seem to apply, or I'm not using the right terminology to describe what I'm wanting to do, so nothing comes up.
Here's the long story:
On our Home Page, we have a section called "Industries". In this section, there are a few choices, "Government", "Manufacturing", "Energy", "Health Care", etc. A visitor to our site can click on one of those choices and it will take them to our Product Filter Page. I would like to have it so that if they clicked on "Manufacturing", that the option would already be chosen on the Product Filter Page, so they only see our products that are available for the Manufacturing Industry.
I am not a coder by any means, but I have been able to take code that I find on forums, and slightly modify it to make it work on our site, to achieve other functionality that we've wanted. But I can't seem to find anything that makes any sense to me that would allow me to modify it to work for us in this case.
Here is the code that makes up the drop-down list on the Product Filter Page, that relates to the Industries that could be chosen:
<div class="dv-dropdown">
<div class="caption">All Industries</div>
<div class="list">
<div class="item df-button">All Industries</div>
<div class="item df-button dfc-retail">Retail</div>
<div class="item df-button dfc-construction">Construction</div>
<div class="item df-button dfc-warehousing">Warehousing</div>
<div class="item df-button dfc-manufacturing">Manufacturing</div>
<div class="item df-button dfc-government">Government</div>
<div class="item df-button dfc-energy">Energy</div>
<div class="item df-button dfc-automotive">Automotive</div>
<div class="item df-button dfc-printing">Printing</div>
<div class="item df-button dfc-healthcare">Health Care</div>
</div>
</div>
I'm not sure what exactly I could include for the Javascript that is on the page, as it is from a purchasable plugin - Divi Filter - and I'm pretty sure that this will need custom script to get it to work.
This is my first post, so please let me know if you need anything else from me. I am currently in the process of creating the site, so it's not exactly live. Thus, if there's any reference to URL links, please just make use of a generic site example, and I can replace it as needed.
Thank you all in advance for your help, and I will do my best to respond to any questions you may have, but please keep in mind my inexperience with coding.
EDIT:
Here is a snippet of the Javascript used for filtering the classes:
var activeClasses = [];
jQuery(function() {
jQuery('.dv-dropdown .df-button').on('click', function() {
// get number of dropdown
var dvIndex = jQuery(this).closest(".dv-dropdown").index(".dv-dropdown");
/* remove class */
if (activeClasses[dvIndex] != "") {
jQuery('.dv-dropdown:not(:eq(' + dvIndex + ')) .df-button').each(function() {
jQuery(this).removeClass(activeClasses[dvIndex]);
});
activeClasses[dvIndex] = "";
}
// get button classes
var filterClasses = jQuery(this).attr('class').split(/\s+/);
// remove all classes except dfc-
filterClasses = jQuery.grep(filterClasses, function(element) {
return element.indexOf("dfc-") === 0;
});
// remove all other active classes from button
jQuery.each(activeClasses, function( index, value ) {
if(index !== dvIndex) {
filterClasses = filterClasses.filter(e => e !== activeClasses[index]);
}
});
if (filterClasses[0] != undefined) { // undefined if you click on all, because no class then just remove
activeClasses[dvIndex] = filterClasses[0];
jQuery('.dv-dropdown:not(:eq(' + dvIndex + ')) .df-button').each(function() {
jQuery(this).addClass(activeClasses[dvIndex]);
});
}
// add active button class dv-activebutton
jQuery.each(activeClasses, function( index, value ) {
// remove classes
jQuery(".dv-dropdown:eq(" + index + ") .df-button").removeClass("dv-activebutton");
// add it to active element
if(value !== "" && typeof value !== 'undefined') {
jQuery(".dv-dropdown:eq(" + index + ") .df-button." + value).addClass("dv-activebutton");
}
else {
jQuery(".dv-dropdown:eq(" + index + ") .df-button.dv-all").addClass("dv-activebutton");
Here is a snippet of the Javascript used for the dropdowns
jQuery(function() {
/* toggle open class */
jQuery('.dv-dropdown > .caption').on('click', function() {
jQuery(this).parent().toggleClass('open');
jQuery('.dv-dropdown > .caption').not(this).parent().removeClass('open');
});
/* make item active element and add to caption */
jQuery('.dv-dropdown > .list > .item').on('click', function() {
jQuery(this).siblings().removeClass('selected');
jQuery(this).addClass('selected').parent().parent().removeClass('open').children('.caption').text( jQuery(this).text() );
});
/* close dropdown if Esc is clicked on keyboard */
jQuery(document).on('keyup', function(evt) {
if ( (evt.keyCode || evt.which) === 27 ) {
jQuery('.dv-dropdown').removeClass('open');
}
});
/* on click remove, close dropdown */
jQuery(document).on('click', function(evt) {
if ( jQuery(evt.target).closest(".dv-dropdown > .caption").length === 0 ) {
jQuery('.dv-dropdown').removeClass('open');
The way I would do this is add a query string to the URL that the link takes you to. So if you clicked "Manufacturing" on the first page, it would append something like "?industry=Manufacturing" to the end of the URL for the product filter page. Then, on the product filter page you would write a javascript function get the value of the query param (window.location.search). This query param would be the "value" chosen for the dropdown.
Are you using any javascript frameworks? A snippet of the code you have for the product filter page would be helpful.

Is there any way to know if a certain button has been pressed in a certain location inside a div element in JavaScript?

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.

Ng-repeat and directive expand one list item at a time

I have an ng-repeat code with expandable list items. I would like to expand one item at a time.
The way I am trying to do it is
in the html file
<div data-ng-repeat="parts in data track by $index">
<li id="titleHelp" ng-click='setItem($index);">
and in the directive in the setItem function I want to collapse the previously expanded item and expand the new one. Is it possible to access one repeat element in the directive using index?
thanks!
How do you currently expand the list item?
What I would do is set a variable as soon as an item is clicked and in your repeated list do a
<div data-ng-repeat="parts in data track by $index">
<li id="titleHelp" ng-click='setItem($index);">
<div ng-show="$index = selected_item"> <!-- contents --></div>
In your setItem function:
$scope.setItem = function(i) {
$scope.selected_item = i;
}
Declare a object
$scope.obj={selected:null};
After that add a method in the ng repeat,
$scope.isHide = function (id) {
if (id == $scope.obj.selected)
return $scope.obj.selected = "all";
return $scope.obj.selected = id;
}
If you want to hide div, call this method with the id. Do the same thing for the li if you need.

Scroll to a particular element in a UL list with dynamic ids

I read the question Scroll to a particular element w/ jQuery and in the question, the original HTML code already has ids to the paragraph elements. However, in my case, I generate the element (list element) dynamically and create ID on runtime. How would I scroll to that particular element with or without jQuery?
To give more detail about my problem:
I am creating a phonegap project to get the list of contacts in the iPhone and display a scrolling list (I use the iscroll plugin) in a div. I categorize the first names A-E, F-J, K-O, P-T, U-Z and group them. If the user touches F-J on the side (as you find in iPhone contacts app), the div should scroll to the first contact that belongs to group F-J..
<div id ="tablediv">
<div id="scroller"></div>
</div>
<div id="sorter">
<span id="gr1">A-E</span>
<span id="gr2">F-J</span>
</div>
Javascript:
var g1 = ['a','b','c','d','e']; //contact's first name starting with these chars
var g2 = ['f','g','h','i','j']; //contact's first name starting with these chars
var idg1=null, idg2=null; // first id of the contact which was in g1, g2
//Array is an array of objects
//example: array = [ {'fname':'x','lname':'y','number':'123'},{..},{..}];
function generateTable(array) {
gpDiv = document.getElementById("scroller");
pDiv = document.createElement("ul");
pDiv.id = "thelist";
for(var i=0;i<array.length;i++) {
cDiv = document.createElement("li");
cDiv.id = 'cd'+i; //id created dynamically
cDiv.textContent = array[i].fname+"\u000a"+array[i].lname;
var ch0 = array[i].fname[0].toLowerCase();
if($.inArray(ch0,g1)!=-1 && idg1==null) {
idg1 = cDiv.id;
document.getElementById('gr1').addEventListener('click',function(){goToG1(idg1);},false);
}
if($.inArray(ch0,g2)!=-1 && idg2==null) {
idg2 = cDiv.id;
document.getElementById('gr2').addEventListener('click',function(){goToG2(idg2);},false);
}
pDiv.appendChild(cDiv);
}
gpDiv.appendChild(pDiv);
}
function goToG1(id) {
$('#tablediv').scrollTop($('#'+id).offset().top);
}
function goToG2(id) {
$('#tablediv').scrollTop($('#'+id).offset().top);
}
The above code doesn't work, as I think since the ids are allotted at runtime, I am not able to scroll to that particular element. Please help
Hmmm, All I needed to do was this.
function goToG1(id) {
document.getElementById(id).scrollIntoView();
}
It appears to me that the ids still work even though they are allotted at run time.
You code worked more or less - you were however using code:
$("#tablediv").scrollTop(...)
Instead of
$(document).scrollTop(...)
Other than that it works - see here: http://jsbin.com/umatuj/2/edit

Categories

Resources