Create UL with data from a set of divs - javascript

I have a selection of divs with the exact markup below and I want to create an unordered list above those divs that will provide the ground work for a 'tab' system - all without modifying the below markup.
<div id="category_1">
<h3 class="maintitle">
<a class="toggle">..</a>
Cat 1 Title
</h3>
<div>
...
</div>
</div>
<div id="category_2">
<h3 class="maintitle">
<a class="toggle">..</a>
Cat 2 Title
</h3>
<div>
...
</div>
</div>
<div id="category_3">
<h3 class="maintitle">
<a class="toggle">..</a>
Cat 3 Title
</h3>
<div>
...
</div>
</div>
And I want to create with jQuery or just pure JS if easy enough:
<ul>
<li>Cat 1 Title</li>
<li>Cat 2 Title</li>
<li>Cat 3 Title</li>
</ul>
The rel would be the ID of the div so I know which tabs to show / hide later on.
The value of the LI item would be the text of the second anchor within the H3 of the original code.
Cheers.

Try this:
$(function () {
var $uls = $('<ul/>');
$('[id^=category]').each(function () { // Provide a container that hold the div as context.
var anch = $(this).find('h3 a').eq(1).clone(); //clone your anchor the second one in h3
anch[0].rel = this.id; // set the rel with the id
$('<li/>').append(anch).appendTo($uls); // append to temp ul
});
$('body').append($uls); // Append anywhere you want
});
http://jsfiddle.net/XmarF/
If you don't want to clone your anchor then you can try this too..
$(function () {
var $uls = $('<ul/>');
$('[id^=category]').each(function () {
$('<li/>').append($('<a/>', {
href: '#',
rel: this.id,
text: $(this).find('h3 a').eq(1).text()
})).appendTo($uls);
});
$('body').append($uls);
});

$('body').prepend($("<ul class='menu'>"));
$('div a[href]').each(function () {
var el = $(this).clone().attr('rel', $(this).closest('div').attr('id'))
el = $('<li></li>').append(el);
$('ul.menu').append(el);
});
Demo ---> http://jsfiddle.net/ht3Y7/

You could do something like this:
$('div[id^="category_"]').each(function(){
var id = $(this).attr('id');
var title = $(this).children('h3').find('a').eq(1).text();
var listItem = $("<li><a href='#'></a></li>");
listItem.find('a').attr('rel',id).text(title);
$('ul').append(listItem);
});
Fiddle

You could try using jQuery's .replaceWith() method. It will replace a current HTML with one you desire. So if your divs were in a wrapper with a name you could do something like:
$("#wrapperID > div").each(function(i) {
var li = $("<li />").html($(this).html());
$(this).replaceWith(li);
});
var ul = $("<ul />", { id: 'wrapperID ' }).html($("#wrapperID ").html());
$("#wrapperID ").replaceWith(ul);
|OR| if you're looking to convert to that exact markup, again I assume all divs in some type of wrapper with ID (for simplicity):
$("#wrapperID > div").each(function(i) {
var li = $("<li />"),
a = $("<a />", { href: "#", rel: $(this).prop("id"), text: $(this).find("a").last().text() }).appendTo(li);
$(this).replaceWith(li);
});
var ul = $("<ul />", { id: 'wrapperID ' }).html($("#wrapperID ").html());
$("#wrapperID ").replaceWith(ul);
See Working Example Here

With no jQuery, this will work in IE8 and up.
var divs = document.querySelectorAll("div[id^=category_]");
var ul = divs[0].parentNode.insertBefore(document.createElement("ul"), divs[0]);
for (var i = 0; i < divs.length; i++) {
ul.appendChild(document.createElement("li"))
.appendChild(divs[i].querySelector("a[href='#']").cloneNode(true))
.rel = divs[i].id
}
DEMO: http://jsfiddle.net/ENvNq/1/

You can do it in three lines (and maybe less):
var html='';
$('div[id^="category"]').each(function () {html += '<li>' + $(this).find('a.toggle').next().text() + '</li>';});
$('#category_1').before('<ul>'+html);
jsFiddle example

Related

jQuery selector based on deep children text content

