The code
JavaScript:
var recurringF = (function(){
this.$el = $("#target");
this.arg = arguments[0];
this.spl = (!_.isEmpty(this.arg)) ? this.arg.split(" ") : false;
if(this.spl){
for(var i=0;i<this.spl.length;i++){
if(i===0){
this.$el.append(document.createElement(this.spl[i]));
}else{
this.$el.children().last().append(document.createElement(this.spl[i]));
}
}
}
return {
"$":this.$el
}
});
var t = new recurringF("div h1 span");
HTML-Body:
<body>
<div id="target"></div>
</body>
The Goal
I'd like to append elements sequentially to an parent element $("#target") so that the end result in the HTML is the following:
<body>
<div id="target">
<div>
<h1>
<span></span>
</h1>
</div>
</div>
</body>
The loop does not append the created elements to the the last appended element, but to the in loop cycle 1 created element 'div' like the following:
<div id="target">
<div>
<h1></h1>
<span></span>
</div>
</div>
What am I missing?
By using .children(), you'll only get the immediate div on every iteration after the first, thus resulting in
<div id="target">
<div>
<h1></h1>
<span></span>
<alltherest></alltherest>
</div>
</div>
because .children only looks at children, not all descendants. What you want is .find(*) so that it will get the deepest nested descendant on each iteration.
this.$el.find('*').last().append(document.createElement(this.spl[i]));
https://jsfiddle.net/f3fb997h/
That said, it would be better if you just stored a reference to the last created element and append to it, rather than having to reselect it every iteration.
var $tempEl = this.$el, newEl;
if(this.spl){
for(var i=0;i<this.spl.length;i++){
newEl = document.createElement(this.spl[i]);
$tempEl.append(newEl);
$tempEl = $(newEl);
}
}
https://jsfiddle.net/f3fb997h/1/
Note that at this point you're not really benefiting from jQuery at all, so a small tweak and you're not depending on it.
var recurringF = (function(){
this.el = document.getElementById('target');
this.arg = arguments[0];
this.spl = (!_.isEmpty(this.arg)) ? this.arg.split(" ") : false;
console.log(this.spl);
var tempEl = this.el, newEl;
if(this.spl){
for(var i=0;i<this.spl.length;i++){
newEl = document.createElement(this.spl[i]);
tempEl.appendChild(newEl);
tempEl = newEl;
}
}
return {
"el":this.el
}
});
You can try using regular javascript functionality, as it has child appending built in:
const recurseElement = (elementString, target) => {
const elements = elementString.split(' ');
elements.forEach(function(ele) {
const domElement = document.createElement(ele); // create the element
target.appendChild(domElement); // append to the target
target = domElement; // this element is the new target
});
}
So now you can use it like so:
recurseElement('div h1 span', document.getElementById('target'));
const recurseElement = (elementString, target) => {
const elements = elementString.split(' ');
elements.forEach(function(ele) {
const domElement = document.createElement(ele); // create the element
target.appendChild(domElement); // append to the target
target = domElement; // this element is the new target
});
};
recurseElement('div h1 span', document.getElementById('target'));
#target div {
background: green;
height: 16px; width: 128px; padding: 10px;
}
#target div h1 {
background: red;
height: 16px; width: 64px; padding: 10px;
}
#target div h1 span {
background: purple; display: block;
height: 16px; width: 32px; padding: 10px;
}
<div id="target"></div>
It should be noted that arrow functions are available for Chrome 45+, Firefox 22.0+, Edge, and Opera. They do not work in IE or Safari. Or they will work if you have a transpiler (like babel)
Related
I have a div container with a certain number of div's created with a for loop inside of it. When i click one of these a divs, i need to make it change the colour. My problem is can't figure out how to select an specific element with the addEventListener to change the color.
<body>
<div id="main-container"></div>
<script src="script.js"></script>
</body>
const mainContainer = document.getElementById("main-container");
for (let i = 0; i <= 11; ++i) {
const gridChildrens = document.createElement("div");
gridChildrens.setAttribute("class", `gridChildrens`);
const grids = document.querySelector('.gridChildrens')
mainContainer.appendChild(gridChildrens);
}
For the moment, i figure out how to change the color of the firt or the last of the elements with a click listener, but not for the rest of the of the divs.
For the moment, i figure out how to change the color of the firt or the last of the elements with a click listener, but not for the rest of the of the divs.
I expect to click any of the divs and change the color.
Try to add an event listener to each div created in the loop and then use 'this' to set your colour. Here's an example :
const mainContainer = document.getElementById("main-container");
for (let i = 0; i <= 11; ++i) {
const gridChildrens = document.createElement("div");
gridChildrens.setAttribute("class", `gridChildrens`);
gridChildrens.addEventListener('click', function() {
this.style.backgroundColor = 'red';
});
mainContainer.appendChild(gridChildrens);
}
Code snippet sample:
<html>
<head>
<style>
.gridChildrens {
width: 50px;
height: 50px;
background-color: blue;
margin: 10px;
}
</style>
</head>
<body>
<div id="main-container"></div>
<script>
const mainContainer = document.getElementById("main-container");
for (let i = 0; i <= 11; ++i) {
const gridChildrens = document.createElement("div");
gridChildrens.setAttribute("class", `gridChildrens`);
gridChildrens.addEventListener('click', function() {
this.style.backgroundColor = 'red';
});
mainContainer.appendChild(gridChildrens);
}
</script>
</body>
</html>
To explicitly target an element the querySelector without click event (which will inspect the event.target ) you can use the nth-child or nth-of-type style css selector as below.
To identify an element based upon user click the event itself will expose the target property which will be the element that caused the event handler to fire. The following uses a delegated event listener bound to the document itself which processes all click events if required but here responds only to those bound to the gridChildrens elements
const mainContainer = document.getElementById("main-container");
for (let i = 0; i <= 11; ++i) {
const div = document.createElement("div");
div.setAttribute("class", `gridChildrens`);
div.textContent=i;
mainContainer.appendChild( div );
}
document.querySelector('.gridChildrens:nth-of-type(4)').classList.add('banana')
document.querySelector('.gridChildrens:nth-of-type(7)').classList.add('banana')
document.querySelector('.gridChildrens:nth-of-type(10)').classList.add('banana')
document.addEventListener('click',e=>{
if( e.target instanceof HTMLDivElement && e.target.classList.contains('gridChildrens') ){
e.target.classList.toggle('tomato')
}
})
.gridChildrens{
width:50%;
height:1rem;
margin:0.25rem;
}
.banana{
background:yellow
}
.tomato{
background:tomato
}
<div id="main-container"></div>
This should give you a good idea of how to use addEventlistner. Basically, you can pass the event object whenever you make some event. That has all the information of the specific div that you are looking for, you can change anything with that. But remember to bind the elements with addEventlistner first.
var containers= document.getElementsByClassName("container");
const changeColor = (e)=>{
if(e.target.style.background =="orange"){
e.target.style.background ="red"
}
else
e.target.style.background ="orange";
}
for(var i=0; i< containers.length; i++){
containers[i].addEventListener('click',function(e){
changeColor(e)
} );
}
.container{
height:50px;
width:100px;
background: #000;
margin :10px 10px;
border-radius:10px;
cursor:pointer;
}
.holder{
display:flex;
flex-wrap:wrap;
}
<div class="holder">
<div class="container"></div>
<div class="container"></div>
<div class="container"></div>
<div class="container"></div>
<div class="container"></div>
</div>
There are several ways to do this. For example, you can add the same class to your divs inside the loop. Then you can access them via document.querySelectorAll('.class-name'). So smth like this:
[...document.querySelectorAll('.class-name')].forEach( el => {
el.addEventListener('click', (e) => { changeColor(e); });
});
I'm trying to add a link to a pseudo element, but not the parent element. I'm brand new to javascript, and after doing a lot of research I've been able to add a link to both the parent and pseudo elements, but I don't want the parent to be linked. It unfortunately will have to be a pseudo element because I don't have the option of adding another div to the html.
I have a fiddle which is kind of a mash of a few different fiddles I've found. Please let me know if I'm on the right track, or if this is even possible. And let me know if there is any additional information I can provide.
One more thing to note, is that the parent div will have child divs as a menu, which is why I'd prefer the parent not be clickable. But after testing (at least in the fiddle as it is now) the child links are still be clickable and correct, and these will still need to be clickable as well.
Thanks!
http://jsfiddle.net/mqb9juhn/1/
<div id="example">
<div class="example-child">
Test Test 2
</div>
</div>
#example {
position: relative;
}
#example::before {
content: "click here"!important;
font-size: 16px;
display: block;
padding: 20px;
background-color: #ffff00;
top: 0;
}
var UID = {
_current: 0,
getNew: function(){
this._current++;
return this._current;
}
};
HTMLElement.prototype.pseudoStyle = function(element,prop,value){
var _this = this;
var _sheetId = "pseudoStyles";
var _head = document.head || document.getElementsByTagName('head')[0];
var _sheet = document.getElementById(_sheetId) || document.createElement('style');
_sheet.id = _sheetId;
var className = "pseudoStyle" + UID.getNew();
_this.className += " "+className;
_sheet.innerHTML += "\n."+className+":"+element+"{"+prop+":"+value+"}";
_head.appendChild(_sheet);
return this;
};
$(document).ready(function(){ $("#example").on('click', function(){
window.location = "http://www.google.com/";});
});
var div = document.getElementById("example");
div.pseudoStyle("before","color","#ff0000");
In my example fiddle I get the .innerText of my clicked Element. How can I get on this way (or a better?) the index of my clicked item?
Without jQuery would be awesome because I want to learn living without jQuery :D
var el = document.getElementsByClassName("lol");
for(var i = 0; i < el.length; i++ ) {
el[i].addEventListener("click", function(e) {
console.log(e.target.innerText)
});
}
https://jsfiddle.net/y6s8c1y8/2/
getElementsByClassName Returns an array-like object of all child elements which have all of the given class names. As we are suppose to use Array#indexOf method, input has to be array
Use Array#from, it creates a new Array instance from an array-like or iterable object.
Use Array#indexOf to get the index of element
var el = document.getElementsByClassName("lol");
var arrElems = Array.from(el);
//Or var arrElems = [].slice.call(el);
for (var i = 0; i < el.length; i++) {
el[i].addEventListener("click", function(e) {
console.log("text is: " + e.target.innerText);
console.log("Index is: " + arrElems.indexOf(e.target));
});
}
.lol {
width: 100px;
height: 100px;
background: #000;
float: left;
margin-right: 5px;
}
<div class="lol">
1
</div>
<div class="lol">
2
</div>
<div class="lol">
3
</div>
<div class="lol">
4
</div>
Fiddle Demo
I've created a sample file that has adding and removing children elements in a mother element. The adding was successful, but I'm having a problem in removing children elements. The goal is every single click of remove button removes a child element.
var adds = document.querySelector('#add');
var remove = document.querySelector('#remove');
var section = document.querySelector('section');
var div;
adds.onclick = function() {
div = document.createElement('div');
section.appendChild(div);
div.classList.add('style');
};
// THE PROBLEM
remove.onclick = function() {
while(section.children.length !== 0) {
for(var c in section.children) {
section.removeChild(div[c]);
}
}
};
section {
display: flex;
background: #0ff;
height: 100px;
padding: 8px;
}
section > div {margin: 0 1px;}
.style {
width: 100px;
height: 100px;
background: lightgreen;
}
<button id="add">Add</button>
<button id="remove">Remove</button>
<section class="container"></section>
<br>
What's wrong with my code?
What's wrong with my code?
This line
section.removeChild(div[c]);
div could be undefined here and anyways, sections's children are not necessarily div's children
so change it to
section.removeChild(section.children [c]);
Also, while is not necessary
remove.onclick = function() {
for(var c in section.children) {
section.removeChild(section.children[c]);
}
};
EDIT
The goal is every single click of remove button removes a child
element.
remove.onclick = function() {
if(section.children length ) {
section.removeChild(section.children[0]);
}
};
changed for with if
The following code copies all elements given one css class, that's fine, it does render the list of elements... Now I'd like to wrap those results in HTML content, how can I achieve that?
setTimeout(function() {
var element = document.getElementById("unique_ID");
element.innerHTML = "";
Array.prototype.forEach.call(document.querySelectorAll(".a_random_class"), function(e) {
var storednode = element.appendChild(e.cloneNode(true));
});
}, 300);
How can I wrap in HTML content each of the storednode? I've been able to apply classes: storednode.className += " another-class";, but how can I wrap the results in any HTML I want? is that possible?
Thank you for your time.
Edit:
This is what the script does.
setTimeout(function() {
var element = document.getElementById("unique_ID");
element.innerHTML = "";
Array.prototype.forEach.call(document.querySelectorAll(".a_random_class"), function(e) {
element.appendChild(e.cloneNode(true));
});
}, 300);
#unique_ID {
border: 1px solid blue;
}
<div id="unique_ID"></div>
<div class="a_random_class">a</div>
<div class="a_random_class">b</div>
<div class="a_random_class">c</div>
<div class="a_random_class">d</div>
<div class="a_random_class">e</div>
<div class="a_random_class">f</div>
What I need is that each result, for example <div class="a_random_class">f</div> can be wrapped inside any HTML code I want, to get something like <div id="another-div" class="a-class" style="maybe:styles"><li><div class="a_random_class">f</div></li></div> This is certainly an example, but I'd like to know if that's possible... Not only copy the class elements but also append some HTML on them.
I think what you are looking for is something like
setTimeout(function () {
var element = document.createElement('div');
element.className = 'something';
[].forEach.call(document.querySelectorAll(".a_random_class"), function (e) {
var wrap = element.cloneNode(true);
e.parentNode.insertBefore(wrap, e)
wrap.appendChild(e);
});
}, 300);
setTimeout(function() {
var element = document.createElement('div');
element.className = 'something';
[].forEach.call(document.querySelectorAll(".a_random_class"), function(e) {
var wrap = element.cloneNode(true);
e.parentNode.insertBefore(wrap, e)
wrap.appendChild(e);
});
}, 300);
.something {
border: 1px solid red;
padding: 5px;
margin-bottom: 5px;
}
.a_random_class {
background-color: lightgrey;
}
<div class="a_random_class">a</div>
<div class="a_random_class">b</div>
<div class="a_random_class">c</div>
<div class="a_random_class">d</div>
<div class="a_random_class">e</div>
<div class="a_random_class">f</div>