Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Find duplicate LI class names and group them in a UL using jQuery

I have a list of items,

<ul class="testList">
  <li class="a">Should be grouped in a UL with id name = a</li>
  <li class="b">2</li>
  <li class="c">Should be grouped in a UL with id name = c</li>
  <li class="c">Should be grouped in a UL with id name = c</li>
  <li class="d">2</li>
  <li class="e">3</li>
  <li class="a">Should be grouped in a UL with id name = a</li>
</ul>

I am trying to locate duplicate LI classes and then group them into ULs.

Here is my jQuery code

$('ul.testList li').each(function(index, el) {
    var li = $(this);
    var cls = li.attr('class');
    var match = $('li[class="' + cls + '"]');

    if (match.length > 0) {
        var ul = $('<ul id="'+ cls +'"></ul>');
        match.appendTo(ul);

        $(this).add(match).addClass('matched');
    }
});

See the jsFiddle: https://jsfiddle.net/b4vFn/41/

like image 908
Greg Avatar asked Oct 09 '15 17:10

Greg


People also ask

How to get all Li elements in ul using JavaScript?

How to get all LI elements in UL using JavaScript. In JavaScript, you can use the .getElementsByTagName () method to get all the <li> elements in <ul>. In-addition, you can use the .querySelectorAll () method also to get all the <li>. I have shared few simple examples here explaining how you can use the method to extract all the LI elements.

How to limit the result to a particular <ul> element only?

You can limit the result to a single or particular <ul> element only, by providing the class name of the <ul> as selector to querySelectorAll () method. In this example, let us assume I have a <ul> with class name navi.

How to select all Li children of an ul element?

Your li elements need to have unique IDs. Once they do, you can select all li children of the ul with the ">" operator: var ul_elem = $("#id_of_ul"); $("> li", ul_elem).click(...); OR $("#id_of_ul > li").click(...);

How to retrieve multiple <Li>elements with the same ID?

3 ID's have to be unique in a document, so having multiple <li>elements with the id "category"is invalid. Change that to a class or a data attribute or something else. Or just assign a class to the parent <ul>so you can easily retrieve all li's inside it.


4 Answers

This appends a new UL for each and removes the original. Also assumes that there will only ever be one class on these li. Also assumes there can be no other similar ID's in page

$('ul.testList li').each(function(index, el) {

    var li = $(this),
        cls = li.attr('class'),
        $parent=$('#'+cls);
    // if new parent doesn't exist create it
    if(!$parent.length){
        $parent = $('<ul id="'+cls+'">').appendTo('body');            
    }
    $parent.append(li.addClass('matched'))
});
// remove original    
$('ul.testList').remove()

DEMO

like image 56
charlietfl Avatar answered Nov 15 '22 20:11

charlietfl


At first glance, I'd suggest:

// finding all direct children of the <ul> with the class 'testList'
// which are both <li> elements and have a 'class' attribute,
// iterating over them using the each() method:
$('ul.testList > li[class]').each(function () {

    // if a <ul> already exists with the class-name of the
    // current <li> element over which we're iterating
    // (which would lead to a truthy non-zero length):
    if ($('ul.' + this.className).length) {

        // we append this <li> element to the found <ul>:
        $(this).appendTo($('ul.' + this.className));
    } else {

        // otherwise we create a <ul> element:
        $('<ul>', {
            // give it the class-name of the current <li> element:
            'class': this.className
        // wrap it (the created <ul>) with an <li> element:
        }).wrap('<li></li>')
        // append the <ul> (wrap returns the original node) to
        // the current parent-node of the <li>:
        .appendTo(this.parentNode)
        // and append the original <li> node (appendTo also returns
        // the original node) to the <ul>:
        .append(this);
    }

    // adding the 'matched' class-name to the current <li>
    // element:
    this.classList.add('matched');
});

$('ul.testList > li[class]').each(function() {
  if ($('ul.' + this.className).length) {
    $(this).appendTo($('ul.' + this.className));
  } else {
    $('<ul>', {
      'class': this.className
    }).wrap('<li></li>').appendTo(this.parentNode).append(this);
  }
  this.classList.add('matched');
});
.matched {
  color: red
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="testList">
  <li class="a">should be red and grouped in a UL with id name = a</li>
  <li class="b">2</li>
  <li class="c">should be red and grouped in a UL with id name = c</li>
  <li class="c">should be red and grouped in a UL with id name = c</li>
  <li class="d">2</li>
  <li class="a">should be red and grouped in a UL with id name = a</li>
</ul>

JS Fiddle demo.

References:

  • append().
  • appendTo().
  • each().
like image 38
David Thomas Avatar answered Nov 15 '22 22:11

David Thomas


Try using .appendTo() , .append() , .is() . Note , if li className is not repeated within .testList , li is not given matched class , not appended to new ul element

$("ul.testList li").each(function(i, el) {
  if (!$(el).parent().find("#" + this.className).is("*") 
      // if `.testList` has another `li` element having `this.className` 
      && $(el).parent().find("." + this.className).not(this).is("*")) {
    $(el).parent()
    .append(
      $("<li />", {
        html: $("<ul />", {
                id: el.className
              }).append($(el).addClass("matched"))[0].outerHTML
      })
    );
  } else {
    $(el).appendTo("#" + this.className).addClass("matched")
  }
})
.matched {
  color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<ul class="testList">
  <li class="a">should be grouped in a UL with id name = a</li>
  <li class="b">2</li>
  <li class="c">should be grouped in a UL with id name = c</li>
  <li class="c">should be grouped in a UL with id name = c</li>
  <li class="d">2</li>
  <li class="e">3</li>
  <li class="a">should be grouped in a UL with id name = a</li>
</ul>
like image 28
guest271314 Avatar answered Nov 15 '22 21:11

guest271314


You can do something like this

var cls = [];
// getting unique class names
$('.testList li').attr('class', function(i, v) {
  if (cls.indexOf(v) == -1) cls.push(v);
});

// iterating over class name and creating ul and appending
for (var i = 0; i < cls.length; i++) {
  // creating ul with id as class name
  var ul = $('<ul/>', {
    id: cls[i]
  });
  // selecting all elements with classname and appending it to ul 
  $('.' + cls[i]).appendTo(ul);
  // creating new li to add to main ul, setting html as created ul.
  $('<li/>', {
    html: ul
  }).appendTo('.testList');
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<ul class="testList">
  <li class="a">should be red and grouped in a UL with id name = a</li>
  <li class="b">2</li>
  <li class="c">should be red and grouped in a UL with id name = c</li>
  <li class="c">should be red and grouped in a UL with id name = c</li>
  <li class="d">2</li>
  <li class="a">should be red and grouped in a UL with id name = a</li>
</ul>

Or combined version

var cls = [];
$('.testList li').attr('class', function(i, v) {
  if (cls.indexOf(v) == -1) cls.push(v);
});

for (var i = 0; i < cls.length; i++) {
  $('<li/>', { // mail ul list item
    html: $('<ul/>', { // it's content as new ul
      id: cls[i], // setting ul id as class name
      html: $('.' + cls[i]) // appending parent ul to new ul
    })
  }).appendTo('.testList'); // appending li to parent ul
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<ul class="testList">
  <li class="a">should be red and grouped in a UL with id name = a</li>
  <li class="b">2</li>
  <li class="c">should be red and grouped in a UL with id name = c</li>
  <li class="c">should be red and grouped in a UL with id name = c</li>
  <li class="d">2</li>
  <li class="a">should be red and grouped in a UL with id name = a</li>
</ul>
like image 39
Pranav C Balan Avatar answered Nov 15 '22 21:11

Pranav C Balan