Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using .after() to add html closing and open tags

I'm trying to split an unordered list into two columns by finding the halfway point of the list and adding </ul><ul> after that </li>. This could be the complete wrong way to do this but it is how I thought to do it. My js looks like this:

$('.container ul').each(function(){

    var total = $(this).children().length;
    var half = Math.ceil(total / 2) - 1;
    $(this).children(':eq('+half+')').after('</ul><ul>');

});

The problem I'm having and what I don't understand is that .after() is reversing the order of the tags and outputs:

<ul>

<li><a href="#">link</a></li>

<li><a href="#">link</a></li>

<li><a href="#">link</a></li>

<ul></ul>

<li><a href="#">link</a></li>

<li><a href="#">link</a></li>

</ul>

Please let me know if there's a better way to do this, but I really would like to know why .after() is reversing the order of tags. Thanks

like image 701
user1120130 Avatar asked Jan 02 '12 23:01

user1120130


1 Answers

You can't think about DOM modification as if you were editing the original HTML file. Once the browser has parsed the HTML file, to all intents and purposes it no longer exists. The only thing that matters is the DOM representation.

With that in mind, let's have a look at the bit of code you've posted...

.after('</ul><ul>')

You're imagining this editing the HTML present and adding in a closing tag and an opening tag. It doesn't. It builds a document fragment from that code and then adds it as a sibling of the element in the original selection. Since </ul> isn't a valid beginning to a string of HTML, it is dropped. All you have left is <ul>, which is parsed as an element in its entirety (imagine an HTML document that went <div><ul></div> and you'll get the idea). So an empty ul element is inserted into the list as a sibling of the element you've selected: it's represented as <ul></ul> as this is the way to serialise a ul element to HTML.

To do what you want to do, you'll need to use a different approach, one that recognises what the DOM is.

$('.container ul').each(function(){
    var total = $(this).children().length;
    var half = Math.ceil(total / 2) - 1;
    $(this).children(':gt('+half+')').detach().wrapAll('<ul></ul>').parent().insertAfter(this);
});

This says "get the children after halfway (:gt), detach them from the current ul, wrap them in a new ul, select that ul with parent and insert it after the current ul (this)."


Working jsFiddle

like image 100
lonesomeday Avatar answered Sep 17 '22 17:09

lonesomeday