Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 9 years ago.
Improve this question
What is a good way to manipulating HTML controls?
By creating HTML element?
var select = document.getElementById("MyList");
var options = ["1", "2", "3", "4", "5"];
for (var i = 0; i < options.length; i++) {
var opt = options[i];
var el = document.createElement("option");
el.Text = opt;
el.value = opt;
el.innerHTML = opt;
select.appendChild(el);
}
Or by manipulating HTML:
var options = new Array(2);
options [0] = '1';
options [1] = '2';
options [0] = '<option>' + options [0] + '</option>';
options [1] = '<option>' + options [1] + '</option>';
var newHTML = '<select>' + options [0] + options [1] + '</select>';
selectList.innerHTML = newHTML;
Which one of these is a good practice? Is one preferred over other in specific conditions?
1st approach looks more modular and reusable. You may want to put the lines within for loop in a method and call that method.
Always 1st approach. if you are using innerhtml style, browser is creating itself.
The first method is better than the second one , i.e.,
**Creating an HTML element is better than manipulating the DOM"
The reason: being working with DOM can cause browser reflow.
For example : assume you need to replace an element to the DOM which already exists.
Using approach :
Creating a DOM Element : You create an element. Add verious attributes to it and replace it. The element will be added in one go and there will be only one reflow of the document.
Manipulating DOM : You need to add and remove attributes or elements one by one. This may cause the browser to trigger a reflow for all the elements and attributes that are being manipulated. This will take up valuable resources in rendering the flow of the document as the elements are manipulated.
So creating a dom element is much smoother since your browser wont have to render the flow of the document again.
*EDIT : * If you need to insert many elements then the best approach is to create a Document Fragment. The document fragment is in memory and not part of the DOM tree. Thus adding elements to it DOES NOT cause reflows. As the documentations says :
Since the document fragment is in memory and not part of the main DOM tree, appending children to it does not cause page reflow (computation of element's position and geometry). Consequently, using document fragments often results in better performance.
Related
Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 7 months ago.
Improve this question
I've searched the jQuery docs and here and can't find an answer to my exact problem...
With a DRY spirit, I want to use javascript to add a character object countdown helper to any textarea element with maxlength and aria-describedby attributes.
Obviously I also need to use javascript to monitor keyup events to update the counter. I'm using jQuery 3.6.0. However, I can't seem to get the countdown method to recognize the newly-added "helper" div element. Here's what I have so far:
$(document).ready(function () {
// "characters remaining" countdown
function textCounter(field) {
var charLimit = field.attr("maxlength");
console.log("charLimit=" + charLimit);
// hack to *double-count* '\r\n' (client/DB discrepency)
var numLines = (field.val().match(/\n/g) || []).length;
var charLength = field.val().length + numLines;
console.log("charLength=" + charLength);
var charDiff = charLimit - charLength;
console.log("charDiff=" + charDiff);
if (charLength > charLimit - numLines)
field.val(field.val().substring(0, charLimit - numLines));
var count = $("#" + field.attr("aria-describedby") + " .count");
console.log(count.html());
count.html(Math.max(0, charDiff));
}
// add countdown helper div
$("textarea[maxlength]").each(function (e) {
var helpID = "#" + $(this).attr("aria-describedby");
var helpDiv = $('<div id="' + helpID + '"><span class="count"></span> characters left.</div>')
$(this).after(helpDiv);
textCounter($(this));
})
// update counter on keyup events
$("textarea[maxlength]").keyup(function () { textCounter($(this)); })
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<textarea maxlength="2000" aria-describedby="content-help" id="content" name="content"></textarea>
I can confirm that:
The helper div element is getting added
Via the console.log statements, the textCounter() method is getting called, but the count object resolves to undefined (even though it is clearly there), and
If the element is hardcoded in HTML (i.e., not dynamically added) the counter works as expected.
Other searches suggest that .delegate() or .on() are part of the answer, but everything I've tried has the exact same behavior as above. :( Every other Q/A I've come across is, for example, binding a click/hover event to the newly-added element, but here it's the textarea that needs monitoring (not the new helper element, although it will be updated), if that makes sense...
Note that I want the solution to work on pages that have multiple textareas, each with potentially different maxlength attributes.
Any thoughts how to accomplish this?
The line:
var helpID = "#" + $(this).attr("aria-describedby");
means that your selector:
var count = $("#" + field.attr("aria-describedby") + " .count");
Should be:
var count = $("#\#" + field.attr("aria-describedby") + " .count");
Or you could simply not include the "#" character when creating the element, giving:
var helpID = $(this).attr("aria-describedby");
Unfortunately this is a typo question (so it will be closed as such), this answer exists only temporarily to clearly show the error.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
In my javascript code I need to get the definition of an element, but without its content - neither text nor children.
E.g. for:
<div id="my_example_id" class="ShinyClass">
My important text
<span> Here</span>
</div>
I would like to write a javascript fucntion that when provided with the element of the div above will return the following as string:
<div id="my_example_id" class="ShinyClass">
I have been trying with different manipulations over the elements, functions like innerHTML, outerHTML and similar, but I was unable to figure out how to fetch only the part I am interested in. Is substring until the first > the best possible solution?
EDIT: selecting the element is not part of the question - I know how to do that, no prob. Rather the question is: when I have already selected a particular element how to parse as string only its own definition.
UPDATE:
const div = document.getElementById('my_example_id'); // get the node
const html = div.outerHTML.replace(div.innerHTML || '', ''); // simple set logic
console.log(html);
Just some way to do this, not saying the best.
const div = document.getElementById('my_example_id');
const copy = div.cloneNode(true);
const parent = document.createElement('div');
copy.innerHTML = '';
parent.appendChild(copy); // I forgot to add this line.
const html = parent.innerHTML;
console.log(html);
Basically you create a copy of the div, create a parent, then remove innerHTML of the copied node to leave out just the 'div' itself. Append the copied node to the new parent and show the parent's innerHTML which is just the 'div' you wanted.
you don't need to do all that fancy stuff copying it to a parent..
// make a copy of the element
var clone = document.getElementById('my_example_id').cloneNode(true);
// empty all the contents of the copy
clone.innerHTML = "";
// get the outer html of the copy
var definition = clone.outerHTML;
console.log(definition);
I threw it in a function in this fiddle: https://jsfiddle.net/vtgx3790/1/
I guess that a Regex is what you need. Check if this works for you
function getHtml(selector) {
var element = document.querySelector(selector)
var htmlText = element.outerHTML
var start = htmlText.search(/</)
var end = htmlText.search(/>/)
return htmlText.substr(start, end + 1)
}
alert(getHtml('.ShinyClass'))
example here
console.log(getElementTag("my_example_id"));
function getElementTag(myElementId) {
var FullEelementObject = document.getElementById(myElementId);
var FullElementText = FullEelementObject.outerHTML;
var regExTag = new RegExp(/(<).*(>)/i);
openingTag = FullElementText.match(regExTag);
return openingTag[0];
}
Just threw together this JSFiddle, it gets the outerHTML of the element you pass the function, the regExp to get the full opening tag.
Edit: Here is the JSFiddle
Given a list of elements and I need to filter by some properties and add a class to the qualifying ones.
Since the data set could be large, I'm just wondering if one way is faster than the other
Suppose listOfElement is given and consists of lots of elements and I also want to return say the value of each qualifying element
method 1:
for(var i = 0; i < listOfElement.length ; i ++){
if ( testing condition ) {
$(listOfElement[i]).addClass("blah");
selected.push(listOfElement[i];
}
}
method 2:
selected = listOfElement.filter(...);
$(selected).addClass("blah")
I want to know the performance cost for $ selection operation and the addClass operation. It would be great if someone can point me to a document for some JavaScript guide for better performance (e.g. use hide/show is faster than insert/delete a DOM)
Native JavaScript is usually, if not always, faster than jQuery as jQuery involves the creation of $ objects.
var selected = listOfElement.filter(function (item) {
// ...
});
// Add class
selected.forEach(function (item) {
item.classList.add('blah');
// If you need to support IE 9 or lower:
// item.className += ' blah'; // note the space in front of the class name
});
This jsPerf may be of interest to you.
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 8 years ago.
Improve this question
Haven't worked much on front-end and was wondering if what I did is correct.
I have created an html table that displays data.
I have added button and check-boxes to modify structurally the table i.e. add a row.
The code to do that is a big block of code that does something like:
var table = document.getElementById('table');
table.insertRow(1);
var id_td = document.createElement('td');
//create options element
id_td.appendChild(options);
var name_td = document.createElement('td');
//create input textbox
name_td.appendChild(txt_box);
etc etc
So I don't like the fact that it is a really big-block of essentially repeating code that creates the elements.
I wanted to know, am I on the right track? Is this the only way unless we use some library like JQuery?
The VanillaJS approach
You can use something like
var table = document.getElementById('table');
table.innerHTML = "<tr><td id="+id+"></td><td class="name"></tr>";
To add your markup as a string, which might end up being more clear. Tough to tell exactly without seeing exactly how you're repeating yourself, but you might be able to abstract this out into a function
Libraries
There are plenty of libraries though that abstract away this ugliness though. jQuery is one, but something like knockoutjs might be a better fit for you.
It allows you to define a data model and bind html templates to that data model with automatic updating. So you could then just define your data as a JSON object and have it reflected in the DOM, with future updates just touching the view-model object and not having to deal with the DOM functions at all.
I don't like the fact that it is a really big-block of essentially repeating code that creates the elements
Why not make aliases for the long-winded function names?
var gid = function (id) {return document.getElementById(id);}, // so short!
ce = function (e) {return document.createElement(e)}, // ce(tag) is easy!
td = function () {return ce('td');}, // td() now makes a new `<td>`
ap = function (p, c) {return p.appendChild(c), p;}; // return more useful
now that "big-block" is
var table = gid('table'),
row = table.insertRow(1);
var id_td = td(), options = ce('select');
ap(id_td, options);
var name_td = td(), txt_box = ce('textarea');
ap(name_td, txt_box);
// etc etc
I have seen a few different methods to add elements to the DOM. The most prevelent seem to be, for example, either
document.getElementById('foo').innerHTML ='<p>Here is a brand new paragraph!</p>';
or
newElement = document.createElement('p');
elementText = document.createTextNode('Here is a brand new parahraph!');
newElement.appendChild(elementText);
document.getElementById('foo').appendChild(newElement);
but I'm not sure of the advantages to doing either one. Is there a rule of thumb as to when one should be done over the other, or is one of these just flat out wrong?
Some notes:
Using innerHTML is faster in IE, but slower in chrome + firefox. Here's one benchmark showing this with a constantly varying set of <div>s + <p>s; here's a benchmark showing this for a constant, simple <table>.
On the other hand, the DOM methods are the traditional standard -- innerHTML is standardized in HTML5 -- and allow you to retain references to the newly created elements, so that you can modify them later.
Because innerHTML is fast (enough), concise, and easy to use, it's tempting to lean on it for every situation. But beware that using innerHTML detaches all existing DOM nodes from the document. Here's an example you can test on this page.
First, let's create a function that lets us test whether a node is on the page:
function contains(parent, descendant) {
return Boolean(parent.compareDocumentPosition(descendant) & 16);
}
This will return true if parent contains descendant. Test it like this:
var p = document.getElementById("portalLink")
console.log(contains(document, p)); // true
document.body.innerHTML += "<p>It's clobberin' time!</p>";
console.log(contains(document, p)); // false
p = document.getElementById("portalLink")
console.log(contains(document, p)); // true
This will print:
true
false
true
It may not look like our use of innerHTML should have affected our reference to the portalLink element, but it does. It needs to be retrieved again for proper use.
There are a number of differences:
innerHTML has only been standardised by the W3C for HTML 5; even though it has been a de facto standard for some time now across all popular browsers, technically in HTML 4 it's a vendor extension that standards-adherent developers would never be caught dead using. On the other hand, it's much more convenient and practically it's supported by all browsers.
innerHTML replaces the current content of the element (it does not let you modify it). But again, you gain in convenience if you don't mind this limitation.
innerHTML has been measured to be much faster (admittedly, that test involves older versions browsers that are not widely used today).
innerHTML might represent a security risk (XSS) if it's set to a user-supplied value that has not been properly encoded (e.g. el.innerHTML = '<script>...').
Based on the above, it seems that a practical conclusion might be:
If you don't mind the fact that innerHTML is a bit limiting (only total replacement of DOM sub-tree rooted at target element) and you don't risk a vulnerability through injecting user-supplied content, use that. Otherwise, go with DOM.
Though this is an old thread, one thing that is not mentioned is the while innerHTML can be faster, care should be taken. Using innerHTML will render every child of the modified element, old and new alike. As such, one single innerHTML assignment is faster (slightly) than DOM create/append, but multiple innerHTML will definetly be slower.
For example:
for(let i=0; i < 10; i++)
document.body.innerHTML+='<div>some text</div>';
will be nearly nearly 5x slower than
let html = '';
for(let i=0; i < 10; i++)
html += '<div>some text</div>';
document.body.innerHTML = html;
Since innerHTML assignment is letting the browser natively create/append elements, the second methods results in 10 elements being natively created/appended, while the firstmethod results in 55 elements being created/appended (and 45 being destroyed): 1 element created on first loop-iteration, 2 elements created on the second loop-iteration (the original being destroyed), 3 elements created on the third loop-iteration (the previous 2 being destroyed), and so on.
If you use innerHTML for speed, you must make sure to create the entire html string first before making the innerHTML assignment, such as creating fresh DOM containers/elements. innerHTML, on the other hand, is a performance loser when appending any container with existing childNodes, especially those with large number of childNodes.
According to this benchmark data, you will receive much faster results with innerHTML than creating DOM elements. It's especially clear when using older IE versions.
First one is straight forward, easier to read, less code and might be faster.
Second one gives you much more control over the element you create, i.e. makes it much easier to modify the new Element using JS (like attaching events, or, just use it in your code).
Second way is for "purist" who like "clean" code (no quick and dirty).
I say, use both, see what fits you better and go with it.
I always prefer readability unless the perf difference is extreme. In a one-off case of this, it probably will be a marginal difference.
In a one-off case like this, setting the innerHTML property will be easiest to read.
But if you are doing a lot of programmatic content generation in JavaScript, it is cleaner and easier to read and understand the DOM option.
Example:
Compare this innerHTML code:
http://jsfiddle.net/P8m3K/1/
// Takes input of a value between 1 and 26, inclusive,
// and converts it to the appropriate character
function alphaToChar(alpha)
{
return String.fromCharCode('a'.charCodeAt() + alpha - 1);
}
var content = "<ul>";
for(i = 0; i < 10; ++i)
{
content += "<li>";
for(j = 1; j <= 26; ++j)
{
content += "<a href=\"" + alphaToChar(j) + ".html\">"
+ alphaToChar(j)
+ "</a>";
}
content += "</li>";
}
document.getElementById("foo").innerHTML = content;
To this DOM code:
http://jsfiddle.net/q6GB8/1/
// Takes input of a value between 1 and 26, inclusive,
// and converts it to the appropriate character
function alphaToChar(alpha)
{
return String.fromCharCode('a'.charCodeAt() + alpha - 1);
}
var list = document.createElement("ul");
for(i = 0; i < 10; ++i)
{
var item = document.createElement("li");
for(j = 1; j <= 26; ++j)
{
var link = document.createElement("a");
link.setAttribute("href", alphaToChar(j) + ".html");
link.innerText = alphaToChar(j);
item.appendChild(link);
}
list.appendChild(item);
}
document.getElementById("foo").appendChild(list);
At this level they start to become quite similar length wise.
But the DOM code will be easier to maintain, and you're a bit less likely to make a typo or mistake that is hard to diagnose, like omitting a closing tag. Either your elements will be in your document, or they won't.
With more complicated scenarios (like building treed menus), you'll probably come out ahead with DOM code.
With scenarios where you have to append multiple types of content together to build a document with more heterogeneous content, it becomes a slam dunk. You don't have to ensure you call your child append code before calling the parent append code.
With scenarios where add, remove, or modify existing static content, DOM will usually win.
If you start doing complicated DOM modifications (one of the last things I mentioned), you'll definitely want to check out a library built around DOM modifications, like jQuery.