I have current list look like:
$('.group1').wrapAll('<ul></ul>');
$('.group2').wrapAll('<ul></ul>');
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<ul>
<li><a href="#">Menu 1</a>
</li>
<li class='group1'><a href="#">_Submenu a</a>
</li>
<li class='group1'><a href="#">_Submenu b</a>
</li>
<li class='group1'><a href="#">_Submenu c</a>
</li>
<li><a href="#">Menu 2</a>
</li>
<li><a href="#">Menu 3</a>
</li>
<li class='group2'><a href="#">_Submenu x</a>
</li>
<li class='group2'><a href="#">_Submenu y</a>
</li>
<li><a href="#">Menu 4</a>
</li>
</ul>
Try this way
Use .wrap()
Description: Wrap an HTML structure around each element in the set of matched elements.
Use .wrapAll()
Description: Wrap an HTML structure around all elements in the set of matched elements.
You can achieve the effect you're looking for by using the following logic.
.find('ul:empty').remove()
).In the example below I have favoured Native DOM API methods instead of their jQuery counterparts in a few instances because:
$(this).append('<ul></ul>')
returns $(this)
instead of the newly created list. The work around is to add another line of code, or just use the DOM API this.appendChild($('<ul>')[0])
which does return the newly created list. And...var prev;
$('.menu li').each(function(){
if(/^_/.test(this.textContent) && prev) {
prev.appendChild(this);
} else {
prev = this.appendChild($('<ul>')[0]);
}
}).find('ul:empty').remove();
<script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
<ul class="menu">
<li><a href="#">Menu 1</a></li>
<li><a href="#">_Submenu a</a></li>
<li><a href="#">_Submenu b</a></li>
<li><a href="#">_Submenu c</a></li>
<li><a href="#">Menu 2</a></li>
<li><a href="#">Menu 3</a></li>
<li><a href="#">_Submenu x</a></li>
<li><a href="#">_Submenu y</a></li>
<li><a href="#">Menu 4</a></li>
</ul>
The example above results in the following HTML structure:
<ul class="menu">
<li><a href="#">Menu 1</a>
<ul>
<li><a href="#">_Submenu a</a></li>
<li><a href="#">_Submenu b</a></li>
<li><a href="#">_Submenu c</a></li>
</ul>
</li>
<li><a href="#">Menu 2</a></li>
<li><a href="#">Menu 3</a>
<ul>
<li><a href="#">_Submenu x</a></li>
<li><a href="#">_Submenu y</a></li>
</ul>
</li>
<li><a href="#">Menu 4</a></li>
</ul>
// Create custom selectors
$.extend($.expr[':'], {
startsWith: function(e, i, m) {
return $(e).text().trim().indexOf(m[3]) === 0;
}
});
$("li:not(:startsWith(_))").each(function(){ // LI that are not _Sub
if($(this).next("li:startsWith(_)").length) // If my next() is _Sub, start grouping:
$("<ul/>", {
html: $(this).nextUntil("li:not(:startsWith(_))"),
appendTo: this
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li><a href="#">Menu 1</a></li>
<li><a href="#">_Submenu a</a></li>
<li><a href="#">_Submenu b</a></li>
<li><a href="#">_Submenu c</a></li>
<li><a href="#">Menu 2</a></li>
<li><a href="#">Menu 3</a></li>
<li><a href="#">_Submenu x</a></li>
<li><a href="#">_Submenu y</a></li>
<li><a href="#">Menu 4</a></li>
</ul>
Here's the HTML result:
<ul>
<li>
<a href="#">Menu 1</a>
<ul>
<li><a href="#">_Submenu a</a></li>
<li><a href="#">_Submenu b</a></li>
<li><a href="#">_Submenu c</a></li>
</ul>
</li>
<li>
<a href="#">Menu 2</a>
</li>
<li>
<a href="#">Menu 3</a>
<ul>
<li><a href="#">_Submenu x</a></li>
<li><a href="#">_Submenu y</a></li>
</ul>
</li>
<li>
<a href="#">Menu 4</a>
</li>
</ul>