innerHTML of dynamically added element not updating in Chrome - javascript

I'm modifying a dynamically created input element by setting the innerHTML, when I view the element in the DOM Inspector I can see that the values I passed are in the input. However, I can't see it on the page? Is there a refresh() function that I should be calling after setting the value?
I have tried innerText, and value and gotten the same results.
Here is how I am setting it:
$("input[name='group']")[0].innerHTML = groups;
(as far as the JS set and the JQuery selector I have found chrome plugins to be fickle this way)

input elements don't contain HTML. They have values.
No, you don't need to refresh anything, the change should show up as soon as the JavaScript finishes running (e.g., the event handler completes) and the browser has a moment to update the display. If you're doing this in a tight loop or something, you won't see the results until the end of the loop, but I didn't immediately get the sense that was what you were doing — unless you're single-stepping through the code in the dev tools? You won't see the refresh as you're single-stepping.
If not that, could it be that the element doesn't exist (yet) when you're calling your code? Remember that if your code is in a script element that's in the HTML before the element you're trying to update, you have to be sure you make it wait to run until the rest of the page has been parsed (using a ready callback, for instance). Alternately, just do what the YUI folks recommend and put your script tag at the end of the body.
Here's a working example:
jQuery(function($) {
setInterval(function() {
$("input[name='group']")[0].value = "Updated " + new Date();
}, 500);
});​
Live copy
Breakdown:
Waiting until the DOM is ready (by putting my code inside the function I pass into jQuery; this is a shorthand way of writing jQuery(document).ready(...)).
Set up an interval timer to update every 500ms.
Within the interval callback, look up the input element with the name "group" and update its value.
Update: Here's a simpler series of examples that demonstrate the whole "does the element exist yet?" thing:
Example 1:
<form>
<input type='text' name='group' value='original value' size='60'>
</form>
<script type='text/javascript'>
// This works, because it's _after_ the element
// it operates on
$("input[name='group']")[0].value = "Just one update: " + new Date();
</script>
Live copy
Example 2:
<script type='text/javascript'>
// This FAILS, because it's _before_ the element
// it operates on
$("input[name='group']")[0].value = "Just one update: " + new Date();
</script>
<form>
<input type='text' name='group' value='original value' size='60'>
</form>
Live copy
Example 3:
<script type='text/javascript'>
// This works, because although this script tag is before
// the element, we're using `ready` to wait until the DOM
// is ready
$(function() {
$("input[name='group']")[0].value = "Just one update: " + new Date();
});
</script>
<form>
<input type='text' name='group' value='original value' size='60'>
</form>
Live copy

Text box has no inner HTML. You need to set its value:
$("input[name='group']").val(groups);

Related

show all the values with .html [duplicate]

