Why I cant create in DOM anchor element? - javascript

I have this javascrpt code:
for (var data in feature.data) {
if (!shownParameters[data]) continue;
var xmlString = "<a href='www.cnn.com'>Link</a>"
var elem = $.parseHTML(xmlString);
var item = $("<li>", { style: 'padding:0px;text-align:right' })
.append($('<div>')
.append($("<span>", { text: elem }).addClass("view"))
.addClass("feature-data-value"))
.append($("<div>").addClass("clear-div"));
item.appendTo('#wfs-details-list');
}
In code above I try want to create anchor link DOM element.
But in the view I get this:
Here how it looks in the view:
Any idea why I cant create in the DOM anchor link elelment?

actually, this is not true way, but resolve your issue..
for (var data in feature.data) {
if (!shownParameters[data]) continue;
var xmlString = "<a href='http://www.cnn.com'>Link</a>";
var item = $("<li>", {style: 'padding:0px;text-align:right'})
.append($('<div>').append($("<span>").append(xmlString)).addClass("view"))
.addClass("feature-data-value")
.append($("<div>").addClass("clear-div"));
item.appendTo('#wfs-details-list');
}

If you are aiming to create this:
<ul id="wfs-details-list">
<li style="padding:0px;text-align:right" class="feature-data-value">
<div class="view"><span>Link</span>
</div>
<div class="clear-div"></div>
</li>
</ul>
then this is clearer but not shorter
for (var data in feature.data) {
if (!shownParameters[data]) continue;
$("<li>", {
style: 'padding:0px;text-align:right', // belongs in a class
class: "feature-data-value"
})
.append(
$('<div>', {
class: "view"
})
.append(
$("<span/>").append(
$("<a/>", {
href: "http://www.cnn.com",
text: "Link"
})
)
)
)
.append($("<div/>", {
class: "clear-div"
}))
.appendTo('#wfs-details-list');
}

Related

How to loop through HTML elements and populate a Json-object?

