Alternative ways to dynamically create li elements - javascript

Using JavaScript, I need to dynamically create a list like this:
<ul id="list">
<li>2015</li>
<li>2016</li>
<li>2017</li>
<li>2018</li>
<li>2019</li>
<li>2020</li>
</ul>
The "classic solution" (as far as I know) is:
for (var i = 2015; i <= 2020; i++) {
var li = document.createElement("li");
li.innerHTML = i;
list.appendChild(li);
}
It works perfectly.
But I would like to find alternative, better - in terms of performance - solutions, if there are (I want to learn something more).
So I tried:
for (var i = 2015; i <= 2020; i++) {
var el = "<li>" + i + "</li>";
list.insertAdjacentHTML('beforeend', el);
console.log(el);
el += el;
}
<ul id="list"></ul>
AND
for (var i = 2015; i <= 2020; i++) {
var el = "<li>" + i + "</li>";
list.innerHTML += el;
console.log(el);
}
<ul id="list"></ul>
But in both cases this is the result:
in the DOM:
<ul id="list">
<li>2015</li>
<li></li>
<li>2016</li>
<li></li>
<li>2017</li>
<li></li>
<li>2018</li>
<li></li>
<li>2019</li>
<li></li>
<li>2020</li>
<li></li>
</ul>
while in the console:
<li>2015<li>
<li>2016<li>
<li>2017<li>
<li>2018<li>
<li>2019<li>
<li>2020<li>
Why those empty nodes (<li></li>)? And why in the DOM only?

In both you added "<li>" + i + "<li>" instead of "<li>" + i + "</li>"
Missing slash small thing, but user agents are prepared to fix missing closing... and your code appeared with doubled li

Related

Loop over data and create html elements with data

