Adding events to multiple childNodes in a for() respecting index - javascript

I need to implement a simple event and dom manipulation, but I can't use jQuery
So I am attaching the event to each single node using for()
document.addEventListener("DOMContentLoaded", function(event) {
var mainList = document.getElementById('mainList');
var mainNodes = document.querySelectorAll('#mainList > li');
for (var i = 0; i < mainNodes.length; i++) {
var node = mainNodes[i];
node.addEventListener('contextmenu', function(e){
e.preventDefault();
var currentActive = document.querySelectorAll('.active');
if(currentActive[0]) { // first item with class 'active'
currentActive[0].className = '';
}
this.className = 'active';
});
var options = node.getElementsByTagName('li');
for (var j = 0; j < options.length; j++) {
var option = options[j];
option.addEventListener('click', function(e){
e.preventDefault();
switch(this.className){
case 'eliminar':
delete(mainList,node);
break;
case 'obrir':
open(mainList,node);
break;
case 'clonar':
clone(mainList,node);
break;
}
node.className = '';
});
}
}
});
The problem here is that even that all elemnts have the event, its allways opened/cloned/deleted the last node,
Doesn't using var node applies only to the current node in the loop?
-fiddle-
http://jsfiddle.net/toniweb/Wx8Jf/34/

Your event handler will be triggered later. When the loop finishes, the node is the last node. You need to create a closure to capture the current node. Something like this:
for (var i = 0; i < mainNodes.length; i++) { (function(node){
//your code
}(mainNodes[i]))
}
Try:
for (var i = 0; i < mainNodes.length; i++) { (function(node){
//Your code
node.addEventListener('contextmenu', function(e){
e.preventDefault();
var currentActive = document.querySelectorAll('.active');
if(currentActive[0]) { // first item with class 'active'
currentActive[0].className = '';
}
this.className = 'active';
});
var options = node.getElementsByTagName('li');
for (var j = 0; j < options.length; j++) {
var option = options[j];
option.addEventListener('click', function(e){
e.preventDefault();
switch(this.className){
case 'eliminar':
delete(mainList,node);
break;
case 'obrir':
open(mainList,node);
break;
case 'clonar':
clone(mainList,node);
break;
}
node.className = '';
});
}
}(mainNodes[i]))
}

Related

Why do all divs have the same name?

I want to delete after clicking the product button, but it does not work properly I do not know why. It does not remove the correct object from the table
document.addEventListener('click', function(e) {
if (e.target.id === 'removeItem') {
var divWithItem = document.getElementsByClassName('containerBasket__allProducts__product');
// Pobieram name itemu
var nameItem = e.target.parentElement.parentElement.getAttribute('name');
var thisItemDiv = e.target.parentElement.parentElement;
var thisItem = JSON.parse(products[nameItem]);
products.splice(thisItem, 1);
localStorage.setItem('product', JSON.stringify(products));
thisItemDiv.remove();
for (var i = 0; i < products.length; i++) {
for (var j = 0; j < divWithItem.length; j++) {
divWithItem[j].setAttribute('name', [j]);
}
}
console.log(products);
}
});
Before looping
After looping
Why does a div with the same name?

How do i convert a Jquery code to Pure javascript