I'm looping through all the html tags in an html-file, checking if those tags match conditions, and trying to compose a JSON-object of a following schema:
[
{ title: 'abc', date: '10.10.10', body: ' P tags here', href: '' },
{ title: 'abc', date: '10.10.10', body: ' P tags here', href: '' },
{ title: 'abc', date: '10.10.10', body: ' P tags here', href: '' }
]
But I'd like to create the new entry only for elements, classed "header", all the other elements have to be added to earlier created entry. How do I achieve that?
Current code:
$('*').each((index, element) => {
if ( $(element).hasClass( "header" ) ) {
jsonObject.push({
title: $(element).text()
});
};
if( $(element).hasClass( "date" )) {
jsonObject.push({
date: $(element).text()
});
}
//links.push($(element))
});
console.log(jsonObject)
Result is:
{
title: 'TestA'
},
{ date: '10.10.10' },
{
title: 'TestB'
},
{ date: '10.10.11' }
I'd like it to be at this stage something like:
{
title: 'TestA'
,
date: '10.10.10' },
{
title: 'TestB'
,
date: '10.10.11' }
UPD:
Here's the example of HTML file:
<h1 class="header">H1_Header</h1>
<h2 class="date">Date</h2>
<p>A.</p>
<p>B.</p>
<p>С.</p>
<p>D.</p>
<a class="source">http://</a>
<h1 class="header">H1_Header2</h1>
<h2 class="date">Date2</h2>
<p>A2.</p>
<p>B2.</p>
<p>С2.</p>
<p>D2.</p>
<a class="source">http://2</a>
Thank you for your time!
Based on your example Html, it appears everything you are trying to collect is in a linear order, so you get a title, date, body and link then a new header with the associated items you want to collect, since this appears to not have the complication of having things being ordered in a non-linear fasion, you could do something like the following:
let jsonObject = null;
let newObject = false;
let appendParagraph = false;
let jObjects = [];
$('*').each((index, element) => {
if ($(element).hasClass("header")) {
//If newObject is true, push object into array
if(newObject)
jObjects.push(jsonObject);
//Reset the json object variable to an empty object
jsonObject = {};
//Reset the paragraph append boolean
appendParagraph = false;
//Set the header property
jsonObject.header = $(element).text();
//Set the boolean so on the next encounter of header tag the jsobObject is pushed into the array
newObject = true;
};
if( $(element).hasClass( "date" )) {
jsonObject.date = $(element).text();
}
if( $(element).prop("tagName") === "P") {
//If you are storing paragraph as one string value
//Otherwise switch the body var to an array and push instead of append
if(!appendParagraph){ //Use boolean to know if this is the first p element of object
jsonObject.body = $(element).text();
appendParagraph = true; //Set boolean to true to append on next p and subsequent p elements
} else {
jsonObject.body += (", " + $(element).text()); //append to the body
}
}
//Add the href property
if( $(element).hasClass("source")) {
//edit to do what you wanted here, based on your comment:
jsonObject.link = $(element).next().html();
//jsonObject.href= $(element).attr('href');
}
});
//Push final object into array
jObjects.push(jsonObject);
console.log(jObjects);
Here is a jsfiddle for this: https://jsfiddle.net/Lyojx85e/
I can't get the text of the anchor tags on the fiddle (I believe because nested anchor tags are not valid and will be parsed as seperate anchor tags by the browser), but the code provided should work in a real world example. If .text() doesn't work you can switch it to .html() on the link, I was confused on what you are trying to get on this one, so I updated the answer to get the href attribute of the link as it appears that is what you want. The thing is that the anchor with the class doesn't have an href attribute, so I'll leave it to you to fix that part for yourself, but this answer should give you what you need.
$('*').each((index, element) => {
var obj = {};
if ( $(element).hasClass( "header" ) ) {
obj.title = $(element).text();
};
if( $(element).hasClass( "date" )) {
obj.date = $(element).text()
}
jsonObject.push(obj);
});
I don't know about jQuery, but with JavaScript you can do with something like this.
const arr = [];
document.querySelectorAll("li").forEach((elem) => {
const obj = {};
const title = elem.querySelector("h2");
const date = elem.querySelector("date");
if (title) obj["title"] = title.textContent;
if (date) obj["date"] = date.textContent;
arr.push(obj);
});
console.log(arr);
<ul>
<li>
<h2>A</h2>
<date>1</date>
</li>
<li>
<h2>B</h2>
</li>
<li>
<date>3</date>
</li>
</ul>
Always use map for things like this. This should look something like:
let objects = $('.header').get().map(el => {
return {
date: $(el).attr('date'),
title: $(el).attr('title'),
}
})

Convert list of HTML element into Javascript list of object

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>

Create ul li dynamically using jquery

I am trying to create dynamic ul and li tags with <a> inside it. I am getting firstName is not defined error.
FIDDLE
var sData= [];
var temp = {
"firstName": 'Steve',
"route": 'url'
};
sData.push(temp);
console.log(sData);
var cList = $('ul#sParts');
$.each(sData, function(i) {
var li = $('<li/>')
.appendTo(cList);
var aaa = $('<a/>')
.text(firstName[i])
.href(route[i])
.appendTo(li);
});
<div class="row">
<ul id="sParts">
</ul>
</div>
'firstName' or 'route' are properties of supercededData. So you need to define them as a part of the array.
$.each(supercededData, function(i) {
var li = $('<li/>')
.appendTo(cList);
var aaa = $('<a/>', {
text : supercededData[i].firstName,
href : supercededData[i].route })
.appendTo(li);
});
Working example : https://jsfiddle.net/rwgoxLg2/2/

javascript, nested for loop issue

