So I'm trying to grab some attributes of a div table from the DOM from within a script - and failing.
Code should speak for itself:
<head>
<script type = "text/javascript" src = "SCRIPT_IN_QUESTION.js"></script>
</head>
<body>
<div id = "my_elements">
<!-- I want to access 'attribute-one' data attributes from
all children -->
<div data-attribute-one = "Hello"></div>
<div data-attribute-one = "World"></div>
</div>
</body>
I've seen how this is done with an embedded script in the DOM using something along the lines of:
<script type = "text/javascript">
var values = document.getElementById('my_elements').childNodes;
var foo = values[0].getAttribute('data-attribute-one');
</script>
I'm trying to access these attributes from within a script that isn't embedded into the DOM, and getAttribute is undefined - guess you can only ue that within the DOM.
How do I access this data in a script 'outside' the DOM?
As the below comment states, doing this after the DOM has been loaded makes sense to do, and I'm doing it something like:
window.addEventListener('load', onload, false);
function onload(){
var data = document.getElementById('canvas_segments').childNodes;
//This throws an undefined error
var attribute = data[0].getAttribute('data-attribute-one');
}
Many thanks
Use .children instead of .childNodes (which also includes text nodes). And you may need to wrap your call into onload event, e.g.
<body onload="onLoad()";>
<div id = "my_elements">
<!-- I want to access 'attribute-one' data attributes from
all children -->
<div data-attribute-one = "Hello"></div>
<div data-attribute-one = "World"></div>
</div>
</body>
and in your script:
function onLoad() {
var values = document.getElementById('my_elements').children;
var foo = values[0].getAttribute('data-attribute-one');
}
You have a timing issue here. The script in question is being executed before the DOM is complete, so there is no element.
Either you can move the script tag to the bottom of the page, after all other markup, or you can put the code in a window.onload function.
First of all in the code snippet above, you are attaching the javascript before the DOM structure is loaded. Attach the js file after body so that the HTML content gets loaded first and then the js executes.
After you have done this you will still hit an issue saying, 'Uncaught TypeError: undefined is not a function.' This will be because you are using 'ChildNodes' instead of 'Children.' The difference between the two is that Children gets only Elements whereas 'ChildNodes' will fetch nodes too. Refer this question for a clearer distinction between the two (What is the difference between children and childNodes in JavaScript?)
You might be interested in a working copy of your code: http://goo.gl/HonxtJ
Related
I got a script converter like this
var currency_data='USD,0.712497,0.01|AUD,0.5576,0.05|AED,0.194009,0.25|BRL,0.248647,0.01|JPY,0.00594888,1|GBP,1.09482,0.01|CAD,0.572195,0.01|CNY,0.115772,0.5|EUR,0.795717,0.01|INR,0.0115219,0.1|ILS,0.178705,0.01|QAR,0.195741,1|RUB,0.0114246,0.01|SAR,0.189999,1|SGD,0.522129,0.01|THB,0.0220219,0.25';
var currency_sdrPer=new Array(),currency_Unit=new Array();currency_make_arrays();function currency_make_arrays(){var d=currency_data.split("|");for(var e=0;e<d.length;e++){var b=d[e].split(","),f=b[0];currency_sdrPer[f]=b[1];currency_Unit[f]=b[2]}};
function currency_rnd(h,e){h=Math.round(h/e)*e+".";var g=(e+".").split("."),c=h.split("."),b=c[1],a=g[1].length,d=b.length;if(d>a){b=b.substring(0,a)}for(var f=0;f<a-d;f++){b+="0"}return c[0]+(a==0?"":"."+b)}function currency_convert(f,d,c){var e=currency_sdrPer;if(!e[d]||!e[c]){return""}return currency_format(f*(e[d]/e[c]),currency_Unit[c])}function currency_format(c,f){var g=typeof currency_thousandsSeparator=="string"?currency_thousandsSeparator:",",b=typeof currency_decimalSeparator=="string"?currency_decimalSeparator:".",f=(typeof currency_decimalDigits=="number")?(1/Math.pow(10,currency_decimalDigits)):(typeof f=="number"?f:0.01),j=typeof currency_thousandsSeparatorMin=="number"?currency_thousandsSeparatorMin:3;if(typeof currency_round=="boolean"&¤cy_round){c=currency_rnd(c,f)}var i=(""+c).split("."),h=i[0],e=i.length>1?b+i[1]:"",a=/(\d+)(\d{3})/;if(g!=""){while(a.test(h)&&h.length>j){h=h.replace(a,"$1"+g+"$2")}}return h+e};
function conversion(e,d,c){document.write(currency_convert(e,d,c))}function currency_getRateHTML(d,c){var g=currency_convert(1,d,c);if(g==""){return""}var f=d+"_"+c+".html";if(c<d){f=c+"_"+d+".html"}f="http://coinmill.com/"+f;var e=unescape("%3Ca+href%3D%22%24link%22%3E%24from_the_name+is+worth+%3Cb%3E%24rate%3C/b%3E+%24to_plural_name%3C/a%3E%3Cbr%3E");if(typeof currency_template!="undefined"){e=currency_template}return e.replace("$link",f).replace("$rate",g).replace("$from_abbrev",d).replace("$from_name",d).replace("$from_plural_name",d+"s").replace("$from_the_name","the "+d).replace("$to_abbrev",c).replace("$to_name",c).replace("$to_plural_name",c+"s").replace("$to_the_name","the "+c)}function currency_showRate(d,c){document.write(currency_getRateHTML(d,c))}function currency_showRates(){for(var e=0;e<currency_rate_list.length;e++){var d=currency_rate_list[e];e++;if(e<currency_rate_list.length){var c=currency_rate_list[e];currency_showRate(d,c)}}}if(typeof currency_rate_list!="undefined"){currency_showRates()};
after element <head>
<script>
var currency_round=true;
</script>
and the calling inside after <body>:
<div>USD 60.61 = GBP <script>conversion(60.61,"USD","GBP");</script></div>
however, I really mind that there are <script> and </script> element inside body where as it's not good for html validation.
Is there any way to change it to be or element?
If you really want to move it out of the body (and there doesn't seem to be any point in doing so, it isn't invalid to have a script there) then you will need to:
Create an element in the body to put the content in
Replace all the document.write statements with DOM methods
Call the conversion function after the element becomes available (e.g. with an load event handler)
I think there is no other way to use.
so use script within body.
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.
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>
I am attempting to grab text from a HTML text area, and call the create() method when a 'Submit' button is pressed. The method is trying to use the message from the text area, and post that to its own p tag with class, and post a date stamp in its own p tag, and its own class.
These will both be in the div 'comments'. The error I am getting (using developer tools in Chrome), is
Uncaught TypeError: Cannot call method 'appendChild' of null.
This is aimed at "cmt.appendChild(divTag);". I am very new to Javascript, and this is just practise for me to increase my skills. All help is greatly appreciated!
var cmt = document.getElementById('comments');
function create() {
var username = 'User',
message = document.getElementById("textBox").value,
divTag = document.createElement('div'),
p1 = document.createElement('p'),
p2 = document.createElement('p');
divTag.className = 'comment';
p1.className = 'date';
p1.innerHTML = new Date();
divTag.appendChild(p1);
p2.className = 'message';
p2.innerHTML = username + ': ' +message;
divTag.appendChild(p2);
cmt.appendChild(divTag);
}
The error you are getting suggests that there is no element with the ID "comments" on your page. document.getElementById will return null when no element with such an ID is found, and thus cmd.appendChild(divTag) will be executed as null.appendChild(divTag).
If you are certain that the element exists, you may be executing your JavaScript that assigns the cmt variable before that element is created by the browser. To prevent that, standard practice is to place the <script> tag which includes your external JavaScript just before the closing </body> tag.
If you can't move your script tag for some reason, try running the code that assigns the variable with $(document).ready() (jQuery) or equivalent.
Your code works if the required elements exist. As you can see in this Fiddle.
Works if HTML is similar to:
<div id="comments">
<input id="textBox" type="textBox" value="Hello" />
</div>
My guess is that one of the identifiers might be misspelled or the element as you expect it does not exist.
However, if you are running the script in an external file it might try to execute before the document is fully loaded, hence your script is referring to elements not yet ready in the DOM.
In jQuery you would wrap a $(document).ready(function(){// your code here..}) around.
There is some details on how to do this in just JavaScript in this SO post: Documen Ready equivalent without jQuery.
Actually, his code is fine. Its just that JavaScript runs BEFORE HTML. A simple fix is to nest all of your code inside of a function with any name. Then use window.onload to run the function after the HTML is loaded. so basically:
window.onload = function any_name()
{
//code to be executed
}
This is useful especially if you do not want to move your script tag. I generally like to leave the tag where it is.
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>");