When the upload button is clicked, the file browser opens using the below method. As far as I'm aware, there is no element added to the DOM unless you explicitly append it to a DOM element.
const inputEl = document.createElement("input");
inputEl.type = "file";
inputEl.multiple = true;
inputEl.click();
inputEl.onchange = (e) => { ... }
Is it possible to select a file in Cypress using this method? selectFile requires the input element to be in DOM and chained off it. Otherwise, I'd have to use hidden input elements instead.
Solved. You can't do it in Cypress. I used an environment variable "DEVELOPMENT=1" to append the input element to the DOM, but only during testing.
const inputEl = document.createElement("input");
if (process.env.DEVELOPMENT) {
document.getElementById("root").appendChild(inputEl);
}
inputEl.type = "file";
inputEl.multiple = true;
inputEl.click();
inputEl.onchange = (e) => { ... }
I need to clone a div that contains an input file, and within the clone, there is a button to delete the created clone.
My problem is that once the clone is created I cannot add the function on the button to delete the clone.
The function does not work. Where am I wrong?
if (document.querySelector('.clona-input-file') !== null) {
var clonaInputFile = document.querySelector('.clona-input-file');
clonaInputFile.addEventListener('click', function(e) {
e.preventDefault();
var RowDaClonare = document.querySelector('#row-da-clonare');
var clone = RowDaClonare.cloneNode(true);
clone.children[0].lastElementChild.value = '';
clone.id = 'row-da-clonare-' + Date.now();
RowDaClonare.after(clone);
var _buttonDel = document.createElement("button");
_buttonDel.id = 'cancellaInputClone';
_buttonDel.type = 'button';
_buttonDel.setAttribute("data-id-da-eliminare", clone.id);
_buttonDel.classList.add("btn");
_buttonDel.classList.add("btn-danger");
_buttonDel.classList.add("cancellaInputClone");
_buttonDel.innerHTML = '<i class="bi bi-trash-fill"></i>';
clone.appendChild(_buttonDel);
});
}
var cloneSet = document.querySelectorAll(".cancellaInputClone");
for (var i = 0; i < cloneSet.length; i++) {
cloneSet[i].addEventListener('click', fx_button);
}
function fx_button() {
console.log(this)
}
The issue is because you're attempting to bind event handlers to elements which don't yet exist in the DOM. This can be addressed by delegating your event handlers to parent elements which do exist when the DOM loads, and interrogating the events to see if they were raised by the elements you created.
In addition there's some other issues in your code to address:
Firstly, don't use id attributes in dynamic content. It makes your logic more complex than it needs to be. Use classes instead, and relate elements to each other using DOM traversal methods, such as closest().
Secondly, use querySelector() to find the child element, not children/index accessors. It's more robust.
Lastly, you can provide multiple separate class names to classList.add() to save you having to call it repeatedly.
With that said, try this working example:
let cloneButton = document.querySelector('.clona-input-file');
if (cloneButton) {
cloneButton.addEventListener('click', function(e) {
e.preventDefault();
let rowDaClonare = document.querySelector('.row-da-clonare'); // querySelector will return first match only
let clone = rowDaClonare.cloneNode(true);
clone.querySelector('input').value = '';
rowDaClonare.after(clone);
let buttonDel = document.createElement("button");
buttonDel.type = 'button';
buttonDel.classList.add("btn", "btn-danger", "cancellaInputClone");
clone.appendChild(buttonDel);
let icon = document.createElement('i');
icon.classList.add('bi', 'bi-trash-fill');
buttonDel.appendChild(icon);
});
}
// icon click handler delegated to the .container element
document.querySelector('.container').addEventListener('click', e => {
let el = e.target;
if (!el.classList.contains('cancellaInputClone') && !el.closest('button')?.classList.contains('cancellaInputClone'))
return;
el.closest('.row-da-clonare').remove();
});
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons#1.3.0/font/bootstrap-icons.css">
<div class="container">
<button class="clona-input-file">Clone</button>
<div class="row-da-clonare">
<div>
Lorem ipsum dolor sit.
<input type="text" class="foo" />
</div>
</div>
</div>
According to your code, it looks like the button is created only when the clonaInputFile is clicked, but the querySelectorAll and loop and addEventListener executes right after you registered the callback for the clonaInputFil. So now there is no button you are querying, and the cloneSet should be empty, if you haven't created before.
Try log out the length of cloneSet. If it is 0, I recommend you to put the addEventListener('click', fx_button); right after the creation of that button.
Would there be any reason the following code would not insert a DIV into the DOM and add the ID attribute? For some reason it is not working:
createDivs() {
const target = document.querySelector(".navbar");
const createDiv = document.createElement("DIV");
createDiv.setAttribute("id", "result-div");
createDiv.innerHTML = "<p>Yes</p>";
createDiv.insertAdjacentElement("afterbegin", target);
}
ngOnInit() {
this.createDivs();
}
You called insertAdjacentElement on the new element instead of on the sibling element... check the documentation
Instead of using
createDiv.insertAdjacentElement("afterbegin", target);
you should use
target.insertAdjacentElement("afterbegin", createDiv);
In the following code, why is document.querySelector() returning null?
var element = document.createElement('div');
element.classList.add('abc');
var test = document.querySelector("." + element.className);
You need to add a .
var test = document.querySelector("."+element.className);
EDIT
You also need to add it to body
document.body.appendChild(element);
See http://codepen.io/jammer99/pen/dMmXYL
The div is not part of the DOM until you append it to a DOM element.
You need to add a dot in front to use the querySelector on a class string: document.querySelector("."+element.className)
The DOM element you append your div to has to exist before you can access it.
window.onload=function() { // body exists
var element = document.createElement('div');
element.classList.add('abc');
var test = document.querySelector("."+element.className);
console.log(test,element.className);
document.body.appendChild(element); // NOW the DIV exists in DOM
test = document.querySelector("."+element.className);
console.log(test);
}
How can I implement prepend and append with regular JavaScript without using jQuery?
Here's a snippet to get you going:
theParent = document.getElementById("theParent");
theKid = document.createElement("div");
theKid.innerHTML = 'Are we there yet?';
// append theKid to the end of theParent
theParent.appendChild(theKid);
// prepend theKid to the beginning of theParent
theParent.insertBefore(theKid, theParent.firstChild);
theParent.firstChild will give us a reference to the first element within theParent and put theKid before it.
Perhaps you're asking about the DOM methods appendChild and insertBefore.
parentNode.insertBefore(newChild, refChild)
Inserts the node newChild as a child of parentNode before the
existing child node refChild. (Returns newChild.)
If refChild is null, newChild is added at the end of the list of
children. Equivalently, and more readably, use
parentNode.appendChild(newChild).
You didn't give us much to go on here, but I think you're just asking how to add content to the beginning or end of an element?
If so here's how you can do it pretty easily:
//get the target div you want to append/prepend to
var someDiv = document.getElementById("targetDiv");
//append text
someDiv.innerHTML += "Add this text to the end";
//prepend text
someDiv.innerHTML = "Add this text to the beginning" + someDiv.innerHTML;
Pretty easy.
If you want to insert a raw HTML string no matter how complex, you can use:
insertAdjacentHTML, with appropriate first argument:
'beforebegin'
Before the element itself.
'afterbegin'
Just inside the element, before its first child.
'beforeend'
Just inside the element, after its last child.
'afterend'
After the element itself.
Hint: you can always call Element.outerHTML to get the HTML string representing the element to be inserted.
An example of usage:
document.getElementById("foo").insertAdjacentHTML("beforeBegin",
"<div><h1>I</h1><h2>was</h2><h3>inserted</h3></div>");
DEMO
Caution: insertAdjacentHTML does not preserve listeners that where attached with .addEventLisntener.
I added this on my project and it seems to work:
HTMLElement.prototype.prependHtml = function (element) {
const div = document.createElement('div');
div.innerHTML = element;
this.insertBefore(div, this.firstChild);
};
HTMLElement.prototype.appendHtml = function (element) {
const div = document.createElement('div');
div.innerHTML = element;
while (div.children.length > 0) {
this.appendChild(div.children[0]);
}
};
Example:
document.body.prependHtml(`Hello World`);
document.body.appendHtml(`Hello World`);
Here's an example of using prepend to add a paragraph to the document.
var element = document.createElement("p");
var text = document.createTextNode("Example text");
element.appendChild(text);
document.body.prepend(element);
result:
<p>Example text</p>
In order to simplify your life you can extend the HTMLElement object. It might not work for older browsers, but definitely makes your life easier:
HTMLElement = typeof(HTMLElement) != 'undefined' ? HTMLElement : Element;
HTMLElement.prototype.prepend = function(element) {
if (this.firstChild) {
return this.insertBefore(element, this.firstChild);
} else {
return this.appendChild(element);
}
};
So next time you can do this:
document.getElementById('container').prepend(document.getElementById('block'));
// or
var element = document.getElementById('anotherElement');
document.body.prepend(div);
In 2017 I know for Edge 15 and IE 12, the prepend method isn't included as a property for Div elements, but if anyone needs a quick reference to polyfill a function I made this:
HTMLDivElement.prototype.prepend = (node, ele)=>{
try { node.insertBefore(ele ,node.children[0]);}
catch (e){ throw new Error(e.toString()) } }
Simple arrow function that's compatible with most modern browsers.
var insertedElement = parentElement.insertBefore(newElement, referenceElement);
If referenceElement is null, or undefined, newElement is inserted at the end of the list of child nodes.
insertedElement The node being inserted, that is newElement
parentElement The parent of the newly inserted node.
newElement The node to insert.
referenceElement The node before which newElement is inserted.
Examples can be found here: Node.insertBefore
You can also use unshift() to prepend to a list
document.write() is not a good practice, some browsers like Chrome give you a warning if you use it, and it may be a bad solution if you are providing it to a customer, they don't want to use your code and see warnings in the debug console!
Also jQuery may also be a bad thing if you are giving your code to a customer who already uses jQuery for other functionality on their site, there will be a conflict if there is already a different version of jQuery running.
If you want to insert content into an iframe, and do that with pure JS, and with no JQuery, and without document.write(), I have a solution.
You can use the following steps
1.Select your iframe:
var iframe = document.getElementById("adblock_iframe");
2.Create an element that you want to insert into the frame, let's say an image:
var img = document.createElement('img');
img.src = "https://server-name.com/upload/adblock" + id + ".jpg";
img.style.paddingLeft = "450px";
//scale down the image is we have a high resolution screen on the client side
if (retina_test_media == true && high_res_test == true) {
img.style.width = "200px";
img.style.height = "50px";
} else {
img.style.width = "400px";
img.style.height = "100px";
}
img.id = "image";
3.Insert the image element into the iframe:
iframe.contentWindow.document.body.appendChild(img);
This is not best way to do it but if anyone wants to insert an element before everything, here is a way.
var newElement = document.createElement("div");
var element = document.getElementById("targetelement");
element.innerHTML = '<div style="display:none !important;"></div>' + element.innerHTML;
var referanceElement = element.children[0];
element.insertBefore(newElement,referanceElement);
element.removeChild(referanceElement);