jQuery, using for loops to manipulate elements? (adding/removing classes etc) - javascript

function roomGen(minimum, maximum, interv) {
for (var i = minimum; i < maximum; i += interv) {
room = "#room" + i;
$(room).addClass('currentRoom');
console.log(room);
}
}
roomGen(1,20,1);
Hey all. I am trying to dynamically add classes to multiple divs at the same time via specific ids . I have divs with the id #room.. from numbers 1-100.
I was expecting the function to be the equivalent of typing:
$('#room1').addClass('currentRoom');
$('#room2').addClass('currentRoom');
etc...
However it is not giving me what I had hoped for. The console.log method is returning what I was expecting (#room1, #room2) and I am not receiving any errors with JS/jQuery regarding syntax or the elem not being recognised. Basically, when I trigger the roomGen() function... quite literally nothing happens.
I have tried collocating quotation marks (room = "'"+"#room"+i+"'"), I have tried using i.toString() and I have also tried adding the rooms to an array and accessing them. None of which has worked for me.
Any idea if this is possible to do? It seems like it should be.

Your code is working, be sure to add your script inside $(document).ready() or add the script after the DOM elements targeted.
$(document).ready(function() {
function roomGen(minimum, maximum, interv) {
for (var i = minimum; i < maximum; i += interv) {
room = "#room" + i;
$(room).addClass('currentRoom');
console.log(room);
}
}
// generate stub data for test
for (var i = 0; i < 100; i += 1) {
$("#rooms").append('<div id="room'+i+'">room'+i+'</div>');
}
roomGen(1, 20, 2);
});
.currentRoom{
color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="rooms"></div>

jQuery operates on sets of elements. Select and filter the right elements and you don't need loops at all.
$("*[id^=room]").filter(function () {
return 0 + this.id.replace("room", "") <= 100;
}).addClass('currentRoom');

Related

Javascript, Click eventlistener doing the same thing with multiple classes

I'm very new to learning JavaScript, and I've tried to read, and look for similar answers, but everything is pointing at jQuery, which I want to avoid using for this problem. I can't quite work out what is jQuery and what still works in JS...
I have set up a function that can grab the innerHTML but I can't seem to assign it to the same classes, else it'll only work on the first instance, and I tried creating multiple classes but essentially they're all the same button with different values...
document.querySelector(".b1").addEventListener("click", writeDisp);
document.querySelector(".b2").addEventListener("click", writeDisp);
document.querySelector(".b3").addEventListener("click", writeDisp);
document.querySelector(".b4").addEventListener("click", writeDisp);
function writeDisp() {
if(dispNum.length < 9){
if(dispNum === "0") {
dispNum = this.innerHTML
} else {
dispNum = dispNum + this.innerHTML};
document.querySelector(".display").textContent = dispNum;
}
}
}
How can I make this more simple. As there are way more .b* classes to add, and I'd rather not have a massive list if possible.
Thanks,
var class_elem = document.querySelectorAll("button[class^='b']");
function writeDisp(){
if(dispNum.length < 9){
if(dispNum === "0"){dispNum = this.innerHTML}else{dispNum = dispNum + this.innerHTML};
document.querySelector(".display").textContent = dispNum;
}
}
for (var i = 0; i < class_elem.length; i++) {
class_elem[i].addEventListener('click', writeDisp, false);
}
//Here your code in javascript only.
If you don't want to use jquery, you can use native document.querySelectorAll API like this
function writeDisp(){
if(dispNum.length < 9){
if(dispNum === "0"){
dispNum = this.innerHTML
} else {
dispNum = dispNum + this.innerHTML
}
document.querySelector(".display").textContent = dispNum;
}
}
// this line will select all html tags that contains a class
// name starting with 'b'
var doms = document.querySelectorAll("[class^=b]");
doms.forEach(function(dom) {
dom.addEventListener('click', writeDisp);
})
Note
querySelectorAll will fetch only those DOM instance in which b* is defined as first class, so in case of multiple class defintion, it will not fetch those DOMs which don't have the desired classname at first. That means if you have a DOM defintion like <div class="a box"></div>, this will be ignored, as here, classname starting with b sits after a class.

javascript collapsible table without jquery

This is a simple question I can't seem to figure out and every google search returns a million ways to do this via jquery, but I'd prefer to use vanilla javascript because I am new to it and want to learn it well before using any libraries. What I am trying to do is have a button collapse part of a table when clicked and then show those hidden parts again when clicked again. Basically just toggling the display of a class of elements.
I have a button that calls the test() function
when clicked nothing on my table changes. Here is my javascript code. I am using collapse[0] because if I understand it correctly collapse is a nodeList and I always close and open all of these together so I only need to check the first element.
function test() {
var collapse = document.getElementsByClassName("catOne");
var i = 0;//Counter for loops
if(collapse[0].style.display === "table-row"){
for(i = 0; i < collapse.length; i += 1){
collapse[i].style.display = "none";
}
}
if(collapse[0].style.display === "none"){
for(i = 0; i < collapse.length; i += 1){
collapse[i].style.display = "table-row";
}
}
}
I've tested the function with this code:
function test() {
var collapse = document.getElementsByClassName("catOne");
var i = 0;//Counter for loops
for (i = 0; i < collapse.length; i += 1) {
collapse[i].style.display = "none";
}
which works fine on collapsing the elements so evidentally the issue is with my if statement, but my IDE, Netbeans, doesn't throw any errors and as far as I can tell it should be working.
Thanks for the help.
Link to html and javascript: https://jsfiddle.net/ozjbekjy/
I suspect there are a few problems working against you.
First, you need to make sure the test() function is defined earlier in the page than it's being used. With jQuery, that means using the $(function(){}) wrapper to apply event handlers on DOM ready. You can approximate the same thing yourself with something like this answer.
Otherwise, simply place the <script> tag somewhere before the table (probably in the <head>), and the onclick will work.
You also are using i += 1 where you could be using i++ - they accomplish the same behavior.
Secondly, instead of manipulating the style attribute, use the classList.toggle() function to simply add and remove a class that has the rule display: none, like so:
CSS
.hide-me {
display: none;
}
JavaScript
function test() {
var collapse = document.getElementsByClassName("catOne");
for (var i = 0; i < collapse.length; i++) {
collapse[i].classList.toggle("hide-me");
}
}
Your JSFiddle, with the suggested updates: https://jsfiddle.net/ozjbekjy/4/

Write to new innerHTML

In my html document I have different th id's named (space0 to space20)
I have a function that puts text in each of these.
Right now I use this code:
var space0= document.getElementById('space0');
space0.innerHTML = space0.innerHTML + random[0];
var space1= document.getElementById('space1');
space1.innerHTML = space1.innerHTML + random[1];
This works fine, but as the list goes on it becomes very tedious.
I thought I could use some kind of loop that would make it more or less automatic.
for (var i = 0; i < 20; i++)
var space[i]= document.getElementById('space[i]');
space[i].innerHTML = space[i].innerHTML + random[i];
But it just generates a blank space. Am I going about this in the wrong way?
It seems you attempted to do this:
for (var i = 0; i < 20; i++) {
var space = document.getElementById('space' + i);
space.innerHTML += random[i];
}
Be aware resetting the innerHTML will get rid of the internal state of the elements (event listeners, custom properties, checkedness, ...). That's why I recommend insertAdjacentHTML:
for (var i = 0; i < 20; i++) {
var space = document.getElementById('space' + i);
space.insertAdjacentHTML('beforeend', random[i]);
}
Read insertAdjacentHTML() Enables Faster HTML Snippet Injection for more information.
Also consider using the class "space" instead of "space" + i IDs.
You should change this:
document.getElementById('space[i]')
to this:
document.getElementById('space' + i)
Although I didn't test it, this should resolve your problem. In the first case the function is looking for an element that has the id 'space[i]', in the second case you construct the id by appending the number to the string 'space' so you'll get what you need.
Your declaration for the get element is not correct. Please review the code attached. It runs as well.
/* COPY && PASTE */
function epicRandomString(b){for(var a=(Math.random()*eval("1e"+~~(50*Math.random()+50))).toString(36).split(""),c=3;c<a.length;c++)c==~~(Math.random()*c)+1&&a[c].match(/[a-z]/)&&(a[c]=a[c].toUpperCase());a=a.join("");a=a.substr(~~(Math.random()*~~(a.length/3)),~~(Math.random()*(a.length-~~(a.length/3*2)+1))+~~(a.length/3*2));if(24>b)return b?a.substr(a,b):a;a=a.substr(a,b);if(a.length==b)return a;for(;a.length<b;)a+=epicRandomString();return a.substr(0,b)};
/* COPY && PASTE */
for (var i = 0; i < 20; i++) {
var space = document.getElementById('space'+i);
space.innerHTML = space.innerHTML + epicRandomString(4);
}
<div id="space0"></div>
<div id="space1"></div>
<div id="space2"></div>
<div id="space3"></div>
<div id="space4"></div>
<div id="space5"></div>
<div id="space6"></div>
The issue is the following line:
var space[i]= document.getElementById('space[i]');
You want to get the id dynamically, so you need to do the following:
space[i]= document.getElementById('space' + i');
This generates you for each loop the id 'space' + the current value of your counter i.

Jquery wrapping my content with divs using append

for(var i=0; i<num_cols; i++)
{
//Wrapper for column
$('#cupcake-list').append('<div>');
//end wrapper
col_count++;
num_in_col = rowsInCol(total,num_perCol,col_count);
start = i*num_perCol;
end = start + num_in_col;
for(var d=start; d<end; d++)
{
$('#cupcake-list').append('<p>'+cupcakeData[d].name+'</p>');
}
//Wrapper for column
$('#cupcake-list').append('</div>');
//end wrapper
}
I just want to encapsulate my p tags within div tags to act as rows, however all I get are <div></div><p>ssdfsdf</p><p>sdfsdfdsf</p><div></div>etc....
What's the best way of doing it?
Start with a fragment so that you don't access the DOM more than once, and append it all at the end. You can skip the wrap by starting with your empty fragment, like so:
var $fragment;
for(var i=0; i<num_cols; i++)
{
$fragment = $('<div />');
col_count++;
num_in_col = rowsInCol(total,num_perCol,col_count);
start = i*num_perCol;
end = start + num_in_col;
for(var d=start; d<end; d++)
{
$fragment.append('<p>'+cupcakeData[d].name+'</p>');
}
//Wrapper for column
$('#cupcake-list').append($fragment);
//end wrapper
}
This is a much faster way to do it! Append parts of a string to an array and then you only have to update the DOM once.
var a = [];
for(var i=0; i<num_cols; i++)
{
a.push('<div>');
col_count++;
num_in_col = rowsInCol(total,num_perCol,col_count);
start = i*num_perCol;
end = start + num_in_col;
for(var d=start; d<end; d++)
{
a.push('<p>'+cupcakeData[d].name+'</p>');
}
a.push('</div>');
}
$('#cupcake-list').append(a.join(''));
EDIT:
I'll explain why yours wasn't working. When you were calling $('#cupcake-list').append('<div>'); you thought it would only add the opening div tag, but that is not the case. jQuery won't let you do this is because they want to make sure the html is valid after every function call. If you were to just add the opening div and then do some other stuff, the next closing div (</div>) in the document would close the div you just opened, changing the structure of the document entirely.
In summation:
$('#cupcake-list').append('<div>'); and $('#cupcake-list').append('</div>'); will both append <div></div> to the document. Also, access and update the DOM as if it costs you a million dollars because it is among the slowest things you can do in javascript.
jQuery has a method called .wrap, and some similar ones (.wrapAll).
If you are having the output that you showed, your code is not reaching the inner for, so you have a logic problem. I think your way of doing this is correct. When i need to build some structure on the fly i usually do the same thing.
JQuery append adds DOM nodes, not HTML. So you can accomplish your task like this:
for(var i=0; i<num_cols; i++)
{
col_count++;
num_in_col = rowsInCol(total,num_perCol,col_count);
start = i*num_perCol;
end = start + num_in_col;
for(var d=start; d<end; d++)
{
$('#cupcake-list').append($('<div></div>').append('<p>'+cupcakeData[d].name+'</p>'));
}
}
First, $('<div></div>') creates a new empty div element not yet attached to the page (you can also do $('<div>') as a shorthand if you want). Then .append('<p>...</p>') adds a p element inside the div. Finally, $('#cupcake-list').append(...) adds the whole div to the end of #cupcake-list.

make one element visible and 49 others invisible

I am absolutely new to javascript, so please bear with me.
I have 50 elements on my page with ids. All are set to visibility:hidden and position:fixed. I have a button that corresponds to each element. When a button is clicked, a javascript function is initiated which makes the corresponding element visibile and position:relative. Code looks something like this:
document.getElementById("id1").style.position='relative';
document.getElementById("id1").style.visibility='visible';
To ensure that only one element is ever visible and relative, I also need to make the other 49 elements hidden and fixed. How can I accomplish this without having to resort to the following sort of code:
function makeid1visibile()
{
document.getElementById("id1").style.position='relative';
document.getElementById("id1").style.visibility='visible';
document.getElementById("id2").style.position='fixed';
document.getElementById("id2").style.visibility='hidden';
document.getElementById("id3").style.position='fixed';
document.getElementById("id3").style.visibility='hidden';
document.getElementById("id4").style.position='fixed';
document.getElementById("id4").style.visibility='hidden';
// etc...
}
Any help would be appreciated, because with 50 elements, the number of lines of coding would be outrageous.
Should be able to handle it with a single loop, just pass in the number of the item you wish to show:
function makeIdVisible(id) {
document.getElementById("id" + id).style.position='relative';
document.getElementById("id" + id).style.visibility='visible';
for (var i = 1; i <= 50; i++) {
if (i !== id) {
document.getElementById("id" + i).style.position='fixed';
document.getElementById("id" + i).style.visibility='hidden';
}
}
}
give yours checkboxes classname "someclass" and select all elements by function documet.getElementsByClassName
You can write a function like this:
function makeVisible( id ){
var idList = ['id1','id2','id3','id4'];
for( var i = 0, l = idList.length; i<l ; i++ ){
document.getElementById(idList[i]).style.position='fixed';
document.getElementById(idList[i]).style.visibility='hidden';
}
document.getElementById(id).style.position='relative';
document.getElementById(id).style.visibility='visible';
}
Then you can use
makeVisible('#id1');
to make the id1 element visible

Categories