I have this one
<ul id="reportsTree" class="tree">
<li class="reportGroupItem">Coffee</li>
<li class="reportGroupItem">Tea
<li class="reportItem">Black tea</li>
<li class="reportItem">Green tea</li>
</li>
<li class="reportGroupItem">Milk</li>
</ul>
But I need this one
<ul id="reportsTree" class="tree">
<li class="reportGroupItem">Coffee</li>
<li class="reportGroupItem">Tea
<ul>
<li class="reportItem">Black tea</li>
<li class="reportItem">Green tea</li>
</ul>
</li>
<li class="reportGroupItem">Milk</li>
</ul>
Look that the two <li_> elements with the class "reportItem" are wrapped by a element... but I cannot just wrap "reportItem" elements with because can be more than one (like the example) and I cannot just insert the element after a "reportGroupItem" becasue maybe there are no childs inside... So, what can I do.
I've tried with .wrapInner(), .wrapAll, looking for first child...
Very easy, but very frustrating for me :(
Malformed code is generated like this:
<logic:iterate name="ReportGenerationForm" property="reportGroups" id="group">
<li class="reportGroupItem">
<bean:write name="group" property="code" />
<logic:iterate name="group" property="reports" id="report" indexId="index">
<li class="reportItem">
<bean:write name="report" property="code" />
</li>
</logic:iterate>
</li>
</logic:iterate>
Reframing the question based on OPs comment "this was my first try", by changing the source to output as:
<logic:iterate name="group" property="reports" id="report" indexId="index">
<ul>
<li class="reportItem">
<bean:write name="report" property="code" />
</li>
</ul>
</logic:iterate>
which will output as:
<ul id="reportsTree" class="tree">
<li class="reportGroupItem">Coffee</li>
<li class="reportGroupItem">Tea
<ul>
<li class="reportItem">Black tea</li>
</ul>
<ul>
<li class="reportItem">Green tea</li>
</ul>
</li>
<li class="reportGroupItem">Milk</li>
</ul>
We can then, based on this answer combine the lis inside the inner uls using:
$("ul > li > ul + ul").each((i, e) => {
$(e).children('li').appendTo($(e).prev());
$(e).remove();
})
you could use ids/classes instead, eg ul#reportsTree > li.reportGroupItem > ul + ul
which says: find all lists that follow another list inside a list item inside a list. The key part is the ul + ul. Similar would be ul>li>ul:not(:first)
Then moves all the children list items to the previous ul (no need for .prev("ul") or similar as the ul+ul already confirms previous is a ul)
Updated snippet below. Here, I've given each ul and underline/separator so you can visibly see them combine when clicking the button. Or you can inspect element to see the effect (and that there's no "orphaned"(childless) ul left behind)
$("button").on("click", () => {
$("ul>li>ul+ul").each((i, e) => {
//console.log($(e).text())
$(e).children('li').appendTo($(e).prev());
$(e).remove();
})
});
ul {
border-bottom: 1px solid #CCC
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul id="reportsTree" class="tree">
<li class="reportGroupItem">Coffee</li>
<li class="reportGroupItem">Tea
<ul>
<li class="reportItem">Black tea</li>
</ul>
<ul>
<li class="reportItem">Green tea</li>
</ul>
</li>
<li class="reportGroupItem">Milk</li>
</ul>
<button>
click me
</button>