I have an unordered list, each element of which I want to put in an array.
<div id='main'>
<ul>
<li>First</li>
<li>Second</li>
</ul>
</div>
I need to transfer it to JSON object like this:
"type": "list",
"data": ["* First", "* Second"]
For now, i have function which return all data from list in string:
let newObj = document.createElement("div");
newObj.innerHTML = document.getElementsByTagName('UL')[0].innerHTML;
[...newObj.querySelectorAll("li")].forEach(ele => ele.parentNode.replaceChild(document.createTextNode("* "+ele.textContent)),ele);
return newObj
You can select all of the li. Then map it getting textContent and adding * as prefix
const items = document.querySelectorAll('#main li');
const result = {
type: 'list',
data: Array.from(items).map(el => `* ${el.textContent}`),
}
console.log(result)
<div id="main">
<ul>
<li>First</li>
<li>Second</li>
</ul>
</div>
You can use jquery:
let $li = $('#main').find('li') //returns a collection
let array = $.map($li, e => '* ' + e.textContent)
Converting to JSON:
let toJson = JSON.stringify(array)
Related
I need to concatenate all the title value starting from second li elements with Javascript.
The problem is that I want to use it in different pages, so I can't know the exact number of li elements.
<div id="breadcrumb">
<ul>
<li title="One">One</li>
<li title="Two">Two</li>
<li title="Three">Three</li>
<li title="Four">Four</li>
</ul>
</div>
I use a variable for each element but if one or more element is missing the var is not valid and the concat function doesn't work.
var a = document.querySelector(".breadcrumb li:nth-child(2) > a").getAttribute("title");
var b = document.querySelector(".breadcrumb li:nth-child(3) > a").getAttribute("title");
var c = document.querySelector(".breadcrumb li:nth-child(4) > a").getAttribute("title");
var d = document.querySelector(".breadcrumb li:nth-child(4) > a").getAttribute("title");
var str = a.concat(b,c,d);
console.log(str)
Is there a way to do that?
Use querySelectorAll() and map():
const res = [...document.querySelectorAll("#breadcrumb li:not(:first-of-type)")].map(el => el.getAttribute("title")).join(" ")
console.log(res)
<div id="breadcrumb">
<ul>
<li title="One">One</li>
<li title="Two">Two</li>
<li title="Three">Three</li>
<li title="Four">Four</li>
</ul>
</div>
Using a little jquery i achieved this and it should solve your issues.
let list = [];
$('#breadcrumb li').each(function(i){
if(i !== 0) { list.push($(this).attr('title')); }
});
list.toString() //One,Two,Three,Four
The method you tried to use wont scale on a large list
Two minor remarks:
If you want to access the id=breadcrumb, you have to use #breadcrumb instead of .breadcrumb
There is no a tag in your HTML-code, therefore your querySelector won't give you any result
However, let's discuss a solution:
let listElements = document.querySelectorAll("#breadcrumbs li"); // get all list elements
listElements = Array.from(listElements); // convert the NodeList to an Array
listElements = listElements.filter((value, index) => index >= 1); // remove the first element
let titleAttributes = listElements.map(listElement => listElement.getAttribute("title")); // get the title attributes for every list elements. The result is an array of strings containing the title
console.log(titleAttributes.join(", ")); // concatenate the titles by comma
You can write the above statements in a single line:
Array.from(document.querySelectorAll("#breadcrumbs li"))
.filter((value, index) => index >= 1)
.map(listElement => listElement.getAttribute("title"))
.join(", ");
EDIT: I fix my answer, thanks to Barmar
something like that ?
const All_LI = [...document.querySelectorAll('#breadcrumb li')];
let a = ''
for (let i=1; i<All_LI.length; i++) { a += All_LI[i].title }
console.log('a-> ', a )
// .. or :
const b = All_LI.reduce((a,e,i)=>a+=(i>0)?e.title:'', '' )
console.log('b-> ', b )
<div id="breadcrumb">
<ul>
<li title="One">One</li>
<li title="Two">Two</li>
<li title="Three">Three</li>
<li title="Four">Four</li>
</ul>
</div>
I have a function which is triggered on by the click of an update button. When the button is clicked all the elements in a list from a particular div are captured. Each list has about 3 to 4 data attributes. I want create an array in jquery or javascript where the created array is grouped by certain data attributes. Below is the function am using
<div>
<ul id="listDiv" >
<li style="" id="id1" data-type="edit" data-seq="1" data-name="name1">Name1</li>
<li style="" id="id2" data-type="edit" data-seq="2" data-name="name2">Name2</li>
<li style="" id="id3" data-type="create" data-seq="3" data-name="name3">Name3</li>
</ul>
</div>
<a class='upBtn' > Update </a>
$('.upBtn').on('click', function(){
var data = [];
$('#lisDiv li').each(function() {
var id = $(this).attr('id');
var type = $(this).attr('data-type');
data[type]= [];
data[type][id] = [];
data[type][id]['type'] = $(this).attr('data-type');
data[type][id]['seq'] = $(this).attr('data-sequence');
data[type][id]['name'] = $(this).attr('data-name');
});
console.log(data);
})
I tried using push as much as possible. But I am not getting the result I intended. I want the result to be like the format, below:
[edit] => [id1] => ('type') => 'edit',
('seq') => 2,
('name') => 'name1'
[id2] => ('type') => 'edit',
('seq') => 1,
('name') => 'name2'
[create] => [id3] => ('type') => 'edit',
('seq') => 3,
('name') => 'name3'
[id4] => ('type') => 'edit',
('seq') => 4,
('name') => 'name4
'
But whenever I try the array is not getting pushed. I am not sure how to use push here. Any help is highly appreciated.
You need to take objects instead of arrays.
By taking array, you get still the properties, but you can neither see them with console.log, nor stringify them, because an array is stringified with the numerical (positive 32 bit integer) indices.
var data = {};
// ...
data[type] = data[type] || {};
data[type][id] = {};
In your code, you have the wrong identifier, it should be listDev and you need to use a default value for assigning the type.
$('.upBtn').on('click', function() {
var data = {};
$('#listDiv li').each(function() { // listDiv spelling
var id = $(this).attr('id'),
type = $(this).attr('data-type');
data[type] = data[type] || {}; // prevent overwriting the object
data[type][id] = {
type: $(this).attr('data-type'),
seq: $(this).attr('data-seq'), // seq instead of sequence
name: $(this).attr('data-name')
};
});
console.log(data);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
<ul id="listDiv">
<li style="" id="id1" data-type="edit" data-seq="1" data-name="name1">Name1</li>
<li style="" id="id2" data-type="edit" data-seq="2" data-name="name2">Name2</li>
<li style="" id="id3" data-type="create" data-seq="3" data-name="name3">Name3</li>
</ul>
</div>
<a class='upBtn'>Update</a>
I'm trying to convert something like this HTML snippet:
<ul>
<li><span>Frank</span><img src="pic.jpg"></li>
<li><span>Steve</span><img src="pic2.jpg"></li>
</ul>
into a JavaScript objects that contain the name and the image's url. How can I do that?
Use map() method
var res = $('ul li').map(function() { // select all li and iterate
// return as required format of array elemnt
return {
name: $('span', this).text(), // get text in span
src: $('img', this).attr('src') // get src attribute
}
}).get(); // get array from jquery object
console.log(res);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<ul>
<li><span>Frank</span>
<img src="pic.jpg">
</li>
<li><span>Steve</span>
<img src="pic2.jpg">
</li>
</ul>
UPDATE : If you want to generate an object which has key as span text and value as src attribute then use each() method and iterate over elements and generate object.
var res = {};
$('ul li').each(function() { // select all li and iterate
res[$('span', this).text().trim()] = $('img', this).attr('src');
})
console.log(res);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<ul>
<li><span>Frank</span>
<img src="pic.jpg">
</li>
<li><span>Steve</span>
<img src="pic2.jpg">
</li>
</ul>
var objs = document.querySelectorAll('.to-js-obj li');
var objs_arr = [];
if (objs) {
for (var i = 0; i < objs.length; i++) {
var name = objs[i].querySelector('span').innerText;
var url = objs[i].querySelector('img').src;
objs_arr.push({
name: name,
src: url
});
}
console.log(JSON.stringify(objs_arr));
}
<ul class="to-js-obj">
<li><span>Frank</span>
<img src="pic.jpg">
</li>
<li><span>Steve</span>
<img src="pic2.jpg">
</li>
</ul>
Using jQuery
var $list = $('ul'), // get the list (ideally, add an ID)
$listItems = $list.find('li'); // find list items
if( $listItems.length > 0 ) { // if list items exist
var images = []; // create empty array to store objects
$.each( $listItems, function( index ) { // loop through the list items
var $item = $( $listItems[index] ); // save item as jQuery element
var name = $item.find('span').text(); // Get name from span
var imageSrc = $item.find('img').attr('src'); // Get img src
images[index] = {}; // Create new object in array
images[index].name = name; // Add name
images[index].imageSrc = imageSrc; // Add source
});
}
Returns
[Object {
imageSrc: "pic.jpg",
name: "Frank"
}, Object {
imageSrc: "pic2.jpg",
name: "Steve"
}]
You can use this:
var image_pairs = [];
$("ul li").each(function() {
image_pairs.push({
name: $(this).find("span").text(),
url: $(this).find("img").attr("src")
});
});
console.log(image_pairs);
<ul>
<li><span>Frank</span><img src="pic.jpg"></li>
<li><span>Steve</span><img src="pic2.jpg"></li>
</ul>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<ul id='parent_of_all'>
<li>
<span class='operator'>&&</span>
<ul>
<li>
<span class='operator'>||</span>
<ul>
<li>
<span class='operator'>&&</span>
<ul>
<li>
<span class='condition'>1 == 1</span>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<ul>
<li>
<span class='condition'>1 != 0</span>
</li>
</ul>
</li>
</ul>
to
{"&&":[{'||':[ {'&&':[ {"lhs": "1", "comparator": "==", "rhs":"1"} ]} ] } , {"lhs": "1", "comparator": "!=", "rhs":"0"}]}
As of now, I know the basics of jQuery, JavaScript. I need to know where to start thinking in order to accomplish the above conversion.
And the html tree could be more complex with more children.
You can do this with each and map
var obj = {}
var span = $('li > span').not('ul li span').text();
$('ul li span').each(function() {
var text = $(this).text().split(' ');
obj[span] = (obj[span]||[]).concat({lhs: text[0], comparator: text[1], rhs: text[2]});
});
console.log(obj)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<li>
<span>&&</span>
<ul>
<li>
<span>1 == 1</span>
</li>
</ul>
<ul>
<li>
<span>1 != 0</span>
</li>
</ul>
</li>
You will need a way to select the first level of li, I assumed you have a parent element with an id such as list. I wrote the following code using basic jquery so you can understand it.
var result = {};
var $all_li = $('#list').children('li'); // selecting the first level of li
for(var i in $all_li){ // iterating all_li using for (you may use forEach )
var $current_li = $( $all_li[i] ); // getting operator from first span
var operator = $current_li.children('span').html(); // the text of the operator
var $inner_spans = $current_li.find('>ul >li >span'); // getting list of children spans (from path $list>li>ul>li>span)
var li_spans = []; // an array where we will put the inner span objects
for(var j in $inner_spans){ // iterating the inner spans
var text = $($inner_spans[j]).html().split(" "); // splitting the html
li_spans.push({
lhs: text[0],
comparator: text[1],
rhs: text[2]
}); // adding the splitted html to an object. Note: error if text didn't have 2 white spaces
}
result[operator] = li_spans; // adding the operator key and li_spans value to the result json
}
This code will parse the html and construct the result json, it should work for the html format you provided. Keep in mind that it does not handle errors (such as bad tree format).
simmiar html formats.
Thanks #Alexandru and #Nenad for giving a start. I have been able to complete this on my own.
Below is the function that generates json.
function prepare_json(current_node){
var object = {}
var span = $(current_node).children('span')
if (span.hasClass('condition')){
var text = span.html().split(" ");
object = {lhs: text[0], comparator: text[1], rhs: text[2]}
}
else if(span.hasClass('operator')){
var operator = span.text()
object[operator] = (object[operator] || [])
var children = $(current_node).children('ul').children('li')
for(var i = 0; i < children.length; i++){
var child_pql = prepare_json([children[i]])
object[operator].push(child_pql)
}
}
return object
}
Below is the code that calls that function:
var parent_node = $('#parent_of_all').children('li')
var json = JSON.stringify(prepare_pql_json(parent_node), null, 2)
I have to embed some tracking code on my site. So I have a list of LI elements with an ID value that I want to place inside an array of the snippet. They should be numeric like, 123, 456, etc inside an object. I want to do it in pure JavaScript.
This is my code I have tried. My HTML:
<ul id="itemGrid">
<li class="item" id="1080"> product code </li>
<li class="item" id="1487"> product code </li>
<li class="item" id="1488"> product code </li>
...
</ul>
This is the JavaScript code
// Get all LI items and get the ID of them in the object viewList
var catId = document.getElementById('itemGrid').getElementsByTagName('li');
window.criteo_q = window.criteo_q || [];
window.criteo_q.push(
// SHOULD BE LIKE THIS
// { event: "viewList", item: ["First item id", "Second item id", "Third item id"] }
// My actual code
{ event: "viewList", item: [ catId[].id ] }
);
try this
var lis = document.getElementById('itemGrid').getElementsByTagName('li');
var idArray = [];
for ( var counter = 0; counter < lis.length; counter++)
{
idArray.push( lis[ counter ].id );
}
console.log( idArray );
You can use querySelectorAll to select all the matching elements passed as selector.
The selector '#itemGrid li[id]' will select all the <li> elements inside #itemGrid element having id attribute on it.
The querySelectorAll returns a collection of HTML elements. Iterate over this collection to get the individual element id.
var lis = document.querySelectorAll('#itemGrid li[id]');
var arr = [];
for (var i = 0; i < lis.length; i++) {
arr.push(+lis[i].id);
}
console.log(arr);
document.write('<pre>' + JSON.stringify(arr, 0, 4) + '</pre>');
<ul id="itemGrid">
<li class="item" id="1080">1080</li>
<li class="item" id="1487">1487</li>
<li class="item" id="1488">1488</li>
</ul>
<hr />
You can convert your HTMLCollection to an Array by passing it through slice, and you can then map that array:
catId = Array.prototype.slice.call(catId).map(function(li) { return li.id; });
var catId = document.getElementById('itemGrid').getElementsByTagName('li');
catId = Array.prototype.slice.call(catId).map(function(li) { return li.id; });
document.write(catId);
<ul id="itemGrid">
<li class="item" id="1080"> product code </li>
<li class="item" id="1487"> product code </li>
<li class="item" id="1488"> product code </li>
</ul>
var lis = document.getElementById('itemGrid').getElementsByTagName('li');
var arr = [];
// You need to iterate the list lis
[].forEach.call( lis, function(el){
arr.push( el.id );
});
// Making the object you want
var criteo_q = { event: "viewList", item: arr };
console.log(criteo_q);
To iterate the list of DOM elements, you can also use