I am fetching json data from a php script and attempting to display the data on a webpage. The issue I am having is I want to limit the number of < li > tags in a < ul >, if the limit is met then I want to create a new < ul > element.
JSON:
[{"mDescription":"Red Widget","mReference":"rwid"},{"mDescription":"Blue Widget","mReference":"bwid"},{"mDescription":"Yellow Widget","mReference":"ywid"},{"mDescription":"Orange Widget","mReference":"owid"},{"mDescription":"Green Widget","mReference":"gwid"},{"mDescription":"Black Widget","mReference":"bwid"},{"mDescription":"White Widget","mReference":"wwid"}]
I have attempted looping but I'm getting odd results, code:
function getWidgetList() {
let widgetListURL = 'php/list.php';
fetch(widgetListURL)
.then((response) => response.json())
.then((data) => {
let html = '';
html += `<ul class="col-sm-2 list-unstyled"><li><p class="title">Widgets:</p></li>`;
let counter = 0;
let limit = 3;
for (let key in data) {
let widget = data[key];
html += '<li data-desk="' + widget.mReference + '"><a><span class="d-title">' + widget['mDescription'] + '</span></a></li>';
if (++counter > limit) {
html += `</ul><ul class="col-sm-2 list-unstyled">
<li><p class="title">Widgets:</p></li>`;
counter = 0;
}
}
html += `</ul>`;
//byID('widgetList').innerHTML(html);
console.log(html);
})
}
Result:
<ul class="col-sm-2 list-unstyled"><li><p class="title">Widget:</p></li>
<li data-desk="rwid"><a><span class="d-title">Red Widget</span></a></li>
<li data-desk="bwid"><a><span class="d-title">Blue Widget</span></a></li>
<li data-desk="ywid"><a><span class="d-title">Yellow Widget</span></a></li>
<li data-desk="owid"><a><span class="d-title">Orange Widget</span></a></li>
</ul>
<ul class="col-sm-2 list-unstyled"><li><p class="title">Widget:</p></li>
<li data-desk="gwid"><a><span class="d-title">Green Widget</span></a></li>
</ul>
<ul class="col-sm-2 list-unstyled"><li><p class="title">Widget:</p></li>
<li data-desk="bwid"><a><span class="d-title">Black Widget</span></a></li>
</ul>
<ul class="col-sm-2 list-unstyled"><li><p class="title">Widget:</p></li>
<li data-desk="wwid"><a><span class="d-title">White Widget</span></a></li>
</ul>
I am trying to complete this task using modern JavaScript and no JQuery. Any Help would be greatly appreciated.
The best way to do this is to use the modulo operater:
let liTagLimit = 3;
let index = 0;
let html = '<ul id="first-ul">';
for(let key in data){
//...create li
index++;
if(index % liTagLimit == 0){//<----- HERE IS THE TRICK
html += "</ul><ul>";
}
html += '</ul>';
you can use forEach with index.
html += '<ul class="col-sm-2 list-unstyled"><li><p class="title">Widgets:</p></li>';
data.forEach((widget,i)=>{
if (i != 0 && (i % limit == 0)) {
html += '</ul><ul class="col-sm-2 list-unstyled"><li><p class="title">Widgets:</p></li>';
}
html += '<li data-desk="' + widget.mReference + '"><a><span class="d-title">' + widget['mDescription'] + '</span></a></li>';
}
)
html += '</ul>';

JavaScript to trim whitespace from the innerHtml for all elements in a html string

I have a string as follows:
<div> Here is some text </div>
<div>Here is some text </div>
<ul>
<li>test 1 </li>
<li> test 2</li>
<li> test 3 </li>
</ul>
<div> Here is some text </div>
I need to loop through each element and trim the whitespace and any leading or trailing entities using JavaScript so that the end result is as follows:
<div>Here is some text</div>
<div>Here is some text</div>
<ul>
<li>test 1</li>
<li>test 2</li>
<li>test 3</li>
</ul>
<div>Here is some text</div>
To provide more background, this is a string that is being pasted into a WYSIWYG editor. So I am simply attempting to clean up the string as it is being pasted. I'm not great with JavaScript, but even if I were to use the method suggested in the Javascript: How to loop through ALL DOM elements on a page? post, I am uncertain as to how to utilise document.getElementsByTagName("*"); in a string.
UPDATE
Using #Bharata's answer, I was able to achieve the clean up using the following:
var str = "<div> Here is some text </div>" +
"<div>Here is some text </div>" +
"<ul>" +
" <li>test 1 </li>" +
" <li> test 2</li>" +
" <li> test 3 </li>" +
"</ul>" +
"<div> Here is some text </div>";
var cleanHtml = cleanUp(str);
function cleanUp(content) {
var dom = document.createElement("div");
dom.innerHTML = content;
var elems = dom.getElementsByTagName('*');
for (var i = 0; i < elems.length; i++) {
if (elems[i].innerHTML) {
elems[i].innerHTML = elems[i].innerHTML.trim();
}
}
return dom.innerHTML;
}
You can use JS DOM API for this case like follows:
Add your text to hidden div element
Replace all spaces in innerHTML content using trim() and replace() functions.
Full example
var str = "<div> Here is some text </div>" +
"<div>Here is some text </div>" +
"<ul>" +
" <li>test 1 </li>" +
" <li> test 2</li>" +
" <li> test 3 </li>" +
"</ul>" +
"<div> Here is some text </div>";
var hiddenDiv = document.querySelector('#hidden-div');
hiddenDiv.innerHTML = str;
var hiddenElems = hiddenDiv.getElementsByTagName('*');
for(var i = 0; i < hiddenElems.length; i++)
{
if(hiddenElems[i].innerHTML)
{
hiddenElems[i].innerHTML = hiddenElems[i].innerHTML.trim().replace(/ /g, '');
}
}
document.write('<pre>' + hiddenDiv.innerHTML + '</pre>');
<div id="hidden-div" style="display:none"></div>
you have to get all text nodes and trim content:
var walker = document.createTreeWalker(
document.querySelector('#my-div'),
NodeFilter.SHOW_TEXT,
null,
false
);
var node;
while(node = walker.nextNode()) {
if(!node.previousSibling)
node.textContent = node.textContent.replace(/^( |\s)*/, '')
if(!node.nextSibling)
node.textContent = node.textContent.replace(/( |\s)*$/, '')
}

Dynamically created tabs getting error: Uncaught Error: jQuery UI Tabs: Mismatching fragment identifier. at Function.error

Dynamically created tabs, but getting this kind of error, I don't know where I went wrong, and tabindex is -1 if i check in developer console.
<div id="tabDiv">
<ul id="tabs" class="nav-tabs">
<li class="active"> All </li>
</ul>
</div>
<script>
function addTabs(result) {
var unit = _.map(result, 'unit');
unit = _.uniq(unit);
var tabs = $("#tabDiv").tabs();
for (var i = 0; i < unit.length; i++) {
var ul = tabs.find("ul");
var current_idx = ul.find("li").length + 2; // Get correct index for id
$("<li><a href=#" + current_idx + " tabindex=" + ul.find("li").length + " onclick=getList(); data-toggle=tab>" + unit[i] + "</a></li>").appendTo(ul);
onclick = "getList('wip_production');"
tabs.tabs("refresh")
}
$("</ul>").appendTo(tabs);
}
</script>

Get text and id value from li

I've been stuck in this stupid situation, i got an unorder list like this:
var liList = $("#first").find("li");
var append = "";
for(var i =0; i< liList.length; i++){
var item = $(liList);
append += "<option value=" + item.prop("id") + ">" + item.text() + "</option";
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul id="first">
<li id=1>
li 1
<ul>
<li id=2> li 2</li>
</ul>
</li>
</ul>
I want to get the text and id for each li in unorder list, but in the item.text() code part i got the current li text and the childrens text ("li1li2", "li2", etc). Any suggestion?.
Regards
You can get the value first node from a DOM element (which happens to be text in your case) with .childNodes[0].nodeValue:
append += "<option value=" + item.prop("id") + ">" + item[0].childNodes[0].nodeValue + "</option";
Since liList is an array containing all the li elements you must iterate over every element inside you loop:
for(var i = 0; i < liList.length; i++) {
// retreive each element from the array
var item = $(liList[i]);
append += "<option value=" + item.prop("id") + ">" + item.text() + "</option>";
}

Transpose non-well formed XML document to an HTML Unordered List

I am working on a project that requires me to parse an XML tree where the XML is not so great. I need to define a UL structure from the XML but the issue is that all the nodes are the same name with different attributes. I am using jQuery ajax function to call this XML file and return it on success. Here is my conundrum:
> <class name="Juice">
> <class name="OJ">
> <class name="Low Sugar" />
> <class name="Some Pulp" />
> </class>
> <class name="Apple" />
> <class name="Grape" />
> </class>
As you can see the node names make it hard to transpose this to a uniformed list. I am trying to get this to recurse and look like this:
<ul>
<li>Juice
<ul>
<li>OJ
<ul>
<li>Low Sugar</li>
<li>Some Pulp</li>
</ul>
</li>
<li>Apple</li>
<li>Grape</li>
</ul>
</li>
</ul>
my ajax call:
$.ajax({
type: "GET",
url: "nav.xml",
dataType: "xml",
success: function (xml) {
xmlParser(xml);
}
});
my xmlParser function:
function xmlParser(xml) {
$(xml).find("class class").each(function () {
var cname = $(this).attr("name");
if ($(this).children.length > 0) {
$("#nav .categories").append("<li id='" + cname + "'><a href='#'>" + cname + "</a></li>");
$(xml).find("[name='" + cname + "']").children().each(function () {
var cname1 = $(this).attr("name");
$("#" + cname).append("<ul></ul>");
$("#" + cname + " ul").append("<li id='" + cname1 + "'><a href='#'>" + cname1 + "</a></li>");
});
} else {
$("#nav .categories").append("<li id='" + cname + "'><a href='#'>" + cname + "</a></li>");
}
});
}
My HTML on the page where I want to append the unordered list:
<ul id="nav" class="categories"></ul>
This ends up duplicating some code and is not recursive, I would like to get something where I can recall the parseXml function and pass some argument where the elements are not duplicated in the tree. I would rather trash this function and start over with something cleaner and neater.
Are there any jQuery plugins that do this already. I have checked this site and Google but nothing I am looking for works with this bad XML. All others I found use a well formed XML structure.
Thanks in advance.
How about this?
<html>
<body>
<script>
var isIE = (window.attachEvent);
var txt = "<class name=\"Juice\"><class name=\"OJ\"><class name=\"Low Sugar\" /><class name=\"Some Pulp\" /></class><class name=\"Apple\" /><class name=\"Grape\" /></class>";
var doc = NewXmlDoc(txt);
var output = "<ul>";
WalkTree(doc.documentElement);
output+="</ul>";
alert( output );
function WalkTree(node)
{
output += "<li>"+node.getAttribute("name");
if (node.childNodes.length > 0)
{
output += "<ul>";
for (var inx = 0; inx < node.childNodes.length; inx++)
{
var childNode = node.childNodes[inx];
WalkTree(childNode);
}
output += "</ul>";
}
output += "</li>";
}
function NewXmlDoc(sXml)
{
var xmlDoc;
if (isIE)
{
xmlDoc = new ActiveXObject("Microsoft.XMLDOM")
xmlDoc.async = false;
xmlDoc.loadXML(sXml);
if (xmlDoc.parseError.errorCode != 0)
return null;
}
else if (document.implementation && document.implementation.createDocument)
xmlDoc = (new DOMParser()).parseFromString(sXml, "text/xml");
return xmlDoc;
}
/* Result is...
<ul>
<li>Juice
<ul>
<li>OJ
<ul>
<li>Low Sugar</li>
<li>Some Pulp</li>
</ul>
</li>
<li>Apple</li>
<li>Grape</li>
</ul>
</li>
</ul>
*/
</script>

Categories

Resources