Select Child ByClassName Javascript - javascript

I have many divs like the following rendering on the same page:
<div class="contentUser">
<div class="innerContent">
Some data
</div>
<div class="contentButtonWrap">
Some buttons
</div>
</div>
I need to trigger a style change on "contentButtonWrap" when "contentUser is clicked".
I don't know how I can select a child element of a certain class name. Notice that the number of elements that can be rendered within "contentUser" changes from div(contentUser) to div. But there is all ways only one "contentButtonWrap" element within "ContentUser".
This is what I have:
function avoidHover() {
var userDivs = document.getElementsByClassName('contentUser');
[].forEach.call(userDivs, function(e){
e.click = function(){
var target = e.getElementsByClassName('contentButtonWrap');
target[0].style.backgroundColor='green';
};
});
};

"onclick" instead of "click". Sorry about that...
function avoidHover() {
var userDivs = document.getElementsByClassName('contentUser');
[].forEach.call(userDivs, function(e){
e.onclick = function(){
var target = e.getElementsByClassName('contentButtonWrap');
target[0].style.backgroundColor='green';
};
});
};

Here is my take at it : http://jsfiddle.net/cdL51w2g/
function avoidHover() {
var userDivs = document.getElementsByClassName('contentUser');
for(var i=0; i<userDivs.length; i++){
userDivs[i].onclick = function(){
var target = this.getElementsByClassName('contentButtonWrap');
target[0].style.backgroundColor='green';
};
}
};
I changed the way to access the children in the parent divand used the function onclick instead of click in the question.

Related

Clone function and addEventListener in button inside

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.

Changing attributes with click and querySelector not fully functioning