I have an assignment for school where we have to make random edits to a webpage using only javascript, no jquery or css is allowed for the edits. I'm looking to reverse the order of the nav bar, for example change
home about contact
to
contact about home
because they are links I had to change the href as well, but I have made a silly mistake somewhere because it is changing everything to home (the the text to "home" and the href to the href i want to use for "home") so I think the problem must be my second for loop or else in the loop, I just can't see where, so any help would be much appreciated!
var navIds = ["hHome", "hAbout", "hPlants", "hGarden", "hNews", "hArticle", "hContact"];
var navHref = ["index.html", "about.html", "plants.html", "garden.html", "news.html", "article.html", "contact.html"];
var navText = ["home", "about", "plants", "garden", "news", "article", "contact"];
function changeNav()
{
for(var i=0; i<navIds.length; i++)
{
for(var j=navHref.length; j>=0; j= j-1)
{
var x = document.getElementById(navIds[i]);
var y = navHref[j];
x.setAttribute("href", y);
x.textContent = navText[j];
}
}
}
the vars are just arrays where i stored the ids for what i want to change and the hrefs i want to use and the text i want them to display.
thanks in advance if you can help!!
the html is just a from a free template and isn't mine bar adding an id to the links,
<div id="header">
<img src="images/logo.png" alt="Logo">
<ul>
<li>
<a id="hHome" href="index.html">Home</a>
</li>
<li>
<a id="hAbout" href="about.html">About</a>
</li>
<li>
<a id="hPlants" href="plants.html">Plants</a>
</li>
<li>
<a id="hGarden" href="gardens.html">Gardens</a>
</li>
<li class="current">
<a id="hNews" href="news.html">News</a>
<ul>
<li class="current">
<a id="hArticle" href="article.html">Article</a>
</li>
</ul>
</li>
<li>
<a id="hContact" href="contact.html">Contact</a>
</li>
</ul>
</div>
<div id="partA">
<input type="submit" value="PartA" onclick="linkA()"/>
<input type="submit" value="PartB" onclick="linkB()"/>
</div>
You can handle that in one single for-loop..
Maybe you should have a look on the For-In Loop -> https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Statements/for...in
Heres what i come up with:
for(navs in navIds){
var html = '<a id="' + navIds[navs] + '" href="' + navHref[navs] + '">' + navText[navs] + '</a>';
document.body.insertAdjacentHTML('afterend',html);
}
You can try it here: http://jsfiddle.net/1tLkz9o2/
As promised, here is how I would approach this problem.
First, condense the multiple arrays into a single array containing nav objects.
var navElementData = [
{ id: "hHome" , href: "index.html" , text: "home" },
{ id: "hAbout" , href: "about.html" , text: "about" },
{ id: "hPlants" , href: "plants.html" , text: "plants" },
{ id: "hGarden" , href: "garden.html" , text: "garden" },
{ id: "hNews" , href: "news.html" , text: "news" },
{ id: "hArticle", href: "article.html", text: "article" },
{ id: "hContact", href: "contact.html", text: "contact" }
];
This way, it is clear that each object in the array relates to a single menu item and makes the reversal process easier.
Below I've provided the full working implementation that I will reference.
We now need a function that will actually do the rendering of a single element. I've named it getNavElement.
To render these elements to the document, I've created a new generic function named renderNav that takes in a container (e.g. a div), and some data navElementData.
Finally, I've created a simple function that wraps this renderNav function named renderReverseNav that simply reverses the data before calling renderNav.
You can view the working example below. Let me know if you have any questions.
http://jsbin.com/molimawicu/1/edit?html,js,output
// Create a new nav element
function getNavElement(id, href, text) {
var element = document.createElement('a');
element.id = id;
element.href = href;
element.textContent = text;
element.setAttribute('style', 'margin: 5px');
return element;
}
// Render the nav element
function renderNav(container, navElementData) {
// Clear the existing container
container.innerHTML = '';
// Map over the data given
navElementData.map(function(data) {
// Create a new element
var element = getNavElement(data.id, data.href, data.text);
// Append it to the container
container.appendChild(element);
});
}
function renderReverseNav(container, navElementData) {
return renderNav(container, navElementData.reverse());
}
// --- usage ---
var navElementData = [
{ id: "hHome" , href: "index.html" , text: "home" },
{ id: "hAbout" , href: "about.html" , text: "about" },
{ id: "hPlants" , href: "plants.html" , text: "plants" },
{ id: "hGarden" , href: "garden.html" , text: "garden" },
{ id: "hNews" , href: "news.html" , text: "news" },
{ id: "hArticle", href: "article.html", text: "article" },
{ id: "hContact", href: "contact.html", text: "contact" }
];
var navContainer = document.getElementById('navContainer');
var revNavContainer = document.getElementById('revNavContainer');
renderNav(navContainer, navElementData);
renderReverseNav(revNavContainer, navElementData);
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<body>
<div id="navContainer"></div>
<div id="revNavContainer"></div>
</body>
</html>