Lets say I have an empty div:
<div id='myDiv'></div>
Is this:
$('#myDiv').html("<div id='mySecondDiv'></div>");
The same as:
var mySecondDiv=$("<div id='mySecondDiv'></div>");
$('#myDiv').append(mySecondDiv);
Whenever you pass a string of HTML to any of jQuery's methods, this is what happens:
A temporary element is created, let's call it x. x's innerHTML is set to the string of HTML that you've passed. Then jQuery will transfer each of the produced nodes (that is, x's childNodes) over to a newly created document fragment, which it will then cache for next time. It will then return the fragment's childNodes as a fresh DOM collection.
Note that it's actually a lot more complicated than that, as jQuery does a bunch of cross-browser checks and various other optimisations. E.g. if you pass just <div></div> to jQuery(), jQuery will take a shortcut and simply do document.createElement('div').
EDIT: To see the sheer quantity of checks that jQuery performs, have a look here, here and here.
innerHTML is generally the faster approach, although don't let that govern what you do all the time. jQuery's approach isn't quite as simple as element.innerHTML = ... -- as I mentioned, there are a bunch of checks and optimisations occurring.
The correct technique depends heavily on the situation. If you want to create a large number of identical elements, then the last thing you want to do is create a massive loop, creating a new jQuery object on every iteration. E.g. the quickest way to create 100 divs with jQuery:
jQuery(Array(101).join('<div></div>'));
There are also issues of readability and maintenance to take into account.
This:
$('<div id="' + someID + '" class="foobar">' + content + '</div>');
... is a lot harder to maintain than this:
$('<div/>', {
id: someID,
className: 'foobar',
html: content
});
They are not the same. The first one replaces the HTML without creating another jQuery object first. The second creates an additional jQuery wrapper for the second div, then appends it to the first.
One jQuery Wrapper (per example):
$("#myDiv").html('<div id="mySecondDiv"></div>');
$("#myDiv").append('<div id="mySecondDiv"></div>');
Two jQuery Wrappers (per example):
var mySecondDiv=$('<div id="mySecondDiv"></div>');
$('#myDiv').html(mySecondDiv);
var mySecondDiv=$('<div id="mySecondDiv"></div>');
$('#myDiv').append(mySecondDiv);
You have a few different use cases going on. If you want to replace the content, .html is a great call since its the equivalent of innerHTML = "...". However, if you just want to append content, the extra $() wrapper set is unneeded.
Only use two wrappers if you need to manipulate the added div later on. Even in that case, you still might only need to use one:
var mySecondDiv = $("<div id='mySecondDiv'></div>").appendTo("#myDiv");
// other code here
mySecondDiv.hide();
if by .add you mean .append, then the result is the same if #myDiv is empty.
is the performance the same? dont know.
.html(x) ends up doing the same thing as .empty().append(x)
Well, .html() uses .innerHTML which is faster than DOM creation.
.html() will replace everything.
.append() will just append at the end.
You can get the second method to achieve the same effect by:
var mySecondDiv = $('<div></div>');
$(mySecondDiv).find('div').attr('id', 'mySecondDiv');
$('#myDiv').append(mySecondDiv);
Luca mentioned that html() just inserts hte HTML which results in faster performance.
In some occassions though, you would opt for the second option, consider:
// Clumsy string concat, error prone
$('#myDiv').html("<div style='width:'" + myWidth + "'px'>Lorem ipsum</div>");
// Isn't this a lot cleaner? (though longer)
var newDiv = $('<div></div>');
$(newDiv).find('div').css('width', myWidth);
$('#myDiv').append(newDiv);
Other than the given answers, in the case that you have something like this:
<div id="test">
<input type="file" name="file0" onchange="changed()">
</div>
<script type="text/javascript">
var isAllowed = true;
function changed()
{
if (isAllowed)
{
var tmpHTML = $('#test').html();
tmpHTML += "<input type=\"file\" name=\"file1\" onchange=\"changed()\">";
$('#test').html(tmpHTML);
isAllowed = false;
}
}
</script>
meaning that you want to automatically add one more file upload if any files were uploaded, the mentioned code will not work, because after the file is uploaded, the first file-upload element will be recreated and therefore the uploaded file will be wiped from it. You should use .append() instead:
function changed()
{
if (isAllowed)
{
var tmpHTML = "<input type=\"file\" name=\"file1\" onchange=\"changed()\">";
$('#test').append(tmpHTML);
isAllowed = false;
}
}
This has happened to me . Jquery version : 3.3.
If you are looping through a list of objects, and want to add each object as a child of some parent dom element, then .html and .append will behave very different. .html will end up adding only the last object to the parent element, whereas .append will add all the list objects as children of the parent element.

Network gear scripts

As a long time network engineer, Javascript has been a challenge to say the least. I am looking to use HTML & Javascript to create a template used to make network gear configurations. The HTML portion is very basic. Just a form with input fields and a button:
<body>
<form id="form1">
<label for="siteCode">Site Code: </label>
<input type="text" id="siteCode" name="name" placeholder="ex. HEN" required="required"/><br>
A button is used to call a Javascript function named "makeConfig"
I am running into an issue when it tries to get the "siteCode" ID from the HTML:
var siteCode = document.getElementById("siteCode");
function makeConfig() {
var myWindow = window.open("", "MsgWindow", "width=1000,height=850");
myWindow.document.write("service nagle<br>no service pad<br>service tcp-keepalives-in<br>service tcp-keepalives-out<br>");
myWindow.document.write("service timestamps debug datetime localtime show-timezone<br>service timestamps log datetime localtime show-timezone");
myWindow.document.write("service password-encryption<br>service compress-config<br>!<br>");
myWindow.document.write("hostname P" + siteCode + "A01M01UAA<br>!<br>");
}
The last line always generates a null value for siteCode. I would think this is simple, but I am drawing a blank. Thank you in advance for any help!
siteCode will be a reference to the DOM (Document Object Model) node of the element; which contains a bunch of objects and properties that you probably don't want to print.
Instead; you probably want the the text that the user has entered into it. For that; you could do something like
myWindow.document.write("hostname P" + siteCode.value + "A01M01UAA<br>!<br>");
Notice we are getting it's value (siteCode.value); rather than just the raw element.
For something like this; another common mistake is that the JavaScript may be running before the rest of the page has loaded; and therefore the element may simply not have loaded yet. However, since you've put it in a function; I'm assuming that's not what happening here; and you're running it only when the user presses a button; etc. If not; that may be something to check.

jQuery "add" Only Evaluated When "appendTo" Called

