Issue Faced while appending the new child DOM into parent in ReactJS - javascript

I am trying to append the N number of 'intentSection' by onClick and getting added only string instead of DOM).
It directly appends the following as string instead of DOM.
<div className="intent">..</div>
Here's my code:
let intentSection = '<div className="intent">..</div>';
let reactfindDomNode = ReactDOM.findDOMNode(intentContainer);
$(reactfindDomNode).append(intentSection);

While the answer in the comment would probably work, manipulating the actual DOM is an anti-pattern and usually a bad idea. What you should be doing is utilizing the virtual DOM.
It isn't clear what you are trying to do here, but I guess it can be done by using the state to determine whether a component should be rendered inside the render method return

Related

How to get the component that rendered a dom element with Vue.js

How to get the component that rendered a dom element with Vue.js ?
For example, suppose you want to retrieve which component "owns" a dom element that the user has selected, how would you do ? (it seems to be implemented in the dev tools, but I can't find a way neither in the documentation, neither on SO)
(I mean, given the DOM element, I know how to retrieve what element is selected)
DISCLAIMER : This may not be the right solution for common use cases. Always prefer handling event & co. in the root component using direct sub-component reference if you can
I do not know if this is safe or officially supported, but assuming you're trying to access the component from some external-to-Vue code, this will return the VueComponent object for a given DOM element (substitute your own DOM selector as needed):
document.getElementById('foo').__vue__
If used on the app's root element, it will instead return the Vue constructor object.
(This appears to work in both Vue 1.x and 2.x.)
This is possibly not the most elegant solution, but you can use mixins to achieve this:
var elemOwner = {
mounted: function() {
this.$el.setAttribute("isVueComponent", this.$options.name);
}
};
As long as you set the mixin to the components you need it in, when you click an element you can test the attributes to see if there's a component name in there.
See this codepen for a fuller example: https://codepen.io/huntleth/pen/EpEWjJ
Clicking the smaller blue square will return the component name of the component that rendered it.
EDIT - It should be noted though that this obviously would only work if the element is actually inside that components root element. I think that would be the case for almost all uses.
Getting this.$parent refers to the parent of a component.

Unable to reference dom object

I am trying to set a reference to a DOM Element with the following code. For some reason anything called immediately after the reference is made works perfectly fine but calling it anywhere else in my application nothing happens. I don't get any errors like "unable to set innerHTML of undefined" which is the weirdest part. Immediately after the declaration it works fine later it doesn't do anything, yet other elements referenced in the same manner and in the same function work fine.
var dom = new function() {
this.signInA = document.getElementById("signInPin");
this.orderEntry = document.getElementById("orderEntry");
this.menuGroup = document.getElementById("openGroup");
}
<div id="orderEntry">
<div id="openGroup">
</div>
</div>
then later i am calling
dom.openGroup.innerHTML="TEST";
But nothing is happening. This of course is just a snippet of the application, yet ive already searched through the entire document to check every other refrence to DOM and specifically dom.openGroup. dom.orderEntry works just fine through the entire application and dom.openGroup is only working in the immediate vacinity of this declaration.
The problem I found was that the innerHTML method when changed deleted all nested DOM objects and therefore, any references to the child objects where also deleted.
So in hindsight I should either only use innerHTML on very simple objects that won't cascade down, and use other methods to append new elements into these more complex objects.

Why should y.innerHTML = x.innerHTML; be avoided?

Let's say that we have a DIV x on the page and we want to duplicate ("copy-paste") the contents of that DIV into another DIV y. We could do this like so:
y.innerHTML = x.innerHTML;
or with jQuery:
$(y).html( $(x).html() );
However, it appears that this method is not a good idea, and that it should be avoided.
(1) Why should this method be avoided?
(2) How should this be done instead?
Update:
For the sake of this question let's assume that there are no elements with ID's inside the DIV x.
(Sorry I forgot to cover this case in my original question.)
Conclusion:
I have posted my own answer to this question below (as I originally intended). Now, I also planed to accept my own answer :P, but lonesomeday's answer is so amazing that I have to accept it instead.
This method of "copying" HTML elements from one place to another is the result of a misapprehension of what a browser does. Browsers don't keep an HTML document in memory somewhere and repeatedly modify the HTML based on commands from JavaScript.
When a browser first loads a page, it parses the HTML document and turns it into a DOM structure. This is a relationship of objects following a W3C standard (well, mostly...). The original HTML is from then on completely redundant. The browser doesn't care what the original HTML structure was; its understanding of the web page is the DOM structure that was created from it. If your HTML markup was incorrect/invalid, it will be corrected in some way by the web browser; the DOM structure will not contain the invalid code in any way.
Basically, HTML should be treated as a way of serialising a DOM structure to be passed over the internet or stored in a file locally.
It should not, therefore, be used for modifying an existing web page. The DOM (Document Object Model) has a system for changing the content of a page. This is based on the relationship of nodes, not on the HTML serialisation. So when you add an li to a ul, you have these two options (assuming ul is the list element):
// option 1: innerHTML
ul.innerHTML += '<li>foobar</li>';
// option 2: DOM manipulation
var li = document.createElement('li');
li.appendChild(document.createTextNode('foobar'));
ul.appendChild(li);
Now, the first option looks a lot simpler, but this is only because the browser has abstracted a lot away for you: internally, the browser has to convert the element's children to a string, then append some content, then convert the string back to a DOM structure. The second option corresponds to the browser's native understanding of what's going on.
The second major consideration is to think about the limitations of HTML. When you think about a webpage, not everything relevant to the element can be serialised to HTML. For instance, event handlers bound with x.onclick = function(); or x.addEventListener(...) won't be replicated in innerHTML, so they won't be copied across. So the new elements in y won't have the event listeners. This probably isn't what you want.
So the way around this is to work with the native DOM methods:
for (var i = 0; i < x.childNodes.length; i++) {
y.appendChild(x.childNodes[i].cloneNode(true));
}
Reading the MDN documentation will probably help to understand this way of doing things:
appendChild
cloneNode
childNodes
Now the problem with this (as with option 2 in the code example above) is that it is very verbose, far longer than the innerHTML option would be. This is when you appreciate having a JavaScript library that does this kind of thing for you. For example, in jQuery:
$('#y').html($('#x').clone(true, true).contents());
This is a lot more explicit about what you want to happen. As well as having various performance benefits and preserving event handlers, for example, it also helps you to understand what your code is doing. This is good for your soul as a JavaScript programmer and makes bizarre errors significantly less likely!
You can duplicate IDs which need to be unique.
jQuery's clone method call like, $(element).clone(true); will clone data and event listeners, but ID's will still also be cloned. So to avoid duplicate IDs, don't use IDs for items that need to be cloned.
It should be avoided because then you lose any handlers that may have been on that
DOM element.
You can try to get around that by appending clones of the DOM elements instead of completely overwriting them.
First, let's define the task that has to be accomplished here:
All child nodes of DIV x have to be "copied" (together with all its descendants = deep copy) and "pasted" into the DIV y. If any of the descendants of x has one or more event handlers bound to it, we would presumably want those handlers to continue working on the copies (once they have been placed inside y).
Now, this is not a trivial task. Luckily, the jQuery library (and all the other popular libraries as well I assume) offers a convenient method to accomplish this task: .clone(). Using this method, the solution could be written like so:
$( x ).contents().clone( true ).appendTo( y );
The above solution is the answer to question (2). Now, let's tackle question (1):
This
y.innerHTML = x.innerHTML;
is not just a bad idea - it's an awful one. Let me explain...
The above statement can be broken down into two steps.
The expression x.innerHTML is evaluated,
That return value of that expression (which is a string) is assigned to y.innerHTML.
The nodes that we want to copy (the child nodes of x) are DOM nodes. They are objects that exist in the browser's memory. When evaluating x.innerHTML, the browser serializes (stringifies) those DOM nodes into a string (HTML source code string).
Now, if we needed such a string (to store it in a database, for instance), then this serialization would be understandable. However, we do not need such a string (at least not as an end-product).
In step 2, we are assigning this string to y.innerHTML. The browser evaluates this by parsing the string which results in a set of DOM nodes which are then inserted into DIV y (as child nodes).
So, to sum up:
Child nodes of x --> stringifying --> HTML source code string --> parsing --> Nodes (copies)
So, what's the problem with this approach? Well, DOM nodes may contain properties and functionality which cannot and therefore won't be serialized. The most important such functionality are event handlers that are bound to descendants of x - the copies of those elements won't have any event handlers bound to them. The handlers got lost in the process.
An interesting analogy can be made here:
Digital signal --> D/A conversion --> Analog signal --> A/D conversion --> Digital signal
As you probably know, the resulting digital signal is not an exact copy of the original digital signal - some information got lost in the process.
I hope you understand now why y.innerHTML = x.innerHTML should be avoided.
I wouldn't do it simply because you're asking the browser to re-parse HTML markup that has already been parsed.
I'd be more inclined to use the native cloneNode(true) to duplicate the existing DOM elements.
var node, i=0;
while( node = x.childNodes[ i++ ] ) {
y.appendChild( node.cloneNode( true ) );
}
Well it really depends. There is a possibility of creating duplicate elements with the same ID, which is never a good thing.
jQuery also has methods that can do this for you.

How a variable binds its value to the DOM?

This might be crazy but it intriguing me for quite some time :)
I would like to know how a javascript variable can bind itself do the DOM after it is appended to the body, for example?
var p = document.createElement('p');
p.innerHTML = 'Hello World';
document.body.appendChild(p);
So now I have this p variable which contains an exact reference of that specific paragraph no matter where it is located inside the body.
p.innerHTML = 'new content';
will easily find the paragraph and change its value
So my question is...how this binding is made?
what If I want to re-create that after the variable is gone?
is there any way to attach that again without having to run through the DOM and find it?
I was thinking if somehow each node inside the DOM have its specific identifier that is not the id attribute but some kind of UUID that can be referred later on?
like:
console.log(p.localName); //aoi12e2kj2322444r4t
p = null;
so I can still recover that paragraph node thought this uuid?
In this environment I wouldn't have access to any external node attribute, such name, id, data, etc..
So I am quite curious to know how this binding is created between variable and DOM node?
I believe that it changes depending on the browser your using. There's no standard way to do so. Currently you either use the id or iterate over the dom until you reach the element you want.
The binding is created on the first line, where you assign the result of document.createElement to p. This is no different from any other time you assign something to a variable, which always binds the variable name to the value. As far as the script is concerned, there is no other binding occurring. The p is an HTMLElement, and that's all of the element that's exposed.
Note that for p.innerHTML = 'new content';, the element doesn't have to be found because p already refers to the element. That's what the DOM does: it exposes documents and document elements.
If you later want another reference to the same element, you'll have to use DOM methods (such as getElementById) to find it. That's what they're there for.
As for how the DOM exposes elements, that's implemented internally and varies from browser to browser or library to library (since the DOM isn't used just in browsers).

