I wrote a code in PHP for parsing data that I received by an API request from "wikipedia.org".
I used DOMDocument class to parse the data and it worked perfectly fine. Now I want to do the same job in JavaScript. The API request returns (after a little cleaning up) a string like this:
$htmlString = "<ul>
<li>Item 1</li>
<li>Item 2</li>
</ul>
<ul>
<li>Item 3</li>
<li>Item 4</li>
<li>Item 5</li>
</ul>"
Note that this is just an example. Any request might have different number of lists, but it is always a series of unordered lists.
I needed to get the text inside the <li> tags and the following PHP code worked perfectly fine.
$DOM = new DOMDocument;
$DOM->loadHTML($htmlString);
$lis = $DOM->getElementsByTagName('li');
$items =[];
for ($i = 0; $i < $lis->length; $i++) $items[] = $lis[$i]->nodeValue;
And I get the array [Item 1,...,Item 5] inside $items variable as I wanted.
Now I want to do the same job in JavaScript. That is I have a string
htmlString = "<ul>
<li>Item 1</li>
<li>Item 2</li>
</ul>
<ul>
<li>Item 3</li>
<li>Item 4</li>
<li>Item 5</li>
</ul>"
in JavaScript and I want to get the text inside each of the <li> tags. I searched the web for an equivalent class to PHP DOMDocument in JavaScript, and surprisingly I found nothing.
Any ideas how to do this in (preferably Vanilla) JavaScript similar to the PHP code?
If not, any idea how to do this anyway in JavaScript (even maybe with regular expressions)?
Use DOMParser()
Your ported code, which is very much the same as your PHP:
let parser = new DOMParser()
let doc = parser.parseFromString(`<ul>
<li>Item 1</li>
<li>Item 2</li>
</ul>
<ul>
<li>Item 3</li>
<li>Item 4</li>
<li>Item 5</li>
</ul>`, "text/html")
let lis = doc.getElementsByTagName('li')
let items = []
for (let i = 0; i < lis.length; i++) items.push(lis[i].textContent)
console.log(items)
If you're working strictly with strings, you want to use Regular Expressions.
FYI
I'm using ES20xx syntax. If you can't support this, you'll need to convert to the syntax you're users can access.
Here I have an expressions that captures whatever is in between opening <ul> or <li> and the closing tags. Then I use the line breaks to split the string into an array. We need to filter out empty elements from the resulting array and finally return the desired items in a final array.
var htmlString = `<ul>
<li>Item 1</li>
<li>Item 2</li>
</ul>
<ul>
<li>Item 3</li>
<li>Item 4</li>
<li>Item 5</li>
</ul>`;
var lis = htmlString.replace(/<ul>|<li>(.*)<\/li>|<\/ul>/g, '$1').split('\n');
var items = lis
.filter(item => {
if (item && item !== null && item !== '') {
return item;
}
})
.map(item => {
var element = item.replace(/\s{2,}/g, '');
return element;
});
console.log('items array.', items);
Related
How do I iteratively add children elements to a (for example) a .
<ul id="my-list">
<li>item 1</li>
<li>item 2</li>
</ul>
If I have a JS script that runs something like this several times:
document.getElementById('my-list').appendChild('someListItemICreated')
the current 2 list items are removed. How do I add new li items to the ul without losing the current list itmes?
You need to provide an element as the argument for appendChild and not a string. Like this:
const li = document.createElement("li");
li.innerText = "Item 3";
document.getElementById("my-list").appendChild(li);
<ul id="my-list">
<li>Item 1</li>
<li>Item 2</li>
</ul>
A much easier and a cleaner approach that I prefer in most of cases is:
document.getElementById("my-list").innerHTML += "<li>Item 3</li>";
<ul id="my-list">
<li>Item 1</li>
<li>Item 2</li>
</ul>
const c = document.createElement('li');
c.innerText = 'item 3';
document.getElementById('my-list').appendChild(c);
<ul id="my-list">
<li>item 1</li>
<li>item 2</li>
</ul>
I think you need to be more specific with what your code is actually doing, but I can say that someListItemICreated should not be a string, if that's what you're passing. Here's an example I made that's similar to what you're referring to that runs fine.
<ul id="my-list">
<li>Item 1</li>
<li>Item 2</li>
</ul>
let someListItemICreated = document.createElement("li");
someListItemICreated.appendChild(document.createTextNode("item 3"));
document.getElementById("my-list").appendChild(someListItemICreated)
<ul>
<li>item 1</li>
<li>item 2</li>
<li>item 3</li>
<li>item 4</li>
</ul>
<script>
document.querySelectorAll('li').forEach(e=>e.target.style.color='red');
</script>
Create a JSON like this -
let color = {'item 1':'red','item 2':'yellow','item 3':'green','item 4':'black'}
sessionStorage.setItem("textColor", JSON.stringify(color));
and when you need it then
let storeColor = JSON.parse(sessionStorage.getItem("textColor"));
document.querySelectorAll('li').forEach(function (e, i) {
e.style.color = storeColor[e.textContent];
});
First you need to get all diferent colors you want and for each one save with this
'''
let elemento_li = document.querySelectorAll('li');
elemento_li.forEach((elemento)=>{
Here you have to get the id or name of the element to use it like "key"
localStorage.setItem("key", elemento.style.color);
})'''
I have tried everything that I have found on Stack Overflow, but I cannot get this to work. Here is my code.
$(document).ready(function(){
$(".category, .submenu").mouseenter(function(){
var i = 0;
var id = "#category1" /*-- $(obj).attr("id"); */
if (id == "#category1") {i = 1};
$("#submenu" + i).toggleClass("submenuHover");
$("#category" + i).toggleClass("categoryHover");
});
$("#category1, #submenu1").mouseleave(function(){
$("#submenu1").toggleClass("submenuHover")
$("#category1").toggleClass("categoryHover");
});
$("#category2, #submenu2").mouseenter(function(){
$("#submenu2").toggleClass("submenuHover");
$("#category2").toggleClass("categoryHover");
});
$("#category2, #submenu2").mouseleave(function(){
$("#submenu2").toggleClass("submenuHover");
$("#category2").toggleClass("categoryHover");
});
});
<a id="category1" class="category" href="#">Category 1</a>
<div id="submenu1" class="submenu">
<div>
<b>Column 1</b>
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
<li>Item 5</li>
</ul>
</div>
<div>
<b>Column 2</b>
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
<li>Item 5</li>
</ul>
</div>
</div>
<a id="category2" class="category" href="#">Category 2</a>
<div id="submenu2" class="submenu">Submenu #2
<div>
<b>Column 1</b>
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
<li>Item 5</li>
</ul>
</div>
<div>
<b>Column 2</b>
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
<li>Item 5</li>
</ul>
</div>
</div>
line > var id = "#category1" /*-- $(obj).attr("id"); */
is where my problem is.
I have commented out $(obj).attr("id"); and added "#category1".
It works like this.
How do I get the id so I can condense this code into one block?
Also, this is still a work in progress so once I figure out this step I want to combine mouseenter and mouseleave to use the same value of i, and I don't know how to proceed with that part yet.
To get the id from the class that triggered the event:
$(".category, .submenu").mouseenter(function(){
var id = $(this).attr('id');
...
}
Next time make a JSFiddle but here's one I made for you, showing that it works.
https://jsfiddle.net/3yn4e0ng/
Look in the console for proof that it is getting your id.
Lastly, you're going to have issues with your comparison statements like these:
if (id == "#category1") {i = 1};
because jQuery doesn't return the (#) symbol. You're explicitely asking for the id so there's no reason for jQuery to pass back a # sign into the string, indicating that thisis an id.
Consider this instead:
if (id == "category1") {i = 1};
Note: There's no reason for you to use == over === unless your insecure about whether the id that jQuery fetches is of type string. Read this amazing post: Which equals operator (== vs ===) should be used in JavaScript comparisons?
you can do it like this:
var id = $(this).hasClass("category") ? $(this).attr("id") : $(this).closest(".submenu").prev("a").attr("id");
this is a working fiddle.
I want to store all list items of several list of the same class within an array.
for exemple:
<ul class="myList">
<li>item 1</li>
<li>item 2</li>
</ul>
<ul class="myList">
<li>item 3</li>
<li>item 4</li>
<li>item 5</li>
</ul>
Script file:
var arr_list_items = [];
$('ul.myList').each(function(){
while( !$(this).empty() ) {
list_item = $(this).find('li:first');
arr_list_items.push( list_item );
list_item.remove();
}
});
The list items are removed, but the array returns empty. Why?
var array = [];
$('.myList li').each(function(i, li) {
array.push($(li));
});
No need for any complex logic.
You can use the .get() method to retrieve an array of the elements matched by the jQuery object:
Example Here
var arr_list_items = $('.myList li').remove().get();
console.log(arr_list_items);
// [li, li, li, li, li]
Alternatively, you could also use the .map() method:
Example Here
var arr_list_items = $('.myList li').remove().map(function () {
return this;
}).get();
var arr_list_items = [];
$('ul.myList').each(function (i,n) {
$(n).find('li').each(function (j, m) {
arr_list_items.push(m);
}).remove();
});
for (var i = 0; i < arr_list_items.length; i++) {
console.info(arr_list_items[i]);
}
Because I am poor in English, so I can not explain the code,but I think you can understand it
var arr_list_items = [];
$('ul.myList').each(function(){
$(this).find('li').each(function(){
arr_list_items.push(this);
$(this).remove();
});
});
console.info(arr_list_items);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="myList">
<li>item 1</li>
<li>item 2</li>
</ul>
<ul class="myList">
<li>item 3</li>
<li>item 4</li>
<li>item 5</li>
</ul>
I have groups of unordered lists and I am trying to divide each list group into sub-groups of 3 dynamically. So far I have this:
var uls = $("ul > li");
for(var i = 0; i < uls.length; i+=3) {
uls.slice(i, i+3).wrapAll("<ul class='new'></ul>");
}
... for some sample HTML below
<h2>Group 1</h2>
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
<li>Item 5</li>
</ul>
<h2>Group 2</h2>
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
<li>Item 5</li>
<li>Item 6</li>
<li>Item 7</li>
</ul>
The issue I am having is that my code just lumps all the <ul>s together without regard to groups, i.e. 'group 1' 'group 2' I tried using .each(function() { on $("ul > li") but I just get errors. I also tried moving down the each function after .length but that did not work either.
So the final HTML would look like this:
<h2>Group 1</h2>
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
<ul>
<li>Item 4</li>
<li>Item 5</li>
</ul>
<h2>Group 2</h2>
<ul>
etc...
My fiddle is here but as you can see it's not quite working yet.
How's this? http://jsfiddle.net/4Bms6/
$('ul').each(function(){
var uls = $("li", this);
for(var i = 0; i < uls.length; i+=3) {
var lis = $("li", this);
uls.slice(i, i+3).wrapAll("<ul class='new'></ul>");
}
});
The reason you were getting incorrect grouping is because you were starting off by collecting every single li ("ul > li" equates to all li that are children of any ul). What you should have been doing is selecting all li that are children of each ul, perform the grouping, then move on to the next ul.