Get last added element of an element - javascript

I have a pivot element and I want that whenever an element is added to this pivot element a javascript function is called on it. The call must happen exact once per element.
DOMNodeInserted is marked as deprecated so I tried to use the workaround found here. The approach is working fine, but in addition to the element to which the addition happended (event.target), I also need to know which element was added.
Do I have to keep record of all elements added to my pivot element and then compare them after the event happened to detect new elements or is there an easier approach?

If your variable references a node, to retrieve the last item added to it you can use the lastChild property.
var node = document.getElementById("something");
var last = node.lastChild;
last.appendChild(document.createTextNode("I'm the last one..."));
An alternative may be childNodes:
var node = document.getElementById("something");
node.childNodes[node.childNodes.length - 1].appendChild(document.createTextNode("I'm the last one..."));
For extra reference: https://developer.mozilla.org/en-US/docs/Web/API/Node/lastChild
and https://developer.mozilla.org/en-US/docs/Web/API/Node/childNodes

Related

Javascript remove item from DOM before rendering code

I'm trying to remove an element from my HTML document, which I'm able to do with the remove method, however, when console logging the NodeList with document.querySelectorAll() on some classes on elements that should've been removed, they're still showing up in the NodeList.
I need to remove an element from the webpage, but also from the NodeList, as if the element wasn't there initially on page load to prevent the rest of my application from thinking that it's there.
I would've thought that the remove method would've covered this, but unfortunately it doesn't, what am I missing and what's the workaround?
function removeElement (ident) {
const elem = document.querySelector(ident)
if (elem) {
elem.remove()
}
}
you have to get elements by their id name.
var elem = document.getElementById('myid');
elem.remove()
here 'myid' is the id of the item to be deleted.
if you want to delete it using query selector then take the help of elem's parent element.
let elem = document.querySelector(ident);
elem.parentElement.removeChild(elem);

<br> not being appended to div

ogres = document.getElementById('${contentID}')
.
let prettify = streamArray[streamArray.length - 1].split(/--/),
layers = document.createTextNode(prettify[0]),
onions = document.createTextNode(prettify[1]),
breaking = document.createElement('br');
I have an array of two elements that I've created called prettify.
I have definitely confirmed that the prettify[0] and prettify[1] are the elements I want so I make them into onions and layers which are text nodes to be appended to the div.
You'll note I also have breaking which is a break element I create and also append to the div.
I then have the div, orges.
Now for some unknown reason when I do this:
ogres.appendChild(layers);
ogres.appendChild(breaking);
ogres.appendChild(onions);
ogres.appendChild(breaking);
on the html page, this is created:
layersonions
<br>
1: why is this happening
2: how do I fix it?
3: no I don't plan on keeping these variable names, but they are fun :3
When you use document.createElement('br'); to create an element, it is appended as the second node of the parent.
Since you are using the same reference again, it simply detaches the existing element and appends it again in the new position.
It is a single reference to the element. To fix it you will have to create and append an element on the fly.
ogres.appendChild(layers);
ogres.appendChild(document.createElement('br'));
ogres.appendChild(onions);
ogres.appendChild(document.createElement('br'));
appendChild
If you still want to use the variable reference then you could use the cloneNode method which will clone the existing node before insertion.
ogres.appendChild(layers);
ogres.appendChild(breaking);
ogres.appendChild(onions);
ogres.appendChild(breaking.cloneNode(false));
cloneNode

javascript elements/tags array DOM node access