this has been driving me crazy since yesterday afternoon. I am trying to concatenate two bodies of selected HTML using jQuery's "add" method. I am obviously missing something fundamental. Here's some sample code that illustrated the problem:
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
</head>
<body>
<p id="para1">This is a test.</p>
<p id="para2">This is also a test.</p>
<script>
var para1 = $("#para1").clone();
var para2 = $("#para2").clone();
var para3 = para1.add(para2);
alert("Joined para: " + para3.html());
para3.appendTo('body');
</script>
</body>
</html>
I need to do some more manipulation to "para3" before the append, but the alert above displays only the contents of "para1." However, the "appendTo appends the correct, "added" content of para1 and para2 (which subsequently appears on the page).
Any ideas what's going on here?
As per the $.add,
Create a new jQuery object with elements added to the set of matched elements.
Thus, after the add, $para3 represents a jQuery result set of two elements ~> [$para1, $para2]. Then, per $.html,
Get the HTML contents of the first element in the set of matched elements or set the HTML contents of every matched element.
So the HTML content of the first item in the jQuery result ($para1) is returned and subsequent elements (including $para2) are ignored. This behavior is consistent across jQuery "value reading" functions.
Reading $.appendTo will explain how it works differently from $.html.
A simple map and array-concat can be used to get the HTML of "all items in the result set":
$.map($para3, function (e) { return $(e).html() }).join("")
Array.prototype.map.call($para3, function (e) { return $(e).html() }).join("")
Or in this case, just:
$para1.html() + $para2.html()
Another approach would be to get the inner HTML of a parent Element, after the children have been added.

Deleting and inserting Code in a DIV via jQuery

