I generate with a loop for every section on my html site a list element.
<section class="page1" id="name1"></section>
<section class="page2" id="name2"></section>
<section class="page3" id="name3"></section>`
In my jQuery function, see below, I create for every section a link.
for( var i = 0; i < sections.length; i++){
_addClass(sections[i], "ops-section")
sections[i].dataset.index = i + 1;
sections[i].id=document.getElementById(sections[i].id);
if(settings.pagination == true) {
paginationList += '<li><a data-index="'
+ (i + 1) + '" href="#' + (i + 1)
+ '"></a><p class="lead">'
+ sections[i].id + '</p></li>';
}
with sections[i].id=document.getElementById(sections[i].id); I want to read out the text behind id, for example: name1. name2, name3 and so on. I want to add the id-name then as text between the p-tag, so that I get the following list element:
<li><a data-index="1" href="#1" class="active"></a><p class="lead">name1</p></li>
but actually I get this:
<li><a data-index="1" href="#1" class="active"></a><p class="lead">[object HTMLElement]</p></li>
Where is my mistake? What's wrong?
I think you are going about this the wrong way and making the code harder to follow in the process. Your issue is that you are concatenating an entire DOM node, rather than a value of one of the attributes of that node because of this line:
sections[i].id = document.getElementById(sections[i].id)
.getElementById() returns a DOM node so later, when you use:
sections[i].id
You aren't referring to the id at all, you are referring to the entire element returned from:
document.getElementById(sections[i].id)
You don't really even need any of that entire line anyway.
If you use a .forEach() loop to enumerate the section elements, you won't have to set up or manage a counter.
If you create the elements via the DOM API (instead of building a string), you can configure each element much more simply and get out of concatenation hell.
Look at the solution below, it's a little more overall code than your solution, but it is so much cleaner and easier to follow.
// Get the section elements into an array
var theSections = Array.prototype.slice.call(document.querySelectorAll("section[class^='page']"));
// Loop over the elements in the array
theSections.forEach(function(section, index){
// Create li, a and p elements
var li = document.createElement("li");
var a = document.createElement("a");
var p = document.createElement("p");
// Configure each new element
a.setAttribute("data-index", index + 1);
a.href = index + 1;
a.classList.add("active");
p.classList.add("lead");
p.textContent = section.id;
// Inject new elements into the DOM
li.appendChild(a);
li.appendChild(p);
document.body.appendChild(li);
// Just for testing
console.log(a, p);
});
<section class="page1" id="name1"></section>
<section class="page2" id="name2"></section>
<section class="page3" id="name3"></section>
Why is it not working?
First, document.getElementById retrieves an HTML element. Then, you are overriding the id in sections[i].id with the HTML element, resulting in [object HTMLElement].
Solution
As suggested by Liora Haydont, simply remove the line sections[i].id=document.getElementById(sections[i].id);.
for( var i = 0; i < sections.length; i++){
_addClass(sections[i], "ops-section")
sections[i].dataset.index = i + 1;
if(settings.pagination == true) {
paginationList += '<li><a data-index="'
+ (i + 1) + '" href="#' + (i + 1)
+ '"></a><p class="lead">'
+ sections[i].id + '</p></li>';
}
In your code you're attaching an entire HTML element to the section id which is why you're getting that error. Scott just beat me with his answer, but I'm in agreement with him. Using forEach will allow you to make your life a little easier.
In this example I'm also using template literals to create the HTML. YMMV, however.
const sections = document.querySelectorAll('section');
const out = document.getElementById('out');
const settings = {
pagination: true
}
sections.forEach((section, i) => {
const index = i + 1;
const id = section.id;
section.classList.add('ops-section');
section.dataset.index = index;
if (settings.pagination) {
const para = `<p class="lead">${id}</p>`;
const li = `<li><a data-index="${index}" href="#${index}" class="active">test</a>${para}</li>`;
out.insertAdjacentHTML('beforeend', li);
}
});
<section class="page1" id="name1">section1</section>
<section class="page2" id="name2">section2</section>
<section class="page3" id="name3">section3</section>
<ul id="out"></ul>
Why not using JQuery ? This is a small demo on how you can get the id attribute of your section and use it in the JQuery code:
$(document).ready(function() {
$('section').each(function( key, value ) {
// alert($(this).attr('id') + " - " + key + ": " + value );
$('pagination').append("<p class='lead'>* <a data-index='"+ key +"' href=#></a>" + $(this).attr('id') + '</p>');
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<section class="page1" id="name1"></section>
<section class="page2" id="name2"></section>
<section class="page3" id="name3"></section>
<pagination></pagination>
Related
I'm using jQuery to get values from ajax rest call, I'm trying to concatenate these values into an 'a' tag in order to create a pagination section for my results (picture attached).
I'm sending the HTML (divHTMLPages) but the result is not well-formed and not working, I've tried with double quotes and single but still not well-formed. So, I wonder if this is a good approach to accomplish what I need to create the pagination. The 'a' tag is going to trigger the onclick event with four parameters (query for rest call, department, row limit and the start row for display)
if (_startRow == 0) {
console.log("First page");
var currentPage = 1;
// Set Next Page
var nextPage = 2;
var startRowNextPage = _startRow + _rowLimit + 1;
var query = $('#queryU').val();
// page Link
divHTMLPages = "<strong>1</strong> ";
divHTMLPages += "<a href='#' onclick='getRESTResults(" + query + "', '" + _reg + "', " + _rowLimit + ", " + _startRow + ")>" + nextPage + "</a> ";
console.log("Next page: " + nextPage);
}
Thanks in advance for any help on this.
Pagination
Rather than trying to type out how the function should be called in an HTML string, it would be much more elegant to attach an event listener to the element in question. For example, assuming the parent element you're inserting elements into is called parent, you could do something like this:
const a = document.createElement('a');
a.href = '#';
a.textContent = nextPage;
a.onclick = () => getRESTResults(query, _reg, _rowLimit, _startRow);
parent.appendChild(a);
Once an event listener is attached, like with the onclick above, make sure not to change the innerHTML of the container (like with innerHTML += <something>), because that will corrupt any existing listeners inside the container - instead, append elements explicitly with methods like createElement and appendChild, as shown above, or use insertAdjacentHTML (which does not re-parse the whole container's contents).
$(function()
{
var query=10;
var _reg="12";
var _rowLimit="test";
var _startRow="aa";
var nextPage="testhref";
//before divHTMLPages+=,must be define divHTMLPages value
var divHTMLPages = "<a href='#' onclick=getRESTResults('"+query + "','" + _reg + "','" + _rowLimit + "','" + _startRow + "')>" + nextPage + "</a>";
///or use es6 `` Template literals
var divHTMLPages1 = `` + nextPage + ``;
$("#test").append("<div>"+divHTMLPages+"</div>");
$("#test").append("<div>"+divHTMLPages1+"</div>");
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="test"></div>
I have a function which goes through an Array and adds <h3> elements to a div. Then it adds an event listener (an onclick) to the current <h3> element, but only the last element which goes through the function is set by the onclick.
var runstr = [];
//txt comes from the content of a tab separated textfile spilt by '\n'
txt.forEach(function (lcb) { //lcb goes through each line of txt
lcb = lcb.split(" ", 30); //split the line by tab
//MainContent_Infralist is a div where the <h3> elements are listed and lcb[2] is the title
document.getElementById("MainContent_Infralist").innerHTML =
document.getElementById("MainContent_Infralist").innerHTML +
'<h3 class="Infraa" id="' + "Infralist_" + lcb[2] + '">' + lcb[2] + '</h3>';
//I put the id into an array to get the index of the marker later
runstr.push("Infralist_" + lcb[2]);
//I'm working with openlayers here i try to set the entry of
//the list.onlick to trigger a mousedown on a marker.
//And there is the problem: It works, but only for the last entry of my <h3> list...
document.getElementById("Infralist_" + lcb[2]).onclick = function () {
var theM = runstr.indexOf("Infralist_" + lcb[2]);
markers.markers[theM].events.triggerEvent('mousedown');
};
};
The problem is here:
document.getElementById("MainContent_Infralist").innerHTML =
document.getElementById("MainContent_Infralist").innerHTML +
'<h3 class="Infraa" id="' + "Infralist_" + lcb[2] + '">' + lcb[2] + '</h3>';
Every time you assign to innerHTML, you're basically deleting all stuff and adding it all over again. This causes all event listeners to break.
That's the reason why only last one works - it's the only one after assigning which there is no more innerHTML manipulation.
To fix this, create your elements using document.createElement() and append them using element.appendChild().
It could look like:
var header = document.createElement('h3');
header.id = 'Infralist_' + lcb[2];
header.className = 'Infraa';
header.textContent = lcb[2];
document.getElementById('MainContent_Infralist').appendChild(header);
header.onclick = function () {
// you function here
}
I have a string with multiple elements with id's like below:
var data = "<div id='1'></div><input type='text' id='2'/>";
Now I'm using this regex to find all the id's in the string:
var reg = /id="([^"]+)"/g;
Afterwards I want to replace all those id's with a new id. Something like this:
data = data.replace(reg, + 'id="' + reg2 + '_' + numCompare + '"');
I want reg2, as seen above, to return the value of the id's.
I'm not too familiar with Regular Expressions, so how can I go about doing this?
Instead of using regex, parse it and loop through elements. Try:
var data = "<div id='1'></div><div id='asdf'><input type='text' id='2'/></div>",
numCompare = 23,
div = document.createElement("div"),
i, cur;
div.innerHTML = data;
function updateId(parent) {
var children = parent.children;
for (i = 0; i < children.length; i++) {
cur = children[i];
if (cur.nodeType === 1 && cur.id) {
cur.id = cur.id + "_" + numCompare;
}
updateId(cur);
}
}
updateId(div);
DEMO: http://jsfiddle.net/RbuaG/3/
This checks to see if the id is set in the first place, and only then will it modify it.
Also, it is safe in case the HTML contains a comment node (where IE 6-8 does include comment nodes in .children).
Also, it walks through all children of all elements. In your example, you only had one level of elements (no nested). But in my fiddle, I nest the <input /> and it is still modified.
To get the get the updated HTML, use div.innerHTML.
With jQuery, you can try:
var data = "<div id='1'></div><div id='asdf'><input type='text' id='2'/></div>",
numCompare = 23,
div = $("<div>"),
i, cur;
div.append(data);
div.find("[id]").each(function () {
$(this).attr("id", function (index, attr) {
return attr + "_" + numCompare;
});
});
DEMO: http://jsfiddle.net/tXFwh/5/
While it's valid to have the id start with and/or be a number, you should change the id of the elements to be a normal identifier.
References:
.children: https://developer.mozilla.org/en-US/docs/DOM/Element.children
.nodeType: https://developer.mozilla.org/en-US/docs/DOM/Node.nodeType
jQuery.find(): http://api.jquery.com/find/
jQuery.attr(): http://api.jquery.com/attr/
jQuery.each(): http://api.jquery.com/each/
Try using
.replace(/id='(.*?)'/g, 'id="$1_' + numCompare + '"');
Regex probably isn't the right way to do this, here is an example that uses jQuery:
var htmlstring = "<div id='1'></div><input type='text' id='2'/>";
var $dom = $('<div>').html(htmlstring);
$('[id]', $dom).each(function() {
$(this).attr('id', $(this).attr('id') + '_' + numCompare);
});
htmlstring = $dom.html();
Example: http://jsfiddle.net/fYb3U/
Using jQuery (further to your commments).
var data = "<div id='1'></div><input type='text' id='2'/>";
var output = $("<div></div>").html(data); // Convert string to jQuery object
output.find("[id]").each(function() { // Select all elements with an ID
var target = $(this);
var id = target.attr("id"); // Get the ID
target.attr("id", id + "_" + numCompare); // Set the id
});
console.log(output.html());
This is much better than using regex on HTML (Using regular expressions to parse HTML: why not?), is faster (although can be further improved by having a more direct selector than $("[id]") such as giving the elements a class).
Fiddle: http://jsfiddle.net/georeith/E6Hn7/10/
My problem is related to jQuery and the DOM elements. I need a template like the following:
var threadreply = " <li class='replyItem'>"
+ " <div class='clearfix'>"
+ " ${tittle}"
+ " </div>"
+ " </li>"
;
$.template( "threadreply", threadreply );
As you can see, this is a list element. My problem is when I parse it with $.tmpl, which retrieves a valid DOM element without the <li> </li> tags.
liElement = liElement + $.tmpl("threadreply", {"tittle": "hello"} ).html();
Is there any way I can retrieve the element without reformatting?
I know I can do it with a template with a valid ul tag and inside an each jQuery template loop, but I'm not working with JSONs, I can't convert my data structures to JSON.
The full example is as follow:
var threadreply = " <li class='replyItem'>"
+ " <div class='clearfix'>"
+ " ${tittle}"
+ " </div>"
+ " </li>"
;
$.template( "threadreply", threadreply );
var liElement = "";
for( var i = 0; i < 150; i ++ ){
liElement = liElement + $.tmpl("threadreply", {"tittle": "hello"} ).html();
}
$(liElement).appendTo("#ULElement");
EDITED
I found a workaround with this thread: JQuery Object to String wich consists on wraping each DOM element returned by the $.tmpl in a div before get the .html() of the object:
liElement = liElement + $('<div>').append( $.tmpl("threadreply", {"tittle": "hello"} )).html();
With 300 elements it takes aprox 290ms in process all elements. With the appendTo() inside the loop, it takes more than 800ms.
you do not get the 'li' element because when you do
liElement = liElement + $.tmpl("threadreply", {"tittle": "hello"} ).html();
you get the contained html (or innerhtml) of the 'li' element.
html:
<ul id="titleList">
</ul>
js:
$.tmpl("threadreply", {"tittle": "hello"}).appendTo('#titleList');
You just need the string and not a real DOM element. Just use:
liElement = liElement + $.tmpl("threadreply", {"tittle": "hello"});
Outside the loop, you need to wrap the HTML you just generated into a new element, and then replace the former li:
$('<li />').html(liElement).replaceAll('li#existingLiID');
i want to use js this function:
i have a string[] s={"11111","2222","33333",...} how to
achieve the html body
<h2>total s.length </h2>
<p>s[0]</p>
<p>s[1]</p>
<p>s[2]</p>
because s.length and content is uncertain,so i cannot one by one print,i want to use javascript,can you tell me how,i know little about js knowledge.thank you
var arr = ["11111","2222","33333"];
var output = "<h2>total " + arr.length + "</h2>" + "<p>" + arr.join("</p><p>") + "</p>";
document.getElementById("OutputPanel").innerHTML = output;
Live demo: http://jsfiddle.net/TQSK4/
You better add the result into existing container in the document, like in the example, not write directly to the document.