What is the best way in jQuery to wrap elements based on its data attribute?

Given the following structure:
<ul>
<li data-conference="Conference1" >Spain</li>
<li data-conference="Conference1" >France</li>
<li data-conference="Conference1" >Germany</li>
<li data-conference="Conference1" >Italy</li>
<li data-conference="Conference2" >Austria</li>
<li data-conference="Conference2" >Poland</li>
<li data-conference="Conference3" >Russia</li>
<li data-conference="Conference3" >USA</li>
<li data-conference="Conference3" >China</li>
</ul>
what is the best way (with jQuery), considering performance, to rearrange this into this:
<ul>
<li>Spain</li>
<li>France</li>
<li>Germany</li>
<li>Italy</li>
</ul>
<ul>
<li>Austria</li>
<li>Poland</li>
</ul>
<ul>
<li>Russia</li>
<li>USA</li>
<li>China</li>
</ul>
Thanks!
I think the overall question (group elements by attribute) is good, you just should have put more effort into trying to solve it yourself.
Anyways, grouping elements by an attribute is quite simple. You can create an attribute value -> [element, ...] map, which can be done with an object:
var groups = {};
$('li[data-city]').each(function() {
var attr = $(this).attr('data-city'),
group = groups[attr];
if(!group) {
group = groups[attr] = [];
}
group.push(this);
});
Now you have a collection of lists of DOM elements. You can iterate over the collection and create the HTML lists accordingly.
For example:
for(var group in groups) {
var $list = $('<ul />');
$list.append(groups[group]);
// now append $list somewhere
}
Have a look at Working with Objects [MDN] to get more information about how to process objects.
It's also trivial to do this without jQuery, as long as you have references to the elements, for example as a NodeList. Instead of using .each you can then use a "normal" for loop to iterate that list.
Unless you have a insane amount of cities in those lists I wouldn't worry about performance. The only performance consideration I would take is to avoid repaint / reflows by minimizing writing to the DOM. I think code clarity is much more important in this use case.
That being said I'd implement this with something like this - http://jsfiddle.net/XWufy/.
Here you go:
(function () {
var $list = $( '#list' );
var lists = {};
var $newLists = $();
$list.children().each( function () {
var city = $( this ).data( 'city' );
if ( !lists[ city ] ) lists[ city ] = [];
lists[ city ].push( this );
});
$.each( lists, function ( city, items ) {
var $newList = $( '<ul />' ).append( items );
$newLists = $newLists.add( $newList );
});
$list.replaceWith( $newLists );
}());
Live demo: http://jsfiddle.net/rjt9W/6/
Btw, the code assumes that the list has an ID of "list". Replace the selector in this line
var $list = $( ... );
so that it properly selects your UL element.
Use the data attribute as an object property to sort them, then loop over them to construct the new html. this should get you started:
var list = {};
// for each item
list[item.data('city')] = item.text();
// for each property of list
var ul = $('<ul>');
// for each listItem in current list
var li = $('<li>').text(listItem);
ul.append(li);
try this:
<ul id="first"></ul>// you can create the ul tags by using JavaScript
$("li").each(function(){
data = $(this).attr("data");
if (data == "Conference1") {
txt = $(this).text();
$("<li>" + txt + "</li>").appendTo("ul#first");
}
})
Try this:
var list = [];
var $div = $('#my_container_div');
$('li[data-city]').each(function() {
var $this = $(this), data = $this.attr('data-city');
list[ data ] = list[ data ] || [];
list[ data ].push( $this.text() );
});
for(var data in list) {
var $ul = $div.append('<ul/>');
for(var li in list[data]) {
$ul.append('<li>' + list[data][li] + '</li>');
}
}

Categories