I know this has been adressed before, but I can't seem to get it working for me.
I am trying to create a football pitch with editable players via HTML/JavaScript/jQuery.
I can produce the field the first time when loading the page without any problems. The code looks like this:
<div id="pitch" class="updateAble">
<script type="text/javascript">
appBuilder(team1, team2);
</script></div>
appBuilder() looks like this:
var appBuilder = function (team1, team2) {
team1.Display();
team2.Display(); }
It simply creates the players on the pitch for both teams. As it does. I now want to push an input-button to call a function appUpdate(), which deletes the content of #pitch and puts the appBuilder()-part in again as to renew it (if I changed or added players):
var appUpdate = function () {
var newContent = "<script type='text/javascript'>appBuilder(team1, team2);</script>";
var updateItem = $('#pitch');
updateItem.empty();
updateItem.append(newContent);}
Here is what drives me nuts: It seems to work just fine up to and including the empty()-function. So the code has to be fine.
But when I try to append newContent to the #pitch-DIV, the programm seems to completely delete everything inside <head> and <body> it recreates a clean html-file (with empty html-, head-, body-tags) and inserts my players inside <body>.
Any ideas as to why it is doing that?
Thanks in advance!
UPADTE: The solution was a rookie mistake (which is fitting, since I'm a rookie). The Team.Display()-method was trying to do a document.write() call. As I learned: If you call document.write once the document is fully loaded, it will delete your site. Thanks to jfriend for the solution! :)
If you call document.write() AFTER the document has finished loading, then it will clear the current document and create a new empty one.
What you need to do is use DOM insertion operations rather than document.write() to add/change content in the DOM once the document has already loaded.
My guess is that the .Display() method is using document.write() and you need to change the way it works to insert content into a parent node rather than write it into the current position.
Some ways to insert content:
var newNode = document.createElement("div");
node.appendChild(newNode);
node.innerHTML = "<div>My Content</div>";
Or, if you're using jQuery, you can use it's wrappers for this:
obj.append("<div>My Content</div>");
obj.html("<div>My Content</div>");
.html() would empty and fill the div at once. Have you tried that ?
updateItem.html(newContent);
I proposed a JQuery replacement for your code that does what you want, ion the style of your own typing.
Note that I kept the .html() call to mimic your "empty()" function, but it is not necessary. Simply put he code in the append, straight into the html() et get rid of the extra unnecessary remaing bit of code.
My code replacement, as a 100% functioning .html file. Hope it helps, cheers.
<html>
<header>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script>
var appBuilder = function (team1, team2) {
//team1.Display();
//team2.Display();
}
var team1, team2;
</script>
</header>
<body>
<div id="pitch" class="updateAble">
<script type="text/javascript">
appBuilder(team1, team2); // Original code to be updated
</script>
</div>
<script>
var appUpdate = function () {
$("#pitch").html("<!-- Old javscript code has been flushed -->").append($("<script />", {
html: "appBuilder(team1, team2); // brand new, replaced code"
}));
}
appUpdate();
</script>
</body>
</html>

Problem using dynamically added html-object from javascript

I have a problem with dynamically including an object-tag in my html.
We have a external service which we call to get some html-fragment, it includes an object-tag, a script and a simple html-form. I take that content and add it to a div in my page and then try to execute the script that uses the included object. When i debug using Firebug I can see that the code is correctly inserted in the page but the script gets an error when it tries to access the object. It seems to me that the object isn’t initialized. Let me show you some code to exemplify what I mean.
getFragment makes an ajax call using jQuery to get the content.
var htmlSnippet = RequestModule.getFragment( dto );
$('#plugin').html( htmlSnippet ).hide();
The included content in plugin-div looks like this
<div id="plugin" style="display: none; ">
Browser:
Chrome
<object name="signer" id="signer" type="application/x-personal-signer2"></object>
<form method="POST" name="signerData" action="#success">
<input name="nonce" value="ASyhs..." type="hidden">
<input name="signature" value="" type="hidden">
<input name="encodedTbs" value="U2l..." type="hidden">
<input name="provider" value="nexus-personal_4X" type="hidden">
<input type="submit" onclick="doSign()" value="Sign">
</form>
</div>
The javascript that tries to use the “signer” object looks like this:
function doSign(){
var signer2 = document.getElementById("signer");
retVal = signer2.SetParam('TextToBeSigned', 'some value...');
... and then some more
}
It’s when i call the signer2.SetParam method that I get an error saying
Object #<an HTMLObjectElement> has no method 'SetParam'
But when I use the original page where the content is loaded when the page loads the script works so I know that the ‘SetParam’ method exists on the object and that the script works. But somehow it doesn’t work when I dynamically add it to the page afterwards.
I’ve Googled this a lot the last couple of days with no luck.
Does anyone have any idea on how to get this to work?
Best regards,
Henrik
First of all Object tag is not fully supported in all browsers (Source)
Next, from my experience, jQuery (which heavily relies on document.createDocumentFragment) sometimes fails to attach/trigger events on dynamically created/cloned DOM nodes, which could explain why your object failed to initialize.
That said, to try and fix your problem, I suggest using native document.createElement and document.appendChild methods instead of jQuery.html. You can try document.innerHTML but if that fails, you can always go with the ones I mentioned earlier.
My suggestion is to either alter your service to replace:
<script type="text/javascript">
function addElement(parentid, tag, attributes) {
var el = document.createElement(tag);
// Add attributes
if (typeof attributes != 'undefined') {
for (var a in attributes) {
el.setAttribute(a, attributes[a]);
}
}
// Append element to parent
document.getElementById(parentid).appendChild(el);
}
addElement('plugin', 'object', {name:"signer",id:"signer",type:"application/x-personal-signer2"});
</script>
OR if you cannot change the content that is returned by the service, run this after you include the content onto your page:
<script type="text/javascript">
/*
* Goes through al the object tags in the element with the containerid id
* and tries to re-create them using the DOM builtin methods
*/
function reattachObjectTags(containerid) {
jQuery('#'+containerid+' object').each(function(){
var attrs = {}, el = this;
// We're insterested in preserving all the attributes
var saved_attrs = {}, attr;
for(var i=0; i < el.attributes.length; i++) {
attr = el.attributes.item(i);
if(attr.specified) {
saved_attrs[attr.nodeName]=attr.nodeValue;
}
}
this.parentNode.removeChild(this);
var new_element = document.createElement('object');
for (var a in saved_attrs) {
new_element.setAttribute(a,saved_attrs[a]);
}
document.getElementById(containerid).appendChild(new_element);
});
}
// Do your stuff
var htmlSnippet = RequestModule.getFragment( dto );
$('#plugin').html( htmlSnippet ).hide();
// reattach all the object elements in #plugin
reattachObjectTags('plugin');
</script>
THIS IS ALL UNTESTED -
I typed this off the top of my mind, since I don't have the means to fire up IE and test this.
For a jQuery solution, I think this should work:
$("input:submit").click(function(){
$("#signer").append('<param name="TextToBeSigned" value="some value ...">');
... and then some more
});
Might want to give the submit button a class or an id and use that as a selector, if you have multiple forms on that page though.
Hope this helps.
I've set up a test script here: https://dl.dropbox.com/u/74874/test_scripts/object.html
If you open up Firebug/Web Inspector, you'll see that the SetParam method is in-fact, not defined. I don't know what it's supposed to do, but it's not defined in either case. If you're trying to add <param> tags to your embed, you could use the DOM API to do that. There is some code in the test script that does that, but I'll paste it here anyway:
var obj_signer = document.getElementById('signer');
var obj_p = document.createElement('param');
obj_p.id = "myp2";
obj_p.name = "TextToBeSigned";
obj_p.value = "some value ...";
obj_p.setAttribute('valueType', 'ref');
obj_signer.appendChild(e);
Or be faster using jQuery:
$("#signer").append("<param id='myp2' name='TextToBeSigned' value='some value ...' valueType='ref'></param>");

Categories

Resources