I am using Bootstrap.
I am not able to figure out how to put this in pure javascript.This will open a div when we click on the accordion.
$(function() {
$("#panelTicketsList .list-group-item").on("click", function() {
$("#panelTicketsList .list-group-item").removeClass('selected');
$(this).addClass('selected');
if ($('#panelTicketsList').hasClass('col-md-12')) {
$('#panelTicketsList').removeClass('col-md-12').addClass('col-md-3');
$('.panelTicketDetail').removeClass('hide');
}
});
});
jsFiddle : https://jsfiddle.net/tqdc6yyL/
var listGroupItems = document.getElementsByClassName('list-group-item');
for (j = 0; j < listGroupItems.length; j++) {
listGroupItems[j].addEventListener("click", function () {
var elements = listGroupItems;
for (i = 0; i < elements.length; i++) {
if (elements[i].className.indexOf("col-md-12") > -1) {
elements[i].className = elements[i].className.replace("col-md-12", "col-md-3");
elements[i].className = elements[i].className.replace("hide", "");
}
}
this.className = this.className + " selected";
});
}
var list = document.getElementById('panelTicketsList');
var items = document.querySelectorAll("#panelTicketsList .list-group-item");
var detail = document.querySelectorAll(".panelTicketDetail");
items.forEach(function(btn){
btn.addEventListener("click", function(){
items.forEach(function(item){ item.classList.remove("selected"); });
this.classList.add("selected");
if(list.classList.contains('col-md-12')) {
list.classList.remove('col-md-12');
list.classList.add('col-md-3');
detail.classList.add("hide");
}
});
If you have to support older browsers like IE8 or IE9, you can't use JS features like forEach or classList. Instead you should use for loop and className.
//Save DOM query in variable for reuse
var panelTicketsList = document.getElementById('panelTicketsList');
var panelTicketsDetails = document.getElementsByClassName('panelTicketDetail');
var listGroupItems = panelTicketsList.getElementsByClassName('list-group-item');
//go through all of the listGroupItems and set click listener
for (var i = 0; i < listGroupItems.length - 1; i++) {
listGroupItems[i].addEventListener("click", function() {
//On click, go through all of listGroupItems and remove selected class
for (var j = 0; j < listGroupItems.length - 1; j++) {
listGroupItems[j].className = listGroupItems[j].className.replace('selected', '');
}
//Add selected class for clicked element
listGroupItems[i].className += 'selected';
//test if main element has class col-md-12
if (panelTicketsList.className.indexOf("col-md-12") > -1) {
//replace clas col-md-12 with col-md-3
panelTicketsList.className = panelTicketsList.className.replace('col-md-12', 'col-md-3');
//go through all of the panelTicketDetails and remove hide class
for (var k = 0; k < panelTicketsDetails.length - 1; k++) {
panelTicketsDetails[k].className = panelTicketsDetails[k].className.replace('hide', '');
}
}
});
}

Improve code "content changer"

Im trying to improve my as I call it "contenthandler". What it does is that it changes different articles when I click different buttons. Im happy on how it works, but I feel this is not the best practise and I want some advices on how to maybe shorten it even more or use any other way to do this.
Im not intrested in any jQuery or other libaries at the moment.
document.addEventListener("click", function(e){
var article = document.getElementsByClassName("test"); // Article becomes an array.
var buttonClick = e.target.className;
switch (buttonClick){
case "one":
test(article);
article[0].style.display = "";
break;
case "two":
test(article);
article[1].style.display = "";
break;
case "three":
test(article);
article[2].style.display = "";
break;
}
function test(article){
for (var i = 0; i < article.length; i++){
article[i].style.display = "none";
}
}
});
//html
<ul>
<li class="buttonNav"><h2 class="one">Show 1</h2></li>
<li class="buttonNav"><h2 class="two">Show 2</h2></li>
<li class="buttonNav"><h2 class="three">Show 3</h2></li>
</ul>
<article class="test" style="display: none">1</article>
<article class="test" style="display: none">2</article>
<article class="test" style="display: none">3</article>
[Edit]
I remade the script from the answer I got, but I made a small change to it and made it dynamic so I do not need to hard code the "menu" in the script file.
var getClassName = document.querySelectorAll("h2");
var classNamesArray = [];
for (var i = 0; i < getClassName.length; i++){
classNamesArray.push(getClassName[i].className.toString());
};
document.addEventListener("click", function (e) {
var article = document.getElementsByClassName("test"); // Article becomes an array.
var buttonClick = e.target.className,
// Maintain list of class names in an order
validClassNames = classNamesArray,
index = -1;
for (var i = 0; i < validClassNames.length; i++) {
if (buttonClick === validClassNames[i]) {
index = i;
break;
}
}
if (index >= 0) {
test(article);
article[index].style.display = "";
}
});
function test(article) {
for (var i = 0; i < article.length; i++) {
article[i].style.display = "none";
}
}
One approach I can think of is
document.addEventListener("click", function (e) {
var article = document.getElementsByClassName("test"); // Article becomes an array.
var buttonClick = e.target.className,
// Maintain list of class names in an order
validClassNames = ["one", "two", "three"],
index = -1;
for (var i = 0; i < validClassNames.length; i++) {
if (buttonClick === validClassNames[i]) {
index = i;
break;
}
}
if (index >= 0) {
test(article);
article[index].style.display = "";
}
});
function test(article) {
for (var i = 0; i < article.length; i++) {
article[i].style.display = "none";
}
}
Also move the function definition to outside of the event handler.
Fiddle

Convert jquery into Angularjs

I have the following jquery method:
$('.niGridTable table tr').addClass('selected').end().click(function (event) {
event = event || window.event;
var isClassExist = false;
var closesedTable = $(event.target).closest('tr').find('.selected_row');
if (closesedTable.length > 0) {
isClassExist = true;
if (event.ctrlKey) {
for (var i = 0; i < closesedTable.length; i++) {
if ($(closesedTable[i]).hasClass('selected_row')) {
$(closesedTable[i]).removeClass('selected_row');
}
}
}
}
if (!event.ctrlKey) {
if ($('td').hasClass('selected_row')) {
$('td').removeClass('selected_row');
}
}
if (!isClassExist) {
$('.table-striped > tbody > tr:hover > td').addClass('selected_row');
}
});
I want to write such code as angular way.like...
element.on('click', function (event) {
}
In my directive I have changed my question said jquery to Angularjs. In this case I have use angular.element.
$timeout(function () {
//get all row for set selected row class
var trs = iElement.find('tr');
for (var index = 0; index < trs.length; index++) {
var tableTr = angular.element(trs[index]);
//remove prvious click event
tableTr.unbind('click');
tableTr.bind('click', function (event) {
event = event || window.event;
event.stopPropagation();
event.preventDefault();
//if target row contain previos selection then remove such selection
var isClassExist = false;
var targetTd = angular.element(event.target);
var targetTr = targetTd.parent();
if (targetTr.hasClass('selected_row')) {
targetTr.removeClass('selected_row');
isClassExist = true;
}
//if another row contain selection then remove their selection but if control button pressed then it will not work
var closesedTable = iElement.find('tr');
if (closesedTable.length > 0) {
if (!event.ctrlKey) {
for (var i = 0; i < closesedTable.length; i++) {
var eachRow = angular.element(closesedTable[i]);
if (eachRow.hasClass('selected_row')) {
eachRow.removeClass('selected_row');
}
}
}
}
//set selection
if (!isClassExist) {
targetTr.addClass('selected_row');
}
////get selected rows
//for (var j = 0; j < trs.length; j++) {
// gridOption['selectedRow'].push();
//}
});
}
}, 0);

Is it possible to delete/remove an entire "select" element, after you've emptied the options with .remove()?

Like, after you've emptied it with this:
var select = document.GetElementById("selector");
var length = select.options.length;
for (i = 0; i < length; i++) {
select.remove(select.options[i]);
}
Is it possible to remove the entire node by using:
select.parentNode.ChildNodes[1].remove();
afterwards, keeping in mind that I have the function remove() somewhere else, as followed:
Element.prototype.remove = function() {
this.parentElement.removeChild(this);
}
NodeList.prototype.remove = HTMLCollection.prototype.remove = function() {
for(var i = 0, len = this.length; i < len; i++) {
if(this[i] && this[i].parentElement) {
this[i].parentElement.removeChild(this[i]);
}
}
}
This doesn't seem to work for me. I can empty the select, but not remove it.
Try this:
var select = document.getElementsByTagName('select')[0];
if (select.parentNode.removeNode)
select.parentNode.removeNode(select);
else
select.parentNode.removeChild(select);
Demo

Categories