I've written this to change the background of a div that represents hours on a daily planner. The first instance (onclick) works but the others don't. Do I need to give each .container their own id and their own function?
var changeStatus = document.querySelector("#changeStatus");
var container = document.querySelector(".container");
changeStatus.addEventListener("click", function () {
container.setAttribute("class", "filled");
}
querySelector() is designed to return a single element only. If there are multiple elements matching the .container selector then it will only return the first.
In your case you need to use querySelectorAll() to retrieve all relevant elements, then you need to loop through them to update the class.
var changeStatus = document.querySelector("#changeStatus");
var container = document.querySelectorAll(".container");
changeStatus.addEventListener("click", function () {
container.forEach(el => el.setAttribute("class", "filled"));
});
You can add click listener with loops, something like this:
changeStatus.addEventListener("click", function () {
for(var i=0; i<container.length; i++) {
container[0].setAttribute("class", "filled");
}
}
Here's an example with querySelectorAll as #pilchard answered above:
var changeStatus = document.querySelector("#changeStatus");
var containers = document.querySelectorAll(".container");
changeStatus.addEventListener("click", function () {
containers.forEach(function (container) {
container.setAttribute("class", "filled");
});
});
.filled {
color: #f00;
}
<button id="changeStatus">change status</button>
<div class="container">container 1</div>
<div class="container">container 2</div>
<div class="container">container 3</div>

Condense multiple lines of var = false code to less lines?

I have ten buttons. When one is clicked I want the corresponding div to fade in and when another button is clicked I want the div to fade out and the new div to fade in.
My method is not working correctly because my knowledge of JS is limited. I am currently running with something like this:
var active01 = false;
var active02 = false;
var active03 = false;
var active04 = false;
var active05 = false;
$("#button1").click(function () {
active02 = false;
active03 = false;
active04 = false;
active05 = false;
active01 = true;
});
if(active01){
//fadein;
} else{
//fadeout;
}
Is there a way to set all the active buttons to false without having to write everything out each time? Something like this....
var active01 = false;
var active02 = false;
var active03 = false;
var active04 = false;
var active05 = false;
var actives = active01, active02, active03, active04, active05;
$("#button1").click(function () {
actives = false;
active01 = true;
});
Optionally you could use data elements to help you out. For instance...
<input type="button" data-key="1">
<input type="button" data-key="2">
<div data-key="1"></div>
<div data-key="2"></div>
Given this setup you could have event handlers on the inputs. When on is clicked, fade all your divs. Then find the div that corresponds to your input with $('div').filter('[data-key="'+ $(this).data('key') +'"]') and then you can perform your fade in logic on it.
use an array
var active = [];
for(i = 0; i<10; i++){
active.push(false);
}
$("#button1").click(function () {
for(i = 0; i<active.length; i++){
active[i] = false;
}
active[1] = true;
});
I'd use it like this
$('.fade-target-container').on('click', function() {
var targetContainer = $(this).attr('data-target');
$('.fadeable-div').hide('fast');
$('#' + targetContainer).show('fast');
});
.fadeable-div {
display:none
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<button class="fade-target-container" data-target="div1">My Button 01</button>
<button class="fade-target-container" data-target="div2">My Button 02</button>
<button class="fade-target-container" data-target="div3">My Button 03</button>
<button class="fade-target-container" data-target="div4">My Button 04</button>
<button class="fade-target-container" data-target="div5">My Button 05</button>
<div class="fadeable-div" id="div1">DIV1</div>
<div class="fadeable-div" id="div2">DIV2</div>
<div class="fadeable-div" id="div3">DIV3</div>
<div class="fadeable-div" id="div4">DIV4</div>
<div class="fadeable-div" id="div5">DIV5</div>
Hard to give an exact answer without seeing the HTML, but I can give it to you in pseudocode and we can go from there.
You don't need variables to do this . . . from what you've stated, you want all the divs to be hidden, unless their associated button is clicked, and then, only that one div should show. You can do this with jQuery selectors pretty easily.
$(".commonButtonClass").on("click", function() {
$(".commonDivClass").fadeOut();
$("...SELECTOR_TO_FIND_THE_ASSOCIATED_DIV...").fadeIn();
});
Each div would need to have the commonDivClass class assigned to them and the buttons need to have the commonButtonClass assigned to them. then, based on whatever relationship ties the buttons to their specific divs, you would need to create the correct selector to replace "...SELECTOR_TO_FIND_THE_ASSOCIATED_DIV...".
Using this, you don't need to track the states of the divs, just make sure that they are all hidden, before you show the one that is paired with the button that was clicked.
(P.S. - If you provide the actual HTML, I can give you a more exact answer, but, hopefully, you can figure it out from what I've posted.)

Attaching Click Event to DIV Using jQuery Library

I am aware I can use the click function to attach an event to the DIV element but for some reason it is not working for me. Here is how I am creating the DIV element.
function createColorSwatchDiv(color) {
var colorSwatchDiv = $("<div>");
var image = $("<img>");
image.attr("src",color.imageURL);
var label = $("<label>");
label.text(color.title);
colorSwatchDiv.append(image);
return colorSwatchDiv;
}
Then I try to attach the click event like the following:
// run a loop and build the grid layout
for(index = 0; index < colors.length; index++) {
var colorSwatchDiv = createColorSwatchDiv(colors[index]);
// attach the event
colorSwatchDiv.click(function(){
alert('hello world');
});
colorsSection.append(colorSwatchDiv);
}
// add to the dom
$("#color .imageChartOption").after(colorsSection);
But it does not work and no click event is been attached.
following is the code
var $newdiv1 = $("<div id='object1' onClick=Test()>Hello</div>");
$("body").append($newdiv1);
function Test()
{
alert("Clicked");
}
OR
$newdiv1.on('click',function(){alert("hello");});
since you have created the div in a jQuery wrapper you don't need to wrap it again here $(colorSwatchDiv).click(.... Also, are you sure that the colorSwatchDiv variable is referencing the dom element and not the in memory element? Can you apply a class or anything to the elm in the dom?

Can I get the html element in an event trigger function in javascript?

Edit: I need to mention that I do not want to use jQuery.
This is my code. I need to access the element which triggered the event such that I don't have to make two different functions for each html element.
document.getElementById("login").onmouseover = turnWhite;
function turnWhite(e){
}
I need maybe something like this. Don't know if it's possible though.
function turnWhite(e){
e.HTMLEL.style.color = "white";
}
Is this possible?
According to javascripter.net
e.srcElement in Internet Explorer
e.target in most other browsers.
If you wanted to apply the same event function to a set of elements, you could try something like this:
var buttons = document.getElementsByClassName("change");
for(var i = 0;i < buttons.length;i++){
buttons[i].onmouseover = function(){
this.style.color = "red";
}
}
Demo: http://jsfiddle.net/louisbros/rt24U/
You should be able to use e.target or e.currentTarget. However, behavior seems to be different per browser... Best to use a library like jquery or yui. Here is some documentation.
Here is the JSFiddle so you can play with it: http://jsfiddle.net/9nr4Y/
HTML:
<div class="login">Login</div>
<br />
<div class="login">Login 2</div>
JavaScript:
(function() {
var elms = document.getElementsByClassName("login"),
l = elms.length, i;
for( i = 0; i < l; i++ ) {
( function( i ) {
elms[i].onmouseover = function() {
this.style.color = "#000000";
this.style.background = "#FFFFFF";
};
})(i);
( function( i ) {
elms[i].onmouseout = function() {
this.style.color = "#FFFFFF";
this.style.background = "#000000";
}
})(i);
}
})();
Create a self-invoking function that then gets the elements by a class name. The reason for this is because you don't really want to have more than one element with the ID anyway. Getting the class name will generate an Array of items that have that class. Then you can iterate over the new array and assign the event to each one of them.
Then we're getting each individual element with "this" instead of the actual event.
For reference:
How to get current element in getElementsByClassName
You could also go with this non-standard cross-browser hack:
document.getElementById("login").onmouseover = function () { turnWhite(); }
function turnWhite(){
var myEventElement = turnWhite.caller.arguments[0].target;
//do something with myEventElement
}
Useful if you want to avoid passing parrams.
Demo: http://codepen.io/mrmoje/pen/avbEm

Categories

Resources