0

Hi I have a list of unordered elements. When clicked I would like to insert a <p> element whilst splitting the <ul> in 2.

The problem being that $("</ul>"+text+"<ul class=\"test\">").insertAfter(element); seems to separate the <p> element from the <ul> elements, inserting the <p> first then the <ul> tags.

I would also like to remove the opening and closing <ul> immediately before and after the .temp element so I can split the <ul> in different spot. This was the only method I could find but it only removes the <p> element: $('.temp').remove();

The way the page is formatted at the start of this is exactly what I'm after. The JS is just bit broken. http://jsfiddle.net/yU65g/1/

JS:

    $(".test li").click(function () {
    var text = "<p class=\"temp\">Test</p>";
  var index = $(".test li").index(this);
  $("span").text("That was div index #" + index);
   var element = $('.test li').get(index);
    $('.temp').remove();
    $("</ul>"+text+"<ul class=\"test\">").insertAfter(element);
});

HTML:

<html>
<head>
  <script src="http://code.jquery.com/jquery-latest.js"></script>
</head>
<body>
  <span>Click a div!</span>
        <ul class="test">
<li>First div</li>
<li>Second div</li>
<li>Third div</li>

    </ul>
    <p class="temp">Test</p>
 <ul class="test"> 

<li>Fourth div</li>
<li>Fith div</li>
<li>Sixth div</li>
        </ul>

</body>
</html>

CSS:

.test li { background:yellow; margin:5px; }
span { color:red; }
.test {border: solid 1px red; clear:both; margin: 1em;}
.temp {clear:both;}
Ryan King
  • 3,538
  • 12
  • 48
  • 72
  • possible duplicate of [jQuery split long ul list in smaller lists](http://stackoverflow.com/questions/1644668/jquery-split-long-ul-list-in-smaller-lists) – Ram Feb 22 '13 at 01:30
  • what about closing the current ul, inserting the p, then opening the next ul? such as .append('

    content

      ');
    – lukeocom Feb 22 '13 at 01:33
  • 1
    Btw, I think it's important to point out that `var index = $(".test li").index(this); var element = $('.test li').get(index);` is the same as simply doing `var element = this;`. No need to make it overly complicated. – Felix Kling Feb 22 '13 at 01:42

4 Answers4

2

When working with the DOM, "tags" don't really exist. jQuery parses the HTML string and creates DOM elements out of them as best as it can and then inserts them into the tree.

So, with DOM element in mind, "splitting" means that you have to take all of the following li elements (if there are any) and move them to a new list.

For example:

$(".test li").click(function () {
    $("span").text("That was div index #" + $(this).index());

    var $ul = $(this).parent(); // the current list (the parent `ul` element)
    var $following = $(this).nextAll('li'); // all following `li` elements

    if ($following.length > 0) {
        // Create a new list, append the `li` elements and add the list
        // after the current list
        $('<ul />', {'class': 'test'}).append($following).insertAfter($ul);
    }

    // add a paragraph after the current list
    $('.temp').remove();
    $('<p />', {'class': 'temp',text: 'Test'}).insertAfter($ul);
});

DEMO


If you only want to split all elements into two lists, the following will work, assuming both lists already exist:

var $uls = $("ul.test");
var $lis =  $uls.find("li");

$lis.click(function () {
    var index = $lis.index(this);
    $("span").text("That was div index #" + index);

    var $following = $lis.slice(index + 1); // get all following `li` elements
    if ($following.length > 0) {
       // append to second list
       $uls.eq(1).append($following);
    }

    // append all li elements up to the current one to the
    // first list
    $uls.eq(0).append($lis.slice(0, index + 1));

    // add a paragraph after the first list
    $('.temp').remove();
    $('<p />', {'class': 'temp',text: 'Test'}).insertAfter($uls.eq(0));
});

DEMO

Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
  • This is great, but is it possible to get it so there is only ever 2 ul's? One before the paragraph and one after. Maybe if we wrap the ul's in a div we can select all previous li's regardless of what ul they're in and them all into a previous single ul. And and do the same for after the paragraph. – Ryan King Feb 22 '13 at 02:53
  • 1
    @RyanKing: Ah, that's what you want to do. Yes, that's also quite easy, assuming both lists already exist and it actually works exactly how you described it. Have a look at this example: http://jsfiddle.net/yU65g/7/. – Felix Kling Feb 22 '13 at 03:05
  • Perfect. Well almost. I do need it to work with single list in the beginning without the paragraph inserted, then have the second list added once clicked. And then return a single list when the last li is selected so the second list will be removed if it contains no li's. Thanks for your help. – Ryan King Feb 22 '13 at 03:24
  • 1
    You can check wih `$uls.length` how many lists there are. If it's one, you can create a new one, append it (just like in the first example) and add it to `$uls` with `$uls = $uls.add($newUl)`. For removing, check the length of `$following`. – Felix Kling Feb 22 '13 at 09:38
  • Yep that's pretty much what I got: http://jsfiddle.net/yU65g/11/ - except I've used `$('ul.test').after("
      ");` to add a second list and I've had to copy `var $uls = $("ul.test");` within the click event to get `.length` working for some reason.
      – Ryan King Feb 22 '13 at 21:54
    • 1
      @Ryan: Great! But you don't have to reselect `ul.test` over and over again. You can work with the existing `$uls` object. Here is an updated version: http://jsfiddle.net/yU65g/13/. – Felix Kling Feb 22 '13 at 21:58
    • Thanks Felix, that's looking much cleaner. – Ryan King Feb 22 '13 at 22:37
    1

    highly recommend .nextAll() to get the siblings after what is clicked on. .detach() will remove them from the dom, and they can be moved then (it also keeps the click event registered to it). I append the <p> you wanted, then append a cloned ul after the text. fiddle

    $(".test li").click(function () {
      var copied = $(this).nextAll().detach(), ul = $(this).closest("ul"), copyUl = ul.clone().empty().append(copied), test = $("<p>Test</p>",{"class":"temp"}); 
    if(copied.length > 0){
      ul.after(test);
      test.after(copyUl);
    }
    
    });
    
    DefyGravity
    • 5,681
    • 5
    • 32
    • 47
    0

    jQuery (and JavaScript) work with the DOM, not with HTML tags. Don't be confused by the $("<tag>") syntax; it's still DOM nodes that are being created, appended, and the like.

    Therefore, you would have to create a new $("<p>") and append it to the body and append the created ul to that.

    As for getting the <li>s you want, you can use the length of the $("ul li") collection divided in half.

    Working example: http://jsfiddle.net/yU65g/2/

    Explosion Pills
    • 188,624
    • 52
    • 326
    • 405
    0

    Add p and a new ul after the original ul

    JS

    var li = $('#myul li');
    $('body')
        .append($('<p>p</p>'))
        .append($('<ul/>')
        .append(li.slice(li.length/2)));
    

    HTML

    <ul id="myul">
      <li>a</li>
      <li>b</li>
      <li>c</li>
      <li>d</li>
      <li>e</li>
      <li>f</li>
    </ul>
    

    http://codepen.io/anon/pen/qKmae

    Shanimal
    • 11,517
    • 7
    • 63
    • 76