what's the different between using:
// assuming using elements/tags 'span' creates an array and want to access its first node
1) var arrayAccess = document.getElementsByTagName('elementName')[0]; // also tried property items()
vs
// assuming I assign an id value to the first span element/tag
// specifically calling a node by using it's id value
2) var idAccess = document.getElementById('idValue');
then if I want to change the text node....when using example 1) it will not work, for example:
arrayAccess.firstChild.nodeValue = 'some text';
or
arrayAccess.innerText/innerHTML/textContent = 'some text';
If I "access" the node through its id value then it seems to work fine....
Why is it that when using array it does not work? I'm new to javascript and the book I'm reading does not provide an answer.
Both are working,
In your first case you need to pass the tag name instead of the element name. Then only it will work.
There might be a case that you trying to set input/form elements using innerHTML. At that moment you need to use .value instead of innerHTML.
InnerHTML should be used for div, span, td and similar elements.
So your html markup example:
<div class="test">test</div>
<div class="test">test1</div>
<span id="test">test2</span>
<button id="abc" onclick="renderEle();">Change Text</button>
Your JS code:
function renderEle() {
var arrayAccess = document.getElementsByTagName('div')[0];
arrayAccess.innerHTML = "changed Text";
var idEle = document.getElementById('test');
idEle.innerHTML = "changed this one as well";
}
Working Fiddle
When you use document.getElementsByTagName('p'), the browser traverses the rendered DOM tree and returns a node list (array) of all elements that have the matching tag.
When you use document.getElementById('something'), the browser traverses the rendered DOM tree and returns a single node matching the ID if it exists (since html ID's are unique).
There are many differences when to use which, but one main factor will be speed (getElementById is much faster since you're only searching for 1 item).
To address your other question, you already have specified that you want the first element in the returned nodeList (index [0]) in your function call:
var arrayAccess = document.getElementsByTagName('elementName')[0];
Therefore, arrayAccess is already set to the first element in the returned query. You should be able to access the text by the following. The same code should work if you used document.getElementById to get the DOM element:
console.log(arrayAccess.textContent);
Here's a fiddle with an example:
http://jsfiddle.net/qoe30w2w/
Hope this helps!

jQuery: Using .after() or .before() adds element to last item in selection only

I've been using jQuery for a while but this is a new one. A simplified example:
HTML
<div class='custom'></div>
<div class='custom'></div>
<div class='custom'></div>
jQuery:
var $customElems = $('.custom'),
$spanOuter = $('<span class="outer"/>'),
$spanInner = $('<span class="inner"/>');
$customElems.each( function() {
$(this).wrap($spanOuter).after($spanInner);
});
JSFiddle:
http://jsfiddle.net/a3ZK8/
I would have expected the 'inner' span to be added to all three elements in the selection but it gets always inserted into the last one only (no matter how many). I tried it with .before(), with and without the chaining, same result. What am I missing??
The problem is you are using a reference to a jQuery object.
Hence you keep moving the object reference around within each iteration.
If you have no events attached or no need for the span to be a jQuery object then just pass the parameter as a HTML string literal instead of an object reference
Cloning a jQuery object that doesn't need to be a jQuery object in the first place is just redundant processing and unnecessary overhead.
Change your jQuery object to a string similar to this:
spanInnerString = '<span class="inner"/>';
and your method like this:
$(this).wrap($spanOuter).after(spanInner);
The result is:
<span class="outer"><div class="custom"></div><span class="inner"></span></span>
<span class="outer"><div class="custom"></div><span class="inner"></span></span>
<span class="outer"><div class="custom"></div><span class="inner"></span></span>
DEMO - Passing parameter as HTML string
Off course, the same goes for the outer span. Don't create jQuery objects unless you have to.
If you must use a jQuery object because you want to attach events to the span or similar, than cloning is the way to go, though make sure you use clone(true, true) then to also clone the attached events.
You need to clone the element. Otherwise, after() will relocate the same element 3 times, which results in it being attached to only the last looped element.
$customElems.each(function () {
$(this).wrap($spanOuter).after($spanInner.clone());
});
Demo: Fiddle
You might ask, "Why would wrap() work?" That's because 'wrap()' internally clones the element.
You're moving the same span from place to place. If you acted on all three divs at once, jquery will instead clone the span.
http://jsfiddle.net/a3ZK8/1/
var $customElems = $('.custom'),
$spanOuter = $('<span class="outer"/>'),
$spanInner = $('<span class="inner"/>');
$customElems.wrap($spanOuter).after($spanInner);
From the documentation for .after:
Important: If there is more than one target element, cloned
copies of the inserted element will be created for each target except
for the last one.
which means the last element will always get the original, while all other selected elements will get a clone. That's why when you acted on one element at a time, it simply moved the same span around.

JavaScript unexpected object behavior with jQuery

I have two <div> elements, and the following JavaScript code:
var myObject = {
$input: $('<input />'),
insert: function () {
$('div').append(this.$input);
$('div').append(' ');
}
};
myObject.insert();
This, as I expect, produces an <input> element within each of the two <div> elements.
Now when I create a new instance of myObject and call insert() again I will be expecting 4 <input> elements, two in each <div>. Weirdly, I only get 3 <input> elements!
See example code here:
http://jsfiddle.net/FNEax/
You're creating 1 input explicitly:
$input: $('<input />',{value:i}),
...but cloning it implicitly when you try to append it to multiple divs
// 2 divs
$('div').append(this.$input);
Then Object.create doesn't create a new $input, so on the second pass, it appends (moves) the input from the second div (which is actually the original) to the first div, and then does the implicit clone to populate the second.
Here's a jsFiddle example that increments an i variable whenever insert() is called, and adds it as the value of the input. Notice that it is always set at 0.
I also modified it to pass a string to insert so you can see which call each input came from.
The two inputs from the second call both still have the string passed to the first call.
EDIT:
I flipped it around mid explanation, but the concept is the same.
When the second insert() is called, the clone is first created of the original and added to the first div, then the original is appended to the second div (where it already is).
jQuery makes the clones first, then appends the original last.
Here's another jsFiddle example that adds a custom property to the original, then adds some text next to the element with that custom property after each insert(). The text is always added next to that original in the second div.
This is what is happening. From the jQuery docs:
If an element selected this way is inserted elsewhere, it will be moved into the target (not cloned)
If there is more than one target element, however, cloned copies of the inserted element will be created for each target after the first.
So the first time around, since your input isn't anywhere in the DOM it is cloned and inserted into both divs. But, the second time it is called it is removed from the second div, before being cloned and added back into both divs.
At the end of your code, the first div contains both inputs, but the second div only contains the most recent input, since each input was removed from your last div.
http://jsfiddle.net/hePwM/
Once an element is inserted into the DOM, another .append() call with it as the appended content causes it to move within the DOM (docs). Your code creates a jQuery collection with a single input therein, which input has yet to be appended to the DOM. So the first call to insert() appends it to each (using the cloning or copying mechanism internal to jQ).
In the second call, however, this.$input references something which is already in the DOM (due to the first call). Internally, jQuery is each-ing the collection of DIVs and appending the input which lives inside of this.$input. So it adds it, the moves it.
The primary issue is that you're re-appending the same input over and over. Remember that JavaScript generally references existing objects rather than make new ones. That same input element keeps getting re-referenced.
If you want a method to add an input to every DIV, you should simply pass the input markup into append:
$( 'div' ).append( '<input />' );
The wierd behavior is due to the fact you are using a JQuery collection where you shouldn't be. How it even worked in the first place is beyond my skillset.
var myObject = {
input: '<input />',
insert: function () {
$('div').append(this.input);
//$('div').append(' ');
}
};
try each():
var myObject = {
insert: function () {
$('div').each(function(index) {
$(this).append($('<input />'));
$(this).append(' ');
});
}
};
myObject.insert();
myObject.insert();

Categories

Resources