Hiding and showing classes with the same Class with jQuery - javascript

I'm creating a tool which generates a bunch of divs based on data I input into an array, however they all have the same class. The idea is that when one link is clicked it shows one of the ".catbox" divs and hides the rest.
All of these divs have the same class so I need to iterate through them, but I'm not quite sure how this is done with jQuery. Currently clicking on the last ".list" class triggers the on click event instead of all of them, and currently it shows all of the divs with the class ".catbox" instead of the corresponding one.
Here is the code:
var HTMLcatName = '<h1>%data%</h1>';
var HTMLcatImage = '<img id="cat" src="%data%">';
var HTMLcatCounter = '<p class="counter">Number of clicks: %data%</p>';
var HTMLcatList = '<p>%data%</p>'
var noCats = 'No cats selected m8';
var getCounterClass = document.getElementsByClassName("counter");
$(document).ready(function() {
cats.display();
$('.catbox').hide();
for (u = 0; u < cats.name.length; u++) {
formattedCatList = HTMLcatList.replace("%data%", cats.name[u]);
var listDiv = document.createElement('div');
listDiv.innerHTML = formattedCatList;
listDiv.className = "list";
$(".list").click(function() {
$(".catbox").toggle("slow");
});
$("body").prepend(listDiv);
}
});
var update = function() {
for (j = 0; j < getCounterClass.length; j++) {
getCounterClass[j].innerHTML = 'Number of clicks: ' + cats.clicks[j];
}
}
var cats = {
"name": ["Monte", "Jib"],
"image": ["images/monte.jpg", "images/jib.jpg"],
"clicks": [0, 0],
display: function () {
for (i = 0; i < cats.image.length; i++) {
formattedCatNames = HTMLcatName.replace("%data%", cats.name[i]);
formattedCatImages = HTMLcatImage.replace("%data%", cats.image[i]);
formattedCatCounter = HTMLcatCounter.replace("%data%", cats.clicks[i]);
var catDiv = document.createElement('div');
catDiv.className = "catbox";
catDiv.innerHTML = formattedCatNames + formattedCatImages + formattedCatCounter;
catDiv.querySelector('img').addEventListener('click', (function(catCountUp) {
return function() {
cats.clicks[catCountUp]++;
update();
};
})(i));
document.body.appendChild(catDiv);
}
},
}
The function I need help with is found within $(document).ready(function() {
Any help would be greatly appreciated.

The following can do it:
$(".list").on("click", function(){
$(this).find(".catbox").toggle("slow");
});

With $('.list') you get a group of elements of class list, so if you use $('.list').click(); you will bind the click event to just one element. You should use:
$(".list").each(function(){
$(this).click(function() {
$(".catbox").toggle("slow");
});
});

Related

Link Divblock with dynamic link

i'd like to link a divblock with the current position within the for-loop
Problem: all DivBlock get the link with the last position of the loop
my code is like this:
for (var i = 1; i <= kundenAnzahl; i++) {
var block = document.createElement("div");
block.id = i.toString();
document.getElementById(i.toString()).addEventListener('click', function() {
location.href = 'server.html?kunde='+i
}, true);
change var to let because -> https://wesbos.com/for-of-es6/
and you can assign event listeners directly to new created div element, look this code
for (let i = 0; i < 5; i++) {
var block = document.createElement('div');
block.addEventListener('click', function() {
location.href = 'server.html?kunde='+i;
}, true);
document.body.append(block);
}

javascript dynamically adding and removing classes [duplicate]

This question already has answers here:
How can I change an element's class with JavaScript?
(33 answers)
Closed 5 years ago.
I am working on a simple example, if a user clicks on element then all the elements above it should have a class and all elements below it should not have any class applied to them.
Here is my code:
<script>
function test(object) {
var pid = object.id;
var id = parseInt(pid.split("")[1]);
console.log(id);
for (var i = 1; i <= id; i++) {
var element = document.getElementById("p"+i);
console.log(element);
element.className = "active";
}
console.log(id+1);
for(var i = id+1; i <= 4; i++) {
var element = document.getElementById("p"+i);
element.className.replace(new RegExp('(?:^|\\s)'+ 'active' + '(?:\\s|$)'), ' ');
console.log(element);
}
}
</script>
<div id="divid">
<p id="p1" onclick="test(this)">one</p>
<p id="p2" onclick="test(this)">two</p>
<p id="p3" onclick="test(this)">three</p>
<p id="p4" onclick="test(this)">four</p>
</div>
So here if I click on three then the elements for one, two, three should have the class active and element four should not have any class. This is working fine.
Now if I click on one, I am expecting that two, three, four should have any css class but it is not working like that.
Can you please help me where is the issue. I want to use plain Javascript.
It might be wise to consider an alternative to using the onclick attribute due to separation of concerns. The following allows you to alter the HTML without having to consider JavaScript while you work.
https://jsfiddle.net/gseh0wxc/2/
var getList = (selector) => [].slice.call(document.querySelectorAll(selector));
var paragraphs = getList("#divid p[id ^= 'p']");
paragraphs.forEach((paragraph, index) => {
paragraph.addEventListener('click', (e) => {
for (let i = 0; i < index; i++) {
paragraphs[i].classList.remove('active');
}
for (let i = index; i < paragraphs.length; i++) {
paragraphs[i].classList.add('active');
}
});
})
Please try this code
function test(object) {
var pid = object.id;
var id = parseInt(pid.split("")[1]);
console.log(id);
for (var i = 1; i <= id; i++) {
var element = document.getElementById("p"+i);
element.classList.add("active");
}
console.log(id+1);
for(var i = id+1; i <= 4; i++) {
var element = document.getElementById("p"+i);
element.classList.remove("active");
}
}
Hope this helps.
try this simple approach instead, don't need to extract id number and all, and with a single simple loop.
function test(option) {
//this will select all p tags id starts with "p" inside div having id "divid" and return a array
var targetPTags = document.querySelectorAll("div#divid p[id^=p]")
var idx, flag=false;
//we are iterating over that array and taking each dom element in el
for(idx=0;idx<targetPTags.length;idx++) {
var el = targetPTags[idx];
if(flag) {
//do operation you want for after elements in el
} else if(option===el) {
flag=true; // we are making flag true when its the element that clicked and doing no operation
//do the operation you want for the element, may be the same as below operation in else
} else {
//do operation you want for before element in el
}
}
}
Kind of similar to "Chatterjee"'s solution, but here you go:
function test(object)
{
var parentElem = null;
var childElems = null;
var currElemSet = false;
var i=-1;
try
{
parentElem = object.parentElement;
if(parentElem!=null)
{
childElems=parentElem.getElementsByTagName(object.nodeName); // could refine to accommodate sibling nodes only
if(childElems!=null)
{
for(i=0;i<childElems.length; i++)
{
if(currElemSet) childElems[i].className = "";
else childElems[i].className = "active";
if(childElems[i]==object) currElemSet = true;
}
}
}
}
catch(e)
{
alert("Error: " + e.Message);
}
finally
{
}
}

vanilla javascript: element.close() not working on element

This is a Sudoko generator I'm programming in vanilla javascript:
Fiddle with code
Nicer looking full screen fiddle
If you click on one of the fields, a popup will be shown with 3x3 fields from 1 to 9. The problem is this popup can't be closed anymore, although I'm applying the close dialog.
The code how I'm generating the Sudoku board:
// create sudoku
function tableCreate() {
var body = document.getElementsByClassName("frame")[0];
var containerDiv = body.appendChild(document.createElement('div'))
containerDiv.className = 'container';
// create single cells with numbers
function createInnnerCells(parent, xx, yy) {
for (var x = 1; x <= 3; x++) {
for (var y = 1; y <= 3; y++) {
var abc = function () {
var div = parent.appendChild(document.createElement('div'))
var X = y+yy;
var Y = x+xx;
var id = 'x' + [X] + 'y' + [Y];
var cellValue = sudoku[X][Y]['value'] || '';
div.style.background = sudoku[X][Y]['background'] || 'white'
div.className = 'cell';
div.id = id;
var popover = createDialog(id);
popover.onclick = function() {
popover.close();
};
div.onclick = function() {
popover.show();
};
div.appendChild(popover);
div.appendChild(document.createTextNode(cellValue));
};
abc();
}
}
}
// create big cells for 3x3 single cells
for (var i = 0; i <= 6; i+=3) {
for (var j = 0; j <= 6; j+=3) {
var div = containerDiv.appendChild(document.createElement('div'))
div.className = 'block';
createInnnerCells(div, i, j);
}
}
}
Note that I apply the close() function to each cell:
popover.onclick = function() {
popover.close();
};
The code how I create the popup:
// create dialog
function createDialog(position){
var dialog = document.createElement('dialog');
dialog.id ='window_'+ position;
var dialogblock = dialog.appendChild(document.createElement('div'));
dialogblock.className = 'dialogblock';
for (var z = 1; z <= 9; z++) {
var div = dialogblock.appendChild(document.createElement('div'));
div.className = 'dialogcell';
div.id = position + 'z'+ z;
div.appendChild(document.createTextNode(position));
}
dialog.onclick = function() {
dialog.close();
};
return dialog;
}
I applied the close() dialog here as well
dialog.onclick = function() {
dialog.close();
};
I don't know why show() is working, but close() not?
DOM events bubble up the DOM through its parents. In your code, the dialog is a child of div. Therefore, a click event happens on dialog and then again on div which means you're closing and then opening the dialog.
You can stop the propagation of the event by using event.stopPropagation.
You can change your code like this:
popover.onclick = function(e) {
e.stopPropagation();
popover.close();
};
and
dialog.onclick = function(e) {
e.stopPropagation();
dialog.close();
};
modified your fiddle: http://jsfiddle.net/p40oahkd/9/
There's no method close() on the element you are trying to hide. You should either do element.style.display = "none" if you need to hide. Or do the following:
dialog.addEventListener('click', function() {
this.remove();
});
Check out this edit to your fiddle.

Stop output printing multiple times if function activated more than once

I'm activating a javascript function with a Jquery onclick button:
$('#on').click(function() {
var a = document.getElementsByTagName('a');
for (i = 0; i < a.length; i++) {
a[i].addEventListener('click', function() {
var span = document.createElement('span');
var text = document.createTextNode(this.innerHTML + " ");
span.appendChild(text);
document.getElementsByClassName('output')[0].appendChild(span);
})
}
});
The problem is if the button is clicked more than once the function will repeat more than once. In this case it will print the output multiple times. How can I modify the javascript function to only print one character per click?
Example:
http://jsfiddle.net/874Ljaq1/
Use the jQuery event binding method one
$('#on').one("click", function() {
var a = document.getElementsByTagName('a');
for (i = 0; i < a.length; i++) {
a[i].addEventListener('click', function() {
var span = document.createElement('span');
var text = document.createTextNode(this.innerHTML + " ");
span.appendChild(text);
document.getElementsByClassName('output')[0].appendChild(span);
})
}
});
You can use the jQuery .data() function to set a flag when the button has been clicked once, and only proceed if the flag is not set.
The code:
$('#on').click(function () {
// if we have a flag that indicates this button has been clicked before,
// don't do anything.
if ($(this).data('clicked'))
return;
$(this).data('clicked', true); // set the flag
var a = document.getElementsByTagName('a');
for (i = 0; i < a.length; i++) {
a[i].addEventListener('click', function () {
var span = document.createElement('span');
var text = document.createTextNode(this.innerHTML + " ");
span.appendChild(text);
document.getElementsByClassName('output')[0].appendChild(span);
})
}
});

return or send variable to onchange event

I am trying to achieve the same functionality of a function from two separate events. So the function I created is:
function adding_stuff() {
var names = [];
var dates = [];
for(var i = 0; i < this.files.length; i++) {
//adding stuff to names and dates
}
$(".primary .panel-content").append("<ul class='list-unstyled'></ul>");
for(var i in names) {
var li = "<li>";
$(".primary .panel-content ul").append(li.concat(names[i]))
}
}
There are two buttons primary and secondary. I want the same functionality for both the functions but the output in different <div>. Currently the selected <div> is ".primary", however I want this to depend on the button which has been clicked.
The function is triggered using:
$("#primary").onchange = adding_stuff;
$("#secondary").onchange = adding_stuff;
NOTE: primary and secondary are inputs of type file.
You can add additional data when you register the callback, which will be made available within the event handler:
$('#primary').on('change', { target: '.primary' }, adding_stuff);
$('#secondary').on('change', { target: '.secondary' }, adding_stuff);
and then within the handler:
function adding_stuff(ev) {
var cls = ev.data.target; // extract the passed data
...
// file handling code omitted
$(".panel-content", cls).append(...)
}
using jquery's change() event
function adding_stuff(obj,objClass) {
var names = [];
var dates = [];
for(var i = 0; i < obj.files.length; i++) {
//adding stuff to names and dates
}
$("."+ objClass+" .panel-content").append("<ul class='list-unstyled'></ul>");
for(var i in names) {
var li = "<li>";
$("."+ objClass+" .panel-content ul").append(li.concat(names[i]))
}
}
$("#primary").change(function(){
adding_stuff(this,'primary');
});
$("#secondary").change(function(){
adding_stuff(this,'secondary');
});
Try
function adding_stuff(opselector) {
return function() {
var names = [];
var dates = [];
for (var i = 0; i < this.files.length; i++) {
// adding stuff to names and dates
}
var ul = $("<ul class='list-unstyled'></ul>").appendTo(opselector)
for (var i in names) {
ul.append("<li>" + li.concat(names[i]) + "</li>")
}
}
}
$("#primary").change(adding_stuff('.primary .panel-content'));
$("#secondary").change(adding_stuff('.secondary .panel-content'));
You can use $(this).attr("class") inside the function. It will return the class of button who triggered the event.
function adding_stuff() {
var div = $(this).attr("class");
var names = [];
var dates = [];
for(var i = 0; i < this.files.length; i++) {
//adding stuff to names and dates to $div
}
$(div + " .panel-content").append("<ul class='list-unstyled'></ul>");
for(var i in names) {
var li = "<li>";
$(div + " .panel-content ul").append(li.concat(names[i]));
}
}

Categories

Resources