JavaScript: Appending children to element

Which technique below is better from a user experience?
In both examples, assume that thumbContainer is set to the return value of document.getElementById('thumbContainer'), and new Thumbnail(thumb).toXMLString() returns a string with XHTML markup in it.
A) Simply += with thumbContainer.innerHTML:
for (thumb in thumbnails) {
thumbContainer.innerHTML += new Thumbnail(thumb).toXMLString();
}
B) Or converting new Thumbnail(thumb).toXMLString() to DOM elements and using appendChild?
for (thumb in thumbnails) {
var shell = document.createElement('div');
shell.innerHTML = new Thumbnail(thumb).toXMLString();
for (i = 0; i < shell.childElementCount; i++) {
thumbContainer.appendChild(shell.children[i]);
}
}
I've used both and get complaints from Firefox that I've got a long-running script, and do I want to stop it?
Which loop is less-tight, that will allow the UI to update as new elements are added to the DOM?
A) Simply += with thumbContainer.innerHTML
Never do this. This has to serialise all the content to HTML, add a string to it, and parse it all back in. It's slow (doing it in a loop is particularly bad news) and it'll lose all JavaScript references, event handlers and so on.
IE's insertAdjacentHTML will do this more efficiently. It's also part of HTML5, but not widely implemented elsewhere yet.
using appendChild?
Yes, that's fine. If you've got a lot of thumbs it will start to get slow (but not as bad as reparsing innerHTML each time). Making a DocumentFragment to insert multiple elements into the container child node list at once can help in some cases. Combining DocumentFragment with Range can do more still, but gets harder to write compatibly since IE's Range implementation is so StRange.
Either way, since you don't seem to be doing anything with the individual shell nodes, why not simply join all the thumbernail HTML strings together before parsing?
for (var child in shell.childNodes) {
Don't use for..in on sequence types, it won't do what you think. It's only meant for use against Object used as a mapping. The correct way to iterate over an Array or NodeList is plain old for (var i= 0; i<sequence.length; i++).
Personally I like the second approach (using appendChild) better, because, you are adding new element to the document tree without affecting the old elements.
When using innerHTML += new content, you affect old content, because all the HTML has to be reassigned (replaced with new HTML that contains of old code and some new code).
But, if you want to increase the performance, I'd suggest using DocumentFragments. Using them you can append a whole set of nodes with just one appendChild call on the document tree. Worth reading: "DOM DocumentFragments" by John Resig, but it's not the case in your problem, because you get the content as a string, that you have to first convert to DOM nodes.
My second suggestion is, to create a string of HTML code and then use innerHTML on a temporary container to convert it to DOM nodes
var htmlCode = "";
for (thumb in thumbnails) {
htmlCode += new Thumbnail(thumb).toXMLString();
}
var element = document.createElement(htmlCode);
element.innerHTML = htmlCode; // ... and append all the elements to document, or thumbContainer.innerHTML += htmlCode;

Categories

Resources