Jquery expand and collapse functionality - javascript

I'm new to Jquery/javascript and I have myself a bunch of levels of links that I need to organize in to lists that are expandable and collapsible via a +/- button.
An example of the information I am working with is:
Category1 (Level 1)
- Subcategory 1 (Level 2)
- Subcategory 2
- Subcategory 3
Category2 (Level 1)
- Subcategory 1 (Level 2)
- Subcategory 2
- Subcategory 3
Category3 (Level 1)
- Subcategory 1 (Level 2)
----Subcategory 1 (Level 3)
- Subcategory 2
- Subcategory 3
Code wise, it looks like this:
<div class="navCol">
<h4>Pet Club</h4>
<ul>
<li>Pet Home</li>
<li>Arts</li>
<li>ns</li>
<li>Pet Prescrions</li>
</ul>
</div>
<div class="navCol">
<h4>Fresh Ideas</h4>
<ul>
<li>Know Yur Food</li>
<li>Depaments</li>
<li>Free</li>
<li>HoBQ</li>
<li>rt</li>
<li>Kidsb</li>
<li>Tr</li>
</ul>
</div>
<div class="navCol">
<h4>vings</h4>
<ul>
<li>w</li>
<li>Bb</li>
<li>asdf</li>
<li>On </li>
<li>C</li>
<li>Em</li>
<li>P</li>
<li>W</li>
<li>Pet</li>
<li>Fuel</li>
<li>School</li>
<li>Weekly</li>
</ul>
</div>
I want to be able to click the category +- and it will show/hide all the links underneath it. Same with subcategory1 in category3 where I am dealing with the third level. How would I be able to implement all the way down to level 3?
Should I precede all my links with L1, L2, L3 tags? I have looked at some questions that deal with the +/- sign and implementation but I do not understand a lot of it.
Also, how would I go about implementing a button that shows all or expands all on toggle? That is, it would expand to the deepest levels and collapse back to show only the level 1 categories.
If you any place where I can start to learn this on my own, that would be greatly appreciated as well. This is my first project and I am confused as to where to start.

You'll want to start by thinking about your HTML structure. You'll need some kind of nested elements to express the list. I would recommend using nested <ul> elements because it semantically represents your data structure.
Don't worry about how many levels there are; if you do it right, the same code will work for a collapsible element at any level.
You'll really have three tasks: knowing when the tree element is clicked on, finding its children, and toggling their visibility.
You can use jQuery's .click() handler to determine when the element is clicked on. Be careful, though: if you have, for example, nested <li> elements, and you use $('li').click as your event, you'll catch multiple clicks for sub-elements (as they will also trigger their parent's click event). So you'll have to be a little clever with your selector.
Once you're able to detect the click, then you can find any sub-items by using jQuery's .children() function.
Finally, it's a simple matter of toggling the visibility of child elements, which you can do easily with jQuery's .toggle() function.
Lastly, I agree with the sentiment of Josh's comment: why re-invent the wheel? If you're doing it to learn, that's great, and you can use the approach I outlined in this answer. If you just need it done, you should look into using an existing jQuery extension, like Josh's suggestion of Accordion or jQuery Treeview.

While I'd usually advise getting to grips fully with javascript before going head on with jQuery, the latter provides a much easier solution here.
Take a look at .toggle()
Edit: Josh's suggesting is a fine one, but it might be worth getting to grips with building simpler versions beforehand.

Here is a very simple example http://jsfiddle.net/xNh6R/4/
Javascript:
$('.level1').click(function(){
if($(this).next('div').is(':visible')){
$(this).next('div').hide("blind");
} else {
$(this).next('div').show("blind");
}
});
$('.level2').click(function(){
if($(this).next('div').is(':visible') && $(this).next('div').hasClass("level3")){
$(this).next('div').hide("blind");
} else if($(this).next('div').hasClass("level3")) {
$(this).next('div').show("blind");
}
});​

Related

Not able to open sub menus in html

I am working on a HTML website. In Website menus are working properly on desktop screen. But In mobile version Parent menus are opening properly as a dropdown. but when I trying to open sub menus it is not opening. If I click on icon , it is redirecting to a page which is linked to parent menu.
I just want to open sub menu dropdown when I click on a icon. But Parent menu link should be there.
I am very new to javascript. Please help me to solve my problem.
Here is my html code
<nav class="navigation">
<ul>
<li> HOME
</li>
<li> <span>WHO WE ARE </span>
<i class="ion-ios-plus-empty visible-xs"></i>
<ul class="sub-nav">
<li>
Vision
</li>
</ul>
</li>
</ul>
</nav>
and hrere is my js
$('.sub-menu >a').on('click', function() {
if ($(window).width() <= 767) {
$('.sub-menu').removeClass('on');
$('.sub-menu> ul').slideUp('normal');
if ($(this).next().next('ul').is(':hidden') == true) {
$(this).parent('li').addClass('on');
$(this).next().next('ul').slideDown('normal');
}
}
});
please help
Your code is very messy, so first I'll answer the question generally: If you want an event to occur when clicking a link without the link actually opening, you must stop the event from firing. There are 3 ways to do that (I included a link in the bottom of my answer regarding which does what), here I chose e.preventDefault():
document.getElementById("myspeciallink").addEventListener("click", function(e) {
alert("A different action!");
e.preventDefault(); //return false / stopPropagation could've also worked here
});
I'm a link!
Regarding your code:
You're trying to bind an event to sub-menu, which doesn't exist in your code.
The sub-menu > a selector only applies to direct children, so for your selector and the following example code only example B would apply to the selector. Perhaps sub-menu a would be better suited here:
$(".sub-menu > a").click(() => alert("Clicked"))
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="sub-menu">
<li>
Example A
</li>
</ul>
<br/>
<ul class="sub-menu">
Example B (Which is what you did but not what you want)
</ul>
Animations based on screen size (a.k.a Responsive Web Design) shouldn't be done like this unless you don't have a choice, and you do. It is preferred you use CSS to achieve what you're trying to accomplish with transistions. I recommend reading more on this subject.
I highly recommend learning CSS, JS and HTML better in order to have a better understanding of what's going on and of good & bad practices.
See also:
What's the difference between event.stopPropagation and event.preventDefault?
Couple of things here.
First of all you apply jQuery code for element $('.sub-menu >a') which means that it will applay to all a elements which are direct children of .sub-menu element.
But you don't have element wih class .sub-menu. You should add it to direct parent of an a element to which it should be applied.
Secondly, if you don't want the a tag to redirect you, then you shiuld add event.preventDeault() where event is an event variable which you can get in .on() function like this $('.sub-menu >a').on('click', function(event) {...
Lastly, this code
$('.sub-menu').removeClass('on');
$('.sub-menu> ul').slideUp('normal');
if ($(this).next().next('ul').is(':hidden') == true) {
$(this).parent('li').addClass('on');
$(this).next().next('ul').slideDown('normal');
}
works that way that firstly it hides all dropdowns and then opens teh one you clicked. If it is desired behavior, then ignore this. But I don't think it is.
Why? Because right now when you click on visible dropdown a tag (the one that opens it) you would expect the dropdown to hide. And in your case it will hide and show again. But if you want it to work that way, then no problem. The code is correct.

How to observe multiple states in a handlebar template from an ember controller or component

I'm new to ember and am struggeling with the typical "how would one do that"-Problem. What I've got is fairly simple and I know how to do it, but my way is so complicated that I do not think it's correct.
The case:
<ul>
<li>{{link-to top-level}}</li>
<li>{{link-to another-top-level</li>
<ul class="submenu">
<li>{{link-to submenu</li>
</ul>
</ul>
What should happen is:
When a route is clicked, the corresponding list element should become active.
When a submenu is clicked the corresponding upper ul-element should get the class open
It's a fairly simple case with jQuery, but I understand that this is not scalable and abstracted and stuff.
Therefore I started with this approach:
Create a controller / template construct for the entire navigation to handle it's state (there are some other things I need to check as well, so it came in handy).
since ember adds the active class to the anchor tag I created a component to observe that:
Like:
export default Ember.Component.extend({
tagName: 'li',
classNameBindings: ['active'],
active: function() {
return this.get('childViews').anyBy('active');
}.property('childViews.#each.active')
});
Replacing the li elements with {{linked-list}} does indeed work.
But what next? Do I need to add another component to watch the component to watch the build in behaviour of active links? Do I have to write dedicated MVC-Classes for all the DOM Elements?
There has to be a simpler way, I think. I already created a whole lotta files for such a simple behaviour that I'm thinking I'm totally on the wrong track.
My gut feeling is: That is view logic and the view should just observe a few states in the template and that's it.
What's the leanest approach to the problem?
I don't know if I understand your question right, but why you want to add the class open to the corresponding upper element? It automatically get active assigned. And with correct CSS it should work as expected.
I have created a small example demonstrating what I mean. Please have a look and let me know, if that's the solution for you or what's your problem with this solution.
http://emberjs.jsbin.com/wifusosadega/7/edit
EDIT
Here is a Bootstrap flavored version: http://emberjs.jsbin.com/wifusosadega/9/edit .

Navigate to specific anochor tag via up and down arrow press

I am currently using anchor tags and have implemented smooth scrolling on 5 links. This currently works perfectly. However, I would now like to add the ability to use the arrow keys to navigate through these same anchor tags.
I can only fumble through javascript and jquery, so I'm pretty confused when it comes to that stuff.
<ul>
<li class="scrolldot"><span>1</span></li>
<li class="scrolldot"><span>2</span></li>
<li class="scrolldot"><span>3</span></li>
<li class="scrolldot"><span>4</span></li>
<li class="scrolldot"><span>5</span></li>
<li class="scrolldot"><span>6</span></li>
</ul>
So basically, I want a user to hit the down arrow and them to be taken to the next section, depending on where they are on the page. If they are on section 2, take them to three. If they hit up again, they would be taken back to two and so forth. Make sense?
Checkout Mousetrap. It's a nifty little library that makes binding keys pretty easy. There are a few good examples on the site as well.
Perhaps something like this would suffice:
Mousetrap.bind('up', function() {
your_up_function();
});
Mousetrap.bind('down', function() {
your_down_function();
});

jQuery to add a class to menu items?

I have the following menu items:
<ul>
<li class="static">
<a class="static menu-item" href="/mySites/AboutUs">About Us</a>
</li>
<li class="static">
<a class="static-menu-item" href="/mySite/Practices">Practices</a>
</li>
<li class="static">
<a class="static-meunu-item" href="/mySite/Sectors">Sectors</a>
</li>
</ul>
I cannot add specific background images to the menu items as they all have the same class. In order to achieve this it will be ideal if specific classes could be added for example:
<ul>
<li class="static">
<a class="static menu-item about-us" href="/mySites/AboutUs">About Us</a>
</li>
<li class="static">
<a class="static-menu-item practices" href="/mySite/Practices">Practices</a>
</li>
<li class="static">
<a class="static-meunu-item sectors" href="/mySite/Sectors">Sectors</a>
</li>
</ul>
In the above example highlighted in red are the classes that have been added. This will then allow me to add the specific background images to each menu item.
How can I achieve this using the .addClass() method in jQuery?
In this case, adding specific classes is overkill. I would simply use an href selector since that seems to be what you're basing your classes off of:
// *= indicates contains
$('a[href*="AboutUs"]').addClass("about-us");
$('a[href*="Practices"]').addClass("practices");
$('a[href*="Sectors"]').addClass("sectors");
If there are other anchors on the page with the same href's that you don't want to include, simply use the parent > child selector:
// *= indicates contains
$('.static > a[href*="AboutUs"]').addClass("about-us");
$('.static > a[href*="Practices"]').addClass("practices");
$('.static > a[href*="Sectors"]').addClass("sectors");
Here is a working jsFiddle to illustrate the solution.
You should be able to add a class by passing a callback function to the addClass function -
$("a").addClass(function() {
var newclassname = $(this).text().toLowerCase();
return newclassname.replace(/ /g,'-');
})
Demo - http://jsfiddle.net/aZEZN/
I personally find it overkill to do such things with Javascript.
Makes more sense doing it server side as it's been mentioned above.
Or...
CSS! You could use CSS3 pseudo classes to do this.
I have created an example here
To make this work in older browsers such as IE7, make sure you add Selectivizr to your head section
define your class like this;
.highlight { background:yellow; }
.highlight2 { background:yellow; }
.highlight3 { background:yellow; }
then add your class like this;
$(".about-us").addClass("highlight");
$(".practices").addClass("highlight2");
$(".sector").addClass("highlight3");
It's not necessarily overkill specifying individual classes for each list item. A class should be used (as opposed to an ID) when there is even a possibility to group multiple elements together (for scripting, styling). In your case, as this is a navigation menu, you might have multiple menus (such as a left-side pane side bar, a footer menu aswell). From my experience, I would specify each menu button as its own class in order to handle the group of links together (ie all links that directs the user to the About us page).
The most obvious benefit of this is that you will be able to handle the active links as a group vs. individually; just as you would have a hover color on these links, you might as well want the link to be bold when the user is on that specific page. Grouping the links together and handling this as a class would allow you to bold all the links if you have multiple menus.
To add to this, erimerturk had a good idea of specifying highlights or 'themes' within your styles. This is a good practice (although not for your case) when you want to specify a certain color scheme for your site. Specify your color, background color and highlights as classes and tag these classes to the required elements within your html directly. This is a huge boost for maintainability and scalability, so although I wouldn't say as far as saying it's good practice, it's certainly not bad practice as far as I'm concerned.
Overkill or not, sometimes we may just want to test out ideas quickly on the browser, or you might be working on nodejs. I have edited the link classes to static-menu-item.
var links = $("body").find("a.static-menu-item");
$.each(links, function(value) {
var items = $(this).attr('href').split("/");
$(this).addClass(items[items.length-1].toLowerCase() );
});
Working example

Need help creating dynamic Javascript Arrays

Part One:
I'm trying to figure out how to use the DOM and Javascript to create an array containing the links in multiple lists.
The problem is I need each UL to have a unique array containing the links; the only unique ID I am able
to use in this case is the name value in the link tags. I will not be able to add anything else to the markup.
The javascript reference will need to be contained in a single script, with one reference to the script at the
bottom of the page.
Part Two:
What I ultimately need to do, is to hide each of the lists, and replace them with just the first two links,
along with a "view all" link below the two links that, when clicked, adds the other two links to the list.
Again, I can't add any markup, divs, etc. etc.; it must be completely based on the information below, the DOM and
javascript.
Thanks for any help y'all can provide!
<ul>
<li>
Section One, Article One
</li>
<li>
Section One, Article Two
</li>
<li>
Section One, Article Three
</li>
<li>
Section One, Article Four
</li>
</ul>
<ul>
<li>
Section Two, Article One
</li>
<li>
Section Two, Article Two
</li>
<li>
Section Two, Article Three
</li>
<li>
Section Two, Article Four
</li>
</ul>
I am using jQuery for my solutions ;)
Part One:
var list = new Array();
$.each($('ul'), function(index, value) {
list.push(new Array());
$.each($(value).find('li a'), function(index2, value2){
list[list.length - 1].push(value2.href);
});
});
Part Two:
I really don't understand the requirements, but have a look at jQuery it really makes those takes easy.

Categories

Resources