HTML Node tree with add buttons and hierarchical numbering - javascript

How to create a JavaScript based tree where you have add buttons, to add extra child elements.
For example, it has to look like this:
I need do be able to add child elements, and I need to make number counting work like that also.
I tried jQuery click() and then added append(), but it didn't come out as I expected. It started randomly adding rows.
Is there a simple way to do this or am I just overthinking this too much? I'm new in coding and any help would be appreciated.
I started like below, but obviously it's not working like that:
$('document').ready(function() {
$('#parent').on('click', function() {
$('#tree').append('<li><input type="text"></li>')
$('#tree li:last').append('<button type="button" id="child">ADD</button>')
$('#tree li:last').append('<ul></ul>')
$('#child').on('click', function() {
$('#tree li ul').append('<li><input type="text"></li>')
$('#tree li ul li:last ').append('<button id="child2" type="button">ADD</button>')
$('#tree li ul li:last').append('<ul></ul>')
$('#child2').on('click', function() {
$('#tree li ul li ul').append('<li><input type="text"></li>')
$('#tree li ul li ul li:last').append('<button id="child3" type="button">ADD</button>')
$('#tree li ul li ul li:last').append('<ul></ul>')
$('#child3').on('click', function() {
$('#tree li ul li ul li ul').append('<li><input type="text"></li>')
});
});
});
});
});
ul {
list-style-type: decimal;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
<ul id="tree"><button type="button" id="parent">ADD</button></ul>
</div>

The code repetition that you have is indeed a problem. You cannot do this indefinitely.
The solution is to create a generic click handler which will capture a click on any button that exists now or in some future.
For the nested numbering, you can use the counters() CSS-function.
As you are using jQuery, I would also suggest to rely more on the methods it provides:
$('document').ready(function(){
$('#tree').on('click', 'button', function() {
$(this).before(
$("<li>").append(
$("<ul>").append(
$("<button>").text("Add")
)
)
);
});
});
ul { counter-reset: item }
li { display: block }
li:before {
content: "node " counters(item, ".") " ";
counter-increment: item
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div><ul id="tree"><button id="parent">Add</button></ul></div>
This shows more "Add" buttons than in your image, as there are more places where content can be inserted. Every click on such a button will result in one more button.

Related

text on anchor changes when hover

Is it possible to change the content of an anchor when hovered? i have this sample fiddle
i want to change the about anchor to some like My bio when hovered. and something else also for the home. the content attribute doesn't seem to work well with this.
HTML:
<ul>
<li>About</li>
<li>Home</li>
</ul>
CSS:
ul { list-style: none; }
ul li a:hover { color: red; content: 'Content'; }
"content property is used with the :before and :after pseudo-elements, to insert generated content." not with normal elements.
Reference: http://www.w3schools.com/cssref/pr_gen_content.asp
You can change it using jQuery:
$('li a').mouseenter(function(){
$(this).data('text', $(this).text());
$(this).text('Content');
}).mouseleave(function(){
$(this).text($(this).data('text'));
});
http://jsfiddle.net/TrueBlueAussie/s6ao29eg/2/
This version simply saves the text to data on the element on mouseenter, and restores it on mouseleave. You can also use hover passing the same two functions.
e.g.
$('li a').hover(function(){
$(this).data('text', $(this).text()).text('Content');
}, function(){
$(this).text($(this).data('text'));
});
JSFiddle: http://jsfiddle.net/TrueBlueAussie/s6ao29eg/5/
I notice several other clever CSS-only solutions have been provided, so the choice depends on how much you can change your content, vs adding code.
If you want different text, use a data attribute:
<li>About</li>
e.g.
$('li a').hover(function(){
$(this).data('text', $(this).text()).text($(this).data('content'));
}, function(){
$(this).text($(this).data('text'));
});
JSFiddle: http://jsfiddle.net/TrueBlueAussie/s6ao29eg/8/
Update to use a transition (fade) as requested:
$('li a').hover(function(){
$(this).stop(true,true).fadeOut(function(){
$(this).data('text', $(this).text()).text($(this).data('content')).fadeIn();
});
}, function(){
$(this).stop(true,true).fadeOut(function(){
$(this).text($(this).data('text')).fadeIn();
});
});
JSFiddle: http://jsfiddle.net/TrueBlueAussie/s6ao29eg/10/
Further update now the rules have changed :)
As the HTML content apparently cannot be modified, use the index position of the LI combined with an array of text items:
var content = ["About me!", "My home!"];
$('li').hover(function(){
var $a = $('a', this);
$a.stop(true,true).fadeOut(function(){
$a.data('text', $a.text()).text(content[$(this).index()]).fadeIn();
});
}, function(){
var $a = $('a', this);
$a.stop(true,true).fadeOut(function(){
$a.text($a.data('text')).fadeIn();
});
});
JSFiddle: http://jsfiddle.net/TrueBlueAussie/s6ao29eg/11/
Credit to #MariaMadalina who used an array before even knowing the HTML could not be modified :)
Really sounds like a job for JS. CSS only solution via pseudo elements:
http://jsfiddle.net/qpdoby91/
.about:before { content: 'About'; }
.home:before { content: 'Home'; }
ul li a:hover:before { content: 'Content'; }
JavaScript Solution: http://jsfiddle.net/bctaxauo/1/
$('ul li a').hover(function() {
$(this).data('prevText', $(this).text()).text('New Content!');
}, function() {
$(this).text($(this).data('prevText');
});
Just hide "hover text" when in normal state and switch display when on hover:
.menu li:hover .unhover {
display: none;
}
.menu li:hover .hover {
display: inline;
}
.menu li .unhover {
display: inline;
}
.menu li .hover {
display: none;
}
<ul class="menu">
<li>
<a href="#">
<span class="unhover">Home</span>
<span class="hover">Visit home</span>
</a>
</li>
</ul>
Made a jquery snippet
$('li#about').hover(function() {
$("a", this ).text( "something" );
}, function() {
$("a", this ).text( "About" );
});
Take a look here http://jsfiddle.net/s6ao29eg/3/
EDIT:
I made some modifications towards a more scalable solution.
var replacementText=["Something 1","Something 2"];
$('li').hover(function() {
var myindex = $(this).index();
var myText=replacementText[myindex];
$("a", this).data('original', $("a",this).text()).text(myText);
}, function() {
var myindex = $(this).index();
$("a",this).text($("a",this).data('original'));
});
http://jsfiddle.net/s6ao29eg/9/
You can, but you have to use the :before and :after pseudo-elements, and a little color trick to hide the original text.
ul li a:hover {
color: transparent;
}
ul li a:hover:before {
content: "Content";
position: absolute;
color: red;
}
Just by the way, why would you want to use a <ul> to nest your <a> elements? You are removing all styles from the list anyway. Most of the time, what you need is just well-styled <a> tags; only nest them in a list if you're structuring the data as a list, which means you likely want to have something like bullet points preceding each li.
Simple Css only solution
HTML
<ul>
<li> <span class="visible">About</span> <span class="hover"> My Bio</span> </li>
</ul>
Css
ul { list-style: none; }
ul li a span.hover{
display:none;}
ul li a:hover span.hover{
display:block;
}
ul li a:hover span.visible{
display:none;
}
You can also do it using jQuery.
Add an id to your li as:
<li>About
and add this jQuery code
$(document).ready(function(){
$('#about').hover(function(){
$(this).text('');
$(this).text('My Bio');
});
$('#about').mouseout(function(){
$(this).text('');
$(this).text('about');
});
});
Fiddle link is:http://jsfiddle.net/sonam185/w5fh140q/
or also do like this if you have multiple li's
http://jsfiddle.net/sonam185/gayph16x/

Jquery can't use 3 selectors

I'm writing a small script to make a mobile menu.
However I can't get my selectors to work together.
When I have $('#nav_button, .nav li, .nav li li') only #nav_button and .nav li works, however when I remove .nav li and leave $('#nav_button, .nav li li') this sub menu begins to work as well.
I have also tried using $('#nav_button, .nav li, .sub_menu li li') with the same results.
Does anyone have an idea why?
jquery:
var mobileMenu = function () {
var currentPosition = 'closed'
$('#nav_button, .nav li, .nav li li').click(function() {
if (currentPosition == 'closed') {
$('.nav').addClass('open');
currentPosition = 'open';
}
else {
$('.nav').removeClass('open');
currentPosition = 'closed';
}
});
};
html:
<div id="head">
<div class="container">
<div class="cover"></div>
<a href="#"><h1 class="logo pull-left">C<span class="logo_space">AV</span>O</h1>
</a> <!-- end logo !-->
<div id="nav_button"></div>
<ul class="nav pull-right">
<li>Menu
<ul class="sub_menu">
<li>Starters</li>
<li>Breakfast and Brunch</li>
<li>Salads</li>
<li>Sandwiches and Wraps</li>
<li>Pasta</li>
<li>Mains</li>
<li>Pizza</li>
</ul>
</li>
<li>About Us</li>
<li>Contact</li>
</ul>
</div><!-- end container !-->
</div> <!-- end header !-->
Firstly, two of your selectors match the same elements
$('#nav_button, .nav li, .nav li li')
.nav li matches any LI inside .nav, including nested LI's
.nav li li matches any LI's inside .nav that are inside another LI, i.e. nested LI's
In other words, LI elements inside LI elements, inside .nav are matched twice, but it shouldn't matter as jQuery removes duplicates, but it's uneccessary.
The real issue is that the event propagates, when you click a nested LI the event handler is called for the nested LI and the parent LI, so the click handler execute twice, and the class is first added, then removed (or vice versa) so there is no visible change.
Here's a simplified example
FIDDLE
Just doing
$('#nav_button, .nav li')
should be enough, but you have to add event.stopPropagation() to make sure the event doesn't propagate to the next parent LI when a LI is called, here's an example
FIDDLE
$('#nav_button, .nav li').on('click', function(e) {
e.stopPropagation();
// do stuff
});
As #adeneo said in nested li function will call twice unnecessarily. I think the other way to achieve this is divide click grabber in two selectors like below:
$('.nav').click(function() {
if (currentPosition == 'closed') {
alert('open');
$('.nav').addClass('open');
currentPosition = 'open';
}
else {
alert('close');
$(this).removeClass('open');
currentPosition = 'closed';
}
});
$('.nav > li > li').click(function() {
if (currentPosition == 'closed') {
alert('open');
$(this).addClass('open');
currentPosition = 'open';
}
else {
alert('close');
$('.nav').removeClass('open');
currentPosition = 'closed';
}
});
I wrote a fiddle to do what you expect. Please check and comment if that helpful.
http://jsfiddle.net/QMaster/y7d6osoq/

JQuery .mouseover and .mouseout change font color

I am newbie to JQuery and I try to make some basic tricks with it. So basicly, I have simple navigation made of unordered list, and I want to change font color on currently mouseover-ed list item with JQuery, but I have problem because my JQuery script is changing font color of all list items, and I want to change font color of ONLY currently mouseover-ed list item, not all. I tried to get currently mouseover-ed list item, but I don't know how to implement it so that my JQuery change only that list item. Here are pictures:
What I currently have: http://i.imgur.com/8vWcOci.jpg
What I want: http://i.imgur.com/4yD0bIc.jpg
Here is my JQuery code:
$(document).ready(
function(){
$('.nav1 ul li').mouseover(
function () {
var index = $( ".nav1 ul li" ).index(this);
$('.nav1 ul li a').css({"color":"white"});
}
);
$('.nav1 ul li').mouseout(
function () {
var index = $( ".nav1 ul li" ).index(this);
$('.nav1 ul li a').css({"color":"#6291d8"});
}
);
}
);
Here is my HTML:
<nav class="nav1">
<ul>
<li>HOME</li>
<li>SERVICES</li>
<li>THERAPIES</li>
<li>GALLERY</li>
<li>BOOKING</li>
<li>CONTACT</li>
<li>ABOUT ME</li>
</ul>
</nav>
Instead of:
$('.nav1 ul li a').css({"color":"white"});
and:
$('.nav1 ul li a').css({"color":"#6291d8"});
use:
$(this).css({"color":"white"});
$(this).css({"color":"#6291d8"});
if you wan to apply css on achor tag:
$(this).find("a").css({"color":"white"});
$(this).find("a").css({"color":"#6291d8"});
By using $('.nav1 ul li a') you are changing all anchor tags css but but by using $(this) will change the current clicked element css.
Why JQuery?
use a:hover in css it is pretty cleaner.
Like:
.nav1 ul li a {
color: #6291d8;
}
.nav1 ul li a:hover{
color:white;
}
For all other links you can again use a and a:hover also a:active will give you additional functionality.
this is a special word in JavaScript that refers to the element that triggers an event. In jQuery you can use $(this). So you can replaceyour code with:
$(document).ready(function () {
$('.nav1 ul li a').hover(function () {
$(this).css("color", "white");
}, function () {
$(this).css("color", "#6291d8");
});
});
jsFiddle example
Notice that I also changed the selector to '.nav1 ul li a'. The anchors have their own default styling, so to override that you should target them, and not the parent list item. I also replaced your mouseover and mouseout with the hover method as it saves a few characters. Finally, I used the more basic single property version of .css() which also saves a few characters.
There is no need for JS here. You can use the CSS :hover psuedo class:
.nav1 ul li a {
color: #6291d8;
}
.nav1 ul li a:hover {
color: #FFF;
}
Example fiddle

add two li elements into the end of the ul

here is the jsfiddle that I tried to do this: http://jsfiddle.net/fxMFh/
I want to add two li's into the end of the submenu with jquery, but this seems that doesnt navigate to the ul it needs to:
$(document).ready(function() {
$(".navigation_container nav > ul > li > ul").append('<li>test</li>');
});
this must be the problem:
$(".navigation_container nav > ul > li > ul")
I must be doing something very noobish here..
Try
$(document).ready(function() {
$(".navigation_container nav > ul > li > div.sub-menu > ul").append('<li>test</li>');
});
Demo: Fiddle
But probably I will shorten the selector to
$(document).ready(function() {
$(".navigation_container nav div.sub-menu > ul").append('<li>test</li>');
});
Demo: Fiddle
Three problems:
The fiddle doesn't include jQuery.
The selector is missing a div wrapper. It should be:
$(".navigation_container nav > ul > li > div > ul")
.appendTo() should be .append()
http://jsfiddle.net/ryanbrill/fxMFh/5/

jquery: don't run script, if it contains .active

I have a script that animates a menu. I don't want it to if the menu contains an object with an active class (.active). I can't figure it out. I have tried several things, but I guess I'm thinking all wrong. Can you help me?
This is the script:
$('#navigation .toplevel, #navigation > ul > li').each(function(idx) {
$(this).delay( idx * 600 ).fadeIn( 600 );
});
This is the markup:
<div id="navigation">
Menu
<ul class="undermenu">
<li>1.0 Menuitem
<ul>
<li>1.1 Menuitem</li>
<li>1.2 Menuitem</li>
</ul>
</li>
<li>2.0 Menuitem
<ul>
<li>2.1 Menuitem</li>
<li>2.2 Menuitem</li>
</ul> </li>
</ul>
</div>
If an UL does contain an active-class, I want it to be shown per default and the LI (the parent) to get an .active-class.
Does it make any sense?
*EDIT:*
The script shall not run if the main UL contains a child (or a childs child) with .active-class. I guess it's a IF/THEN matter? But I don't know how to write it.
And...
If "UL LI UL LI A" is active the "UL LI" (parents, parents, parent :D) should be given .active class. How do I do this?
Thank you in advance... :)
First, to assign the .active class to parent UL elements. You can simply change the selector below to iterate over your UL elements and add the .active class to their parent LI elements:
$('#navigation > ul > li .active').each(function(){
$(this).parent().addClass('active');
});
This will ensure that none of your .active tags are animated:
$('#navigation .toplevel, #navigation > ul > li').not('.active').each(function(idx) {
$(this).delay( idx * 600 ).fadeIn( 600 );
});
Add :not(.active) to your selector.
You can try it with the :not() selector of jQuery.
http://api.jquery.com/not-selector/
e.g. selecting li's not containing class active:
$('#navigation ul li:not(.active)').each...
Edit:
you can add an if clause like this:
if($('#navigation ul .active').size() != 0)
{
$('#navigation .toplevel, #navigation > ul > li').each(function(idx)
{
$(this).delay( idx * 600 ).fadeIn( 600 );
});
}
2.
$('ul li').has('ul li a.active').addClass('active');
something like this should work.
check out: http://api.jquery.com/size/, http://api.jquery.com/addClass/, http://api.jquery.com/has/
I believe this is what you want.
$('#navigation .toplevel, #navigation > ul > li').each(function(idx) {
$this = $(this);
if( $this.find('li.active').length === 0 ) {
$this.delay( idx * 600 ).fadeIn( 600 );
}
});

Categories

Resources