When I send a div to a function which creates content to a document fragment it provides me this error when I append the fragment to the div.
Object column_left has no method 'appendChild' '
This is my code:
function progress_bar(parent_div){
var frag = document.createDocumentFragment();
var d = document.createElement('div');
d.className = 'progress_bg';
d.style.width = '90%';
frag.appendChild(d);
parent_div.appendChild(frag);
}
The function is called like this:
var d = document.getElementById('column_left');
progress_bar(d);
Does any one know why i cannot append like this?
Before you call progress_bar(d), #column_left doesn't exist (yet) so d is undefined. Since you're passing in an undefined value into progress_bar you can't call appendChild on it.
In order to fix this, you either have to create #column_left first, or pick a pre-existing element like document.body.
Here is a JSFiddle with the code cleaned up, I made it so it appends to the document's body instead and also sets the inner content something is actually rendered.
If you wanted to do it on #column_left, it would be something like this:
var el = document.createElement('div');
el.id = 'column_left';
document.body.appendChild(el);
progress_bar(el);
Related
This is the sample code I am working on:
var DomClass = {
Eprcent: ".item__percentage"
};
var EPrsent = function (prcent) {
prcent.forEach(function (cur) {
var ele = document.getElementById("exp-" + cur.id).innerHTML;
var S = document.querySelector.call(ele, 'DomStrings.Eprcent'); //Uncaught TypeError: Illegal invocation
S.innerText = cur.prcnt + "%";
});
}
I am getting this exception: Uncaught TypeError: Illegal invocation at line number 7.
How can I use document method on my HTML from JavaScript code, ID, and class which I want to use that is already present in HTML?
This is a data structure of prcent class:
var Expense = function (id, description, value) {
this.id = id;
this.description = description;
this.value = value;
this.prcnt = 0;
};
I am aware of that we can use directly document query but these HTML are generating dynamically with unique ids. I have to put information according to element id in my HTML. ex document.getElementById("exp-" + cur.id) this line use for identifying the HTML element in which i want to put value
My main concern is that how can I use call method on QuerySelector so that I can change "this" pointer to innerHTML variable? If it's not possible, then why?
querySelector acts on a Document object.
Its signature is querySelector(String selector)
The Document method querySelector() returns the first Element node within the document, in document order, that matches the specified selectors, or group of selectors. If no matches are found, null is returned.
The problem related to document.querySelector.call is because you are providing an invalid this value.
Check you are setting document.getElementById("exp-" + cur.id).innerHTML (String) as the this argument for document.querySelector.call (lines: 5), 6))
The Element innerHTML property is used to get or set a string representing serialized HTML describing the element's descendants.
Therefore, using the call method on querySelector to change this pointer to innerHTML is not possible because that variable is a String and not a Document object.
In the following snippet you can check how we can use querySelector.call (nothing different to using call on any other function):
const serializedHtml = document.getElementById('example').innerHTML;
console.log(typeof serializedHtml, serializedHtml); // -> string "<div id="inner">inner div</div><span>...</span>"
const inner = document.querySelector('#inner');
// equivalent call: same result using `.call` with the document object
const usingCall = document.querySelector.call(document, '#inner');
console.log(inner === usingCall, typeof inner, inner); // -> true object <div id="inner">inner div</div>
// using an empty Document
console.log(document.querySelector.call(new Document(), '#inner')); // -> null
// error code when pointing to innerHTML string
document.querySelector.call(serializedHtml, '#inner'); // -> Error: Uncaught TypeError: Illegal invocation...
#example, #inner {
border: 1px solid;
padding: 8px;
text-align: center;
}
<div id="example">
<div id="inner">inner div</div>
<span>...</span>
</div>
Trying to bind the document.querySelector to another Document instance makes no sense to me because if you had another Document object, you can always invoke directly the querySelector function of the other document.
Check the following example:
const htmlStr = '<div id="container"><div id="inner"></div></div>'
const parser = new DOMParser();
const doc = parser.parseFromString(htmlStr, 'text/html');
// using window.document
console.log(document.querySelector('#inner')); // -> null
// pointing to the correct Document
console.log(document.querySelector.call(doc, '#inner')); // -> <div id="inner"></div>
// but, really not neccessary because you can use the correct Document directly
console.log(doc.querySelector('#inner')); // -> <div id="inner"></div>
Hope all of this helps!
Read more info about document.querySelector, Element.innerHTML, Function.prototype.call and DOMParser
You can use querySelector directly on the element if its a DOM element like
var DomClass ={
Eprcent: ".item__percentage"
};
var EPrsent = function (prcent) {
prcent.forEach(function (cur) {
var ele = document.getElementById("exp-" + cur.id);
var S = ele.querySelector(DomClass.Eprcent);
S.innerText = cur.prcnt + "%";
});
}
I know that the title sounds weird but I don´t know how to exactly describe my problem. I have an array with all the divs id I created before. Now I want to take the first div´s id and remove the div by parentNode.removeChild(); The console prints:
'The "removeChild" property of an undefined or null reference can not be retrieved.'
I hope you can help me with that :)
var animation_time = 1500;
var div_id_selection = [];//it contains 'div0', div1, div2 ... divn
var array_counter = -1;
// Before that is a function that creates a div by document.createElement("div); with the id div0, div1, div2 ...than it writes the id into the array:
div_id_selection.push('div' + id);
var delete_divs = function(){
setTimeout(function(){
array_counter += 1;
var div_to_delete = div_id_selection[array_counter];
//var div_to_delete_str = div_to_delete.toString(); I already tried it with the string-didn´t work
console.log(div_to_delete);
console.log(array_counter);
div_to_delete.parentNode.removeChild(div_to_delete); // here is the problem
}, animation_time);
}
div_to_delete is a string ( id that is stored in the array ).
parentNode method is only available on a DOM object.
You will have to first select the element using the id.
// get the correct DOM object using the array
var elem = document.getElementById(div_to_delete);
elem.parentNode.removeChild(elem);
This is a strange behavior I noticed. I did not reset a document but immediately used it after I had appended it, and the previous elements it contained were not there.
Should I be clearing it as such?
frag_inner = '';
Are there side-effects I'm not aware of?
frag_outer = NS.createDocumentFragment();
frag_inner = NS.createDocumentFragment();
NS.eachIndex(obj, function(val) {
// fragment element - inner
// image element
val.view_picture = (val.picture === '0') ? this.A.images + 'generic_large.jpg' :
this.A.pictures + val.h_file + '-2.jpg';
img_element = $A.createElement('img');
img_element.className = 'tweet';
img_element.src = val.view_picture;
frag_inner.appendChild(img_element);
// link element
link_element = $A.createElement('a');
link_element.className = 'tweet';
link_element.innerHTML = val.name + ' posted ' +
this.prettyTime(val.time) + '<br>';
frag_inner.appendChild(link_element);
// paragraph element
par_element = $A.createElement('p');
par_element.className = 'tweet';
par_element.innerHTML = val.tweet;
frag_inner.appendChild(par_element);
// div element
div_element = $A.createElement('div');
div_element.className = 'tweet';
div_element.appendChild(frag_inner);
// append the div which is now populated
frag_outer.appendChild(div_element);
}, this);
I think it's actually the expected behaviour, as...
1) it's a well-known feature of Node.appendChild to move existing Nodes. As said in the docs (MDN)...
[Node.appendChild]... adds a node to the end of the list of children of a specified
parent node. If the node already exists it is removed from current
parent node, then added to new parent node.
2) when you append documentFragment, you actually append all its children (MDN again):
Various other methods can take a document fragment as an argument
(e.g., any Node interface methods such as Node.appendChild and
Node.insertBefore), in which case the children of the fragment are
appended or inserted, not the fragment itself.
The point is, when you do someNode.append(documentFragment), you remove all its children from it, then append them to someNode. That's why documentFragment is empty as result.
Note that when you do this...
frag_inner = '';
... you're not clearing the documentFragment stored in this variable - you store a new value (an empty string, obviously) in it instead. The very first attempt to work with it as with documentFragment should result in something like TypeError: Object has no method 'appendChild'.
Is there a way to create a DOM object from the whole string, not just the innerHTML? I have a string in the form of a complete rendered DOM:
<some_tag_name class=... id=...>inner text</some_tag_name> (1)
and want to directly create a DOM object out of it. I know that there is a way to do:
e = document.createElement("some_tag_name")
e.innerHTML = ...
e.className = ...
e.id = ...
but when I do that, I have to extract the innerhtml part from the string (1) that I have, and analyze the tag type and all the attributes and assign that to e separately. I want to do all that simply from the string in the form of (1) that I have.
Edit
I followed the answers, but it was trickier than it seemed at first. The problem is that when you have a string representing things like tr, td, etc., and you try to put that as the innerHTML to a temporarily created div, the browser automatically adds extra tags outside of it. The following is my workaround to overcome this problem, where c is the string and e is the created element:
var cTagName = c.match(new RegExp('[a-zA-Z]+'))[0].toUpperCase();
var e = document.createElement("div");
e.innerHTML = c;
e = e.children[0];
//// When the type of `e' does not match what `c' expects, the browser
//// automatically modifies the type of c. The following is to undo this.
if(e.tagName.toUpperCase() != cTagName){
e = document.createElement("table");
e.innerHTML = c;
e = e.children[0];
};
if(e.tagName.toUpperCase() != cTagName){
e = document.createElement("tbody");
e.innerHTML = c;
e = e.children[0];
};
if(e.tagName.toUpperCase() != cTagName){
e = document.createElement("tr");
e.innerHTML = c;
e = e.children[0];
};
You can always do:
var div = document.createElement("div");
div.innerHTML = "<some> ... </some>"
var e = div.children[0];
(or if you're using jQuery, simply $("<some ... >")[0]).
You're looking for the outerHTML property.
var el = document.createElement('tag');
document.body.appendChild(el); // The element must be appended to the DOM before
// setting outerHTML. Otherwise, it will throw a
// NO_MODIFICATION_ALLOWED_ERR.
el.outerHTML='<some_tag_name class=... id=...>inner text</some_tag_name>';
Given that Firefox is a little behind the times on this one, it's probably safer to just create a wrapper div and set its innerHTML.
var el = document.createElement('div');
el.innerHTML = '<some_tag_name class=... id=...>inner text</some_tag_name>';
You can do it with jQuery:
var myDiv = $('<div class="my-div">This is my div!</div>');
I have very very valuable , so i tried to make shortcuts like this :
LIVE example : http://jsfiddle.net/nqeUN/
var d = "document" ,
t = "getElementByTagName" ,
d = "div" ,
oc = "onclick";
d[t](d)[0].oc = function(){
alert("1");
}
but it's not working , what is the reason? i can see in Google plus api that all the objects are defined like this , as strings , how do they make it work?
There are a couple of problems you need to address
You have two values bound to d: "document" and "div".
It's getElementsByTagName
The getElementsByTagName function needs a DOM entry point not a string. Switch the first d to document
When using dot notation for .oc it will bound to the property oc in stead of the value of the variable oc. Use [] notation instead
Code:
var d = document ,
t = "getElementsByTagName" ,
div = "div" ,
oc = "onclick";
d[t](div)[0][oc] = function(){
alert("1");
}
Working Fiddle: http://jsfiddle.net/nqeUN/1/
Strings will work for properties, but not variable names. You also define d twice, and have the wrong method name. You would be able to do this:
var d = 'document', t = 'getElementsByTagName', div = 'div', oc = 'onclick';
window[d][t](div)[0][oc] = function() { ... }
But this really reduces readability and isn't necessary. You could run your code through a minimizer to get this automatically and still maintain readable dev code.
d is a string, not document.
You should write var d = document to get the actual document object.
However, you should not do this yourself; it makes utterly unreadable code.
Instead, you should develop normal, readable Javascript, then use a minifier (such as Microsoft AjaxMin or Google Closure Compiler) to automatically shrink your code as much as possible in production.
if you replace the values in your example, you'll see:
"document".getElementsByTagName("document").onclick = function() {};
1.) d should be set to the global document reference, not the string 'document'
var d = window.document;
2.) getElementsByTagName returns nodes that match the given tag name that are contained within the given DOM node, so passing 'document' as a string would look for HTML elements named 'document'. you need to find the divs, for example:
d.getElementsByTagName("div"); // All the 'div' elements in the document
3.) For method names to be used as strings, they need to be in brackets
document[ t ]; // document.t won't work, t is not a member
4.) Once you've accessed the nodes you care about, you need to loop through them to add event handlers to each element
var d = document.getElementsByTagName("div"),
i = 0,
len = d.length;
for ( ; i < len; i++ ) {
(function() {
// do something with d[i], the current element in the loop
})(i)
}
hope that helps! cheers.
Because the variable d is a string; and the String object does not have a getElementByTagName method.
Furthermore, your d variable is being redeclared as the string div; so you need to assign that to a different name:
var d = "document" ,
t = "getElementByTagName" ,
e = "div" ,
oc = "onclick";
Then, you need to access the window object, and retrieve the document attribute of it:
window[d]
to retrieve the Document element, and then retrieve the getElementsByTagName method from it (read getElements not getElement)
window[d][t]
You then invoke it and pass it the name of the element, retrieve the first value of the returned array, and assign a function to its onclick attribute:
window[d][t](e)[0][oc] = function () {
alert("1");
};
var d = "document",
t = "getElementsByTagName" ,
div = "div" ,
oc = "onclick";
window[d][t](div)[0][oc] = function(){
alert("1");
}
) document is not a string
) document['getElementByTagName'].call(this, 'div')
) . accessor changed to bracket because oc is a string not a property
) you used to var d twice
) it's getElementsByTagName, plural Elements
Full string madness http://jsfiddle.net/nqeUN/8/
"document"["gg"]()["getElementsByTagName"]("div")["0"]["onclick"] = function(){alert(1);};