Every text value inside an HTML element needs a new line character. Here is the dart method I used to do it. However, it failed to add new lines for the given type of HTML elements. I would like to know how can I change this method which can success for all types of cases.
Thanks in advance.
Code
dom.Element loop(dom.Element node){
final List<dom.Element> elements = node.children;
for (int i = 0; i < elements.length; i++){
if(elements[i].hasContent() && elements[i].children.isEmpty){
elements[i].innerHtml = '${elements[i].text}\n';
continue;
} else
if(elements[i].children.isNotEmpty){
loop(elements[i]);
}
}
return node;
}
Input HTML element
<div>
<ul>
<li>test1</li>
<li>
test2
<ul>
<li>
test3
<ul>
<li>test4</li>
<li>test5</li>
</ul>
</li>
<li>test6</li>
</ul>
</li>
<li>test7</li>
</ul>
</div>
Expected result
<div>
<ul>
<li>test1\n</li>
<li>
test2\n
<ul>
<li>
test3\n
<ul>
<li>test4\n</li>
<li>test5\n</li>
</ul>
</li>
<li>test6\n</li>
</ul>
</li>
<li>test7\n</li>
</ul>
</div>
Here is a javascript implementation of the answer (You can change it to dart easily)
function loop(node) {
const elements = node.children
for(const element of elements) {
if(element.children.length > 0) loop(element)
else if(element.textContent.length > 0) {
element.innerHTML = element.textContent + " \\n "
}
}
}
This works except it won't change the text of a parent node. If you add \n to a parent node like li2 you will get the \n after everything including its children, there is no way to just select that initial text that I can see. You may need to do more research in that area.
The output of the above function.
<div>
<ul>
<li>test1\n</li>
<li>
test2
<ul>
<li>
test3
<ul>
<li>test4\n</li>
<li>test5\n</li>
</ul>
</li>
<li>test6\n</li>
</ul>
</li>
<li>test7\n</li>
</ul>
</div>
Related
Let's say my code looks like that
const menu = document.querySelector(".menu");
//now i need to select <a> tags with 'design' and 'development', but using menu element i've already selected.
//const firstLineChilds = menu.querySelector(???);
<ul class="menu">
<li>Design</li>
<li>Development</li>
<li>
<ul class="sub-menu">
<li>DevOps</li>
<li>Managment</li>
</ul>
</li>
</ul>
Is it even possible to to this the 'clean way'? Or i just need to use menu.parentNode.querySelector(".menu > li > a")
You can chain querySelector and other such methods and it will search children of previous returned node: document.querySelector(".menu").querySelectorAll("a") or menu.querySelectorAll("a")
Converting the hrefs to an Array (in the snippet the spread syntax is used for that) enables you to filter them:
const relevantHrefs = [...document.querySelectorAll(".menu li a")]
.filter(href => ["Design", "Development"].find(h => href.textContent === h));
console.log(relevantHrefs);
// based on comment, this is maybe what OP needs
const menu = [...document.querySelectorAll(".menu > li:nth-child(-n+2) a")];
console.log(menu);
<ul class="menu">
<li>Design</li>
<li>Development</li>
<li>
<ul class="sub-menu">
<li>DevOps</li>
<li>Managment</li>
</ul>
</li>
</ul>
Yes, you can use :scope in conjunction with child combinators, in menu.querySelectorAll():
const menu = document.querySelector(".menu")
const firstLineChilds = menu.querySelectorAll(":scope > li > a");
console.log(firstLineChilds);
<ul class="menu">
<li>Design</li>
<li>Development</li>
<li>
<ul class="sub-menu">
<li>DevOps</li>
<li>Managment</li>
</ul>
</li>
</ul>
If you use descendant combinators, you'll still get the nested a elements, which is not what you want. See What does the ">" (greater-than sign) CSS selector mean?
I need to get the value "B". But coming with value "A". I do not to get the value of "A". How to distinguish?
My HTML structure:
<li>
<ul>
<li value="A">
<ul>
<li onclick="cick(this)" value="B"></li>
</ul>
</li>
</ul>
</li>
If you want to get the value of a particular <li> element when there are more than one in the document, you can distinguish between the element by using unique ids or classes.
Option 1: IDs
<li>
<ul>
<li id="number1" value="100">
<ul>
<li id="number2" onclick="click(this)" value="200"></li>
</ul>
</li>
</ul>
</li>
To get the value you would then:
function(){
var el = document.getElementById("number2")
var value = el.value; // outputs 200
}
Option 2: Classes
<li>
<ul>
<li class="number1" value="150">
<ul>
<li class="number2" onclick="click(this)" value="300"></li>
</ul>
</li>
</ul>
</li>
function(){
var el = document.getElementsByClassName("number2")[0]
var value = el.value; // outputs 300
}
List items can't have non-numeric values. For your HTML to be considered valid, you'll need to change your values to numbers. If you do this, you can then easily use javascript to get your values. A HTML structure with valid values may look something like so:
<li>
<ul>
<li value="1"> <!-- Changed A to 1 -->
<ul>
<li onclick="cick(this)" value="2"></li> <!-- Changed B to 2 -->
</ul>
</li>
</ul>
</li>
You can use document.querySelector and pass in the selector li[value="1"] > ul > li (this will select all li tags which are a child of a ul tag which is a child of a li tag with the value of 1). You can use this generically for a parent list item of value x like so:
li[value="x"] > ul > li
See example below:
const val = document.querySelector('li[value="1"] > ul > li').value;
console.log(val); // 2
<li>
<ul>
<li value="1">
<ul>
<li id="A" onclick="cick(this)" value="2"></li>
</ul>
</li>
</ul>
</li>
I have an array in javascript called menuElm that has <ul> elements in it:
<ul id="1"></ul>
<ul id="2"></ul>
<ul id="3"></ul>
I have a page in HTML that has the following:
<ul id="menu">
<li class="menu-item"></li>
<li class="menu-item"></li>
<li class="menu-item"></li>
</ul>
I want to add the elements of menuElm to the HTML page so it would look like this:
<ul id="menu">
<li class="menu-item">
<ul id="1"></ul>
</li>
<li class="menu-item">
<ul id="2"></ul>
</li>
<li class="menu-item">
<ul id="3"></ul>
</li>
</ul>
I have tried the following, but the <ul> elements just wont show up in the page nor in the code:
function CreateMenu() {
var menuElm;
var k = 0;
menuElm = createElm("ul");
menuElm.id = ++k;
for (var i = 0; i < menuElm.length; ++i) {
document.getElementsByClassName("menu-item")[i].appendChild(menuElm[i]);
}
}
I am new with JavaScript, what am I doing wrong?
menuElm.length
The ul element doesn't have a length, so you are looping from 0 to 0, which is 0 iterations.
menuElm = createElm("ul");
This function isn't defined. You need document.createElement('ul');
menuElm = createElm("ul");
menuElm.id = ++k;
You appear to be creating one list item, and then changing its ID and appending it multiple times.
You need a new list item each time you go around the loop.
appendChild(menuElm[i]);
You've been treating menuElm as an element previously. It isn't an array, [i] makes no sense here.
$("#menu").find('li').each(function(i){
$(this).append(menuElm[i]);
});
/* if you want to use jquery here is the code to append */
I need to write a function in pure JavaScript witn no framework to get all specific tags, but only from first level under parent.
For example: I need to call some function on first <ul> and get all <li> from first level of it (<li> with text 1.2 and <li> with text 2.1)
<div id="sideNavigation">
<ul>
<li class=" act open ">
1.2
<ul>
<li class=" ">
1.2
<ul>
<li class=" ">
1.3
<ul>
<li class=" ">1.4</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li class=" ">
2.1
<ul>
<li class=" ">2.2.1</li>
<li class=" ">2.2.2</li>
<li class=" ">2.2.3</li>
</ul>
</li>
</ul>
</div>
I've been trying to do it like this:
var allLi = document.getElementById("sideNavigation").getElementsByTagName("li");
but it returns all <li> in this div not only first level <li>. Do you have any quick method to solve my problem or do I have to implement a new function to detect depth of nodes
You can use the attribute .children to get those "li"
var firstDepthLi = document.getElementById("sideNavigation").children[0].children;
If you want a generic function you can create something like:
var getElementsByDepth = function(el, tagname, depth) {
var children = el.children;
var res = new Array();
for(var i=0; i<children.length; i++) {
if (children[i].tagName == tagname) {
res.push(children[i]);
if (depth > 0)
res.concat(getElementsByDepth(children[i], tagname, depth-1));
}
}
return res;
}
Try:
var allLi = document.getElementById("sideNavigation").getElementsByTagName("li")[0];
That should return the first li element out of all li's on the page. Change the zero at the end to a different number to get a different element. You could even set a variable for the value:
var liNum = 0;
var allLi = document.getElementById("sideNavigation").getElementsByTagName("li")[liNum];
And in a function:
function getLi(depth) {
var specificLi = document.getElementById("sideNavigation").getElementsByTagName("li")[depth];
return specificLi;
}
var firstLi = getLi(0);
console.log(firstLi);
<div id="sideNavigation">
<ul>
<li>First list tag</li>
<li>Second list tag</li>
<li>Third list tag</li>
</ul>
</div>
And to make the function even shorter, you could just do:
function getLi(depth) {
return document.getElementById("sideNavigation").getElementsByTagName("li")[depth];
}
That should work. :)
I am trying to build a kiosk on a local machine only. I'm planning to use JavaScript to make the menu lists functional. Here is my html code example.
<ul class="sf-menu">
<li class="current">
Area1
<ul>
<li>
John's Store
</li>
<li class="current">
Katy's store
<ul>
<li class="current">Orange</li>
<li>Watermelon</li>
<li>Apple</li>
</ul>
</li>
<li>
Catherine's Store
<ul>
<li>Banana</li>
<li>Pear</li>
<li>Cherry</li>
</ul>
</li>
</ul>
</li>
<li>
Area2
<ul>
<li>
Peter
<ul>
<li>Apple</li>
<li>Rockmelon</li>
</ul>
</li>
<li>
Lynda
<ul>
<li>Strawberry</li>
<li>Jackfruit</li>
<li>Orange</li>
</ul>
</li>
</ul>
</li> <!--current-->
</ul> <!--sf-menu-->
The person who is going to update/change the menu(which is going to be massive) is going to use a simple text file eg notepad - .txt (for certain reasons). Is there any way to update the menu items with a simple text file? Can I use a JavaScript or jQuery plugin/code?
Any direction would be appreciated.
You can do this using .get:
var textFile = "SCHEME://DOMAIN/FILENAME.txt";
jQuery.get(textFile, function(textFileData) {
//Parse file and populate menu based on specs.
//textFileData will have the text
}
If you want the text back for each line you can do (assuming the names are separated by a newline):
var EachLineInTextFile= textFileData.responseText.split("\n");
for (var i = 0, len = EachLineInTextFile.length; i < len; i++)
{
//This will give you each name from here you can put the name where you want it
}
A sample would be:
<script type="text/javascript">
$(document).ready(function () {
var textFile = "http://localhost/MyDomain/Menu.txt";
jQuery.get(textFile, function (textFileData) {
var EachLineInTextFile = textFileData.responseText.split("\n");
for (var i = 0, len = EachLineInTextFile.length; i < len; i++) {
STORE_TO_REPLACE = EachLineInTextFile[i];
//STORE_TO_REPLACE: I would have to the entire format of your file to do this.
}
})
});
</script>
From here, if you need help replacing the values in your list take a look at this article
Or, if you want to replace them all you can use .each to iterate through your list.