This is an example of HTML I am working with.
<html>
<div class="parent-div">
<ul>
<li class="title">Color</li>
<li>Red</li>
<li class="title">Shape</li>
<li>Squared</li>
</ul>
</div>
</html>
I would like to convert the current HTML in the following list-item
Color: Red
Shape: Squared
And this is what I tried so far:
$("html > div.parent-div > ul > li:contains('Color')")
However it throws an exception:
Uncaught DOMException: Failed to execute 'querySelectorAll' on
'Document': html > div.parent-div > ul > li:contains('Color')'
is not a valid selector.
That's because html is the same as document. Leave the html out of the selector.
$("div.parent-div > ul > li:contains('Color')")
The inner working of the jQuery is that it uses document.querySelectorAll. Since document is the root, you don't need to specify it again inside the selector. If you do it will fail because HTML (document) doesn't contain an element called "HTML".
The following snippet will do what you desire.
$("document").ready(function(){
//select all the list elements with the class title
$("div.parent-div > ul > li.title").each(function(){
//concat the text of the title element and the next sibling into one string.
var text = $(this).text() + ": " + $(this).next().text();
$(this).html(text); //change the title element's html to set string
$(this).next().detach(); //delete the value element from the DOM.
})
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<html>
<div class="parent-div">
<ul>
<li class="title">Color</li>
<li>Red</li>
<li class="title">Shape</li>
<li>Squared</li>
</ul>
</div>
</html>
no need to write html in jQuery selector
$("div.parent-div > ul > li:contains('Color')")
I dont know the reasoning of this, but you can get it with something like this:
var output = {};
var output_index = 0;
var last_title = "";
var allLi = $("#parent-div li");
var $this = null;
for(var i = 0; i < allLi.length; i++){
$this = $(this);
if($this).hasClass(title){
last_title = $this.html();
} else {
output[last_title] = $this.html();
}
})

Combine cloned UL menus

I am cloning UL's from one element to another like so.
$( "#mobMenu li a" ).each(function(index) {
var subID = $(this).attr('id')
if (typeof(subID) !== "undefined") {
subID = "#sub_" + subID + " .subnav-menu"
var subMenu = $(subID).clone();
$(this).parent().append(subMenu);
}
});
Menu I am cloning:
<div id="sub_cat3">
<ul id="sub_cat" class="subnav-menu">
<li>..</li>
</ul>
<ul class="subnav-menu">
<li>..</li>
</ul>
</div>
Into a new mobile menu that looks like this:
<ul id="mobMenu">
<li><a id="cat3"></a>
// cloned menu to go here
</li>
</ul>
So ho can I combine each cloned ul into one UL?
<ul class="subnav-menu">
<li>..</li>
<li>..</li>
</ul>
I think you want something like this (had to contrive the HTML as a suitable example was not provided):
JSFiddle: http://jsfiddle.net/TrueBlueAussie/b10n5mf0/1/
or with your new HTML: http://jsfiddle.net/TrueBlueAussie/b10n5mf0/4/
$("#mobMenu li a").each(function (index) {
var subID = $(this).attr('id')
console.log(subID);
if (subID) {
subID = "#sub_" + subID + " .subnav-menu li"
var $div = $('<ul>').append($(subID).clone());
$(this).closest('li').append($div);
}
});
Notes:
It creates a single UL for each matching set of lists' LIs.
Only the matching LIs are cloned, then inserted under the created UL with append.
if (typeof(subID) !== "undefined") can be replaced with if (subID) as attr returns a string or undefined (and empty strings are treated as undefined by your code).
You can do...
var $subs = $('.subnav-menu'),
$lis = $subs.find('> li').clone();
// Add all the $lis to the first subnav...
$subs.eq(0).append($lis);
// Remove the rest of the subs...
$subs.slice(1).remove();
Here is a small demo: http://jsbin.com/jerapo/2/edit?js,output

Dynamically build menu structure based on page elements [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
i'm having some problems creating a dynamic menu based on the elements of the page. How would one create a menu from this?:
<div class="parent">
<div class="one child" id="first"></div>
</div>
<div class="parent">
<div class="one child" id="second"></div>
</div>
<div class="parent">
<div class="one child" id="third"></div>
</div>
<div class="parent">
<div class="one child" id="fourth"></div>
<div class="one child" id="fifth"></div>
<div class="one child" id="sixth"></div>
<div class="one child" id="seventh"></div>
</div>
<div class="parent">
<div class="one child" id="eight"></div>
</div>
So for this i would like jquery to build a menu structure like so:
<ul class="navigation">
<li></li>
<li></li>
<li></li>
<li>
<ul class="sub-navigation">
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
</li>
<li></li>
</ul>
Here is the fiddle i've been meddling with (my attempt on making it work): http://jsfiddle.net/rt9Pm/
Somewhere along the way i lost my focus point and i'm unable to finish this little doodle.
I had some time, and thought this might still be of use to you:
(function($){
$.fn.createMenu = function (opts){
var s = $.extend({
'menuID' : 'menu',
'navigationID' : 'navigation',
'navigationClass' : 'navigation',
'attachTo' : 'body'
}, opts),
nav = $('<nav />', {
'id' : s.navigationID
}),
menu = $('<ul />', {
'id' : s.menuID
}),
textProp = 'textContent' in document.body ? 'textContent' : 'innerText',
ulWrap = document.createElement('ul'),
liWrap = document.createElement('li'),
aWrap = document.createElement('a'),
liTmp,aTmp,
// defining a function to create the li-wrapped links:
createLinks = function (el, par, prefix) {
// if the 'par' is a jQuery object we'll use that,
// otherwise we assume it's a DOM node and we wrap that with jQuery:
var parent = par instanceof jQuery ? par : $(par);
// cloning created elements rather than re-creating elements:
aTmp = aWrap.cloneNode();
// creating the 'href' to link to the id:
aTmp.href = '#' + el.id;
aTmp[textProp] = el.id;
liTmp = liWrap.cloneNode();
// appending the cloned a element to the li element:
liTmp.appendChild(aTmp);
// adding the appropriate class to the parent 'ul' element,
// and appending the 'li':
parent.addClass(('undefined' === typeof prefix ? '' : prefix) + s.navigationClass).append(liTmp);
};
// appending the 'menu' to the 'nav':
nav.append(menu);
// prepending the nav to the specified element (from the options/defaults):
nav.prependTo(s.attachTo);
// iterating over the elements matched by the selector:
this.each(function(i,e){
// using this twice, so caching:
var $e = $(e);
// if there are no siblings:
if ($e.siblings().length === 0) {
// we create the links:
createLinks(e, menu);
}
// if there are previous siblings we do nothing:
else if ($e.prev().length) {
// do nothing, this is inelegant
// but I couldn't think of a better way
}
else {
// there are siblings (this should only be matched by the first
// sibling of a group.
// clone a new 'li' and 'ul' element:
var li = liWrap.cloneNode(),
ul = ulWrap.cloneNode(),
// find all childNodes of the element's parent:
items = e.parentNode.childNodes;
// append the cloned 'ul' to the cloned 'li':
li.appendChild(ul);
// iterate over the childNodes:
for (var i = 0, len = items.length; i < len; i++) {
// if the node has a nodeType *and* that nodeType is exactly 1
// (therefore the node is an HTMLElement):
if (items[i].nodeType && items[i].nodeType === 1) {
// create links from those elements:
createLinks(items[i], ul, 'sub-');
}
}
// append the created 'li' (above, before the for loop) to the menu:
menu.append(li);
}
});
// I tend to return the created elements, jQuery often, however, returns
// the elements of the original selector (which would be 'return this'):
return nav;
};
})(jQuery);
$('.one').createMenu();
JS Fiddle demo.
References:
JavaScript:
Conditional (assessment ? assessment_true : assessment_false) 'ternary' operator.
document.createElement().
instanceof operator.
Node.appendChild().
Node.cloneNode().
Node.nodeType.
typeof operator.
jQuery:
addClass().
appendChild().
"How to Create a Basic jQuery Plugin."
jQuery.extend().
prependTo().
prev().
siblings().
var $parents = $('.parent'),
$ul = $('<ul>'),
$li = $('<li>'),
$a = $('<a>'),
$nav = $('<nav>'),
$navul = $ul.clone().attr('class', 'navigation');
$nav.append($navul);
$parents.each(function ea(){
var $parent = $(this),
$children = $parent.children('.one.child'),
$anchor = $a.clone(),
$subul,
id;
if ($children.length == 1) {
id = $children.attr('id');
$anchor
.attr('href', '#' + id)
.text($children.attr('id'));
$navul.append($li.clone().append($anchor));
} else if ($children.length > 1) {
$subul = $ul.clone().attr('class', 'sub-navigation');
$children.each(function ea(){
var $child = $(this),
$anchor = $a.clone(),
id = $child.attr('id');
$anchor
.attr('href', '#' + id)
.text($child.attr('id'));
$subul.append($li.clone().append($anchor));
});
$navul.append($subul);
}
});
$parents.filter(':eq(0)').before($nav);
http://jsfiddle.net/sPJPr/1

Append sub-elements to its parent element only

I am trying to convert a bunch of menu dropdowns into multiple elements. I have been able to do this when theres only one dropdown on the page but once I add the others, my script seems to run through each menu multiple times. I am new to Javascript/Jquery but I was wondering if there was a way to make it only input to its parent element?
Here is my current script that works for a single dropdown:
$('.mylinks li').each(function() {
var inputClass = $('.mylinks .link').html().toLowerCase();
$('body').prepend('<select class="'+inputClass+'" onchange="window.location.href=this.options[this.selectedIndex].value"></select>');
$('a').each(function() {
var linkName = $(this).html();
var linkVal = $(this).attr('href');
$('select').append('<option value="'+linkVal+'">'+linkName+'</option>');
});
});
HTML
<div class="mylinks">
<ul>
<li>
Drop 1
Link 1
Link 2
Link 3
</li>
<li>
Drop 2
Link 1
Link 2
Link 3
</li>
</ul>
</div>
I have an example of this error here as well: http://jsfiddle.net/UdTcF/
You can try this code:
$(document).ready(function () {
$('.mylinks li').each(function () {
var inputClass = $('.mylinks a').html().toLowerCase();
var select = $('<select class="' + inputClass + '" onchange="window.location.href=this.options[this.selectedIndex].value"></select>');
$('body').prepend(select);
$(this).find('a').each(function () {
var linkName = $(this).html();
var linkVal = $(this).attr('href');
select.append('<option value="' + linkVal + '">' + linkName + '</option>');
});
});
});
Use a variable select to save the <select> you want to add, and late can add <option> to this variable using select.append().
And use $(this).find('a') instead of $('a') to find <a> in certain <li> but not all <a>.
Here is jsfiddle.
Here:
$('a').each,
you're selecting all a elements. I think that you want to select just only those in the current li. SO, just replace add:
$('a',this).each,
it will select only a elements which are children of this, eg the li element.

jQuery cant access element with its attr href // simple tabs structure

I can't access "a" element with its href. Like this example, i need add class to element which got href="#one"
Here is jsFiddle.
jQuery:
//tabs part is working fine
$('.tabs').hide();
$('.tabs:first').show();
$('ul li a').click(function(){
var target = $(this).attr('href');
$('.tabs').hide();
$(target).fadeIn(500);
$('ul li a').removeClass('selected');
$(this).addClass('selected');
});
//problem starts when i try to reach href
var link1 = '#one';
var link2 = '#two';
var link3 = '#three';
var takE = $('ul li a').each();
var finD = take.attr('href');
finD.addClass('thisisLink1');​
html:
<ul>
<li>Home</li>
<li>Posts</li>
<li>About</li>
</ul>
<div class="tabs" id="one">Home Container</div>
<div class="tabs" id="two">Posts Container</div>
<div class="tabs" id="three">About Container</div>​
I have tried each method but it didn't work. I need to access elements with their attr href and set the object to addClass or animate. This way returns me as a string.
Use attribute selector like so:
$('a[href="#one"]').addClass(...)
Also note that you defined a takE variable and the you wrote take: probably you may want to write
var takE = $('ul li'),
finD = takE.find('a[href="#one"]');
finD.addClass('thisisLink1');
$('ul li a').each(function() {
if(this.href == link1) $(this).addClass('thisisLink1');
if(this.href == link2) $(this).addClass('thisisLink2');
if(this.href == link3) $(this).addClass('thisisLink3');
});
You can also use an object mapping:
var links = {
'#one': 'thisislink1',
'#two': 'thisislink2',
'#three': 'thisislink3',
};
$.each(links, function(key, val) {
$('ul li a[href="' + key + '"]').addClass(val);
});
DEMO

Categories