Jasch1
Jasch1

Reputation: 573

How to Add Rows/ Columns of Divs

Code is here: http://jsfiddle.net/jaredasch1/6dhc240q/5/

I know I've asked this question before, but I wasn't able to get a working answer for that. I'm working on a game where it starts out a 4 by 4 grid, and when you click on one of the divs, it toggles the color of the divs above, below, and next two the one being clicked on. This part is working perfectly fine, and when they are all the other color, they switch back to the original color. However, what I'm trying to do now has presented more of a challenge. Once they are all the second color, I want to add another column and row and reset them back to the original color.

This is where I have run into some trouble. For some reason, the grid isn't recreated. This is where you guys come in. I need hep writing a function or edits to my original script to make this happen. I have this all on a JSFiddle here

I'll also post all of the code here.

<!DOCTYPE html>
<body>
    <div id="button" class="on hover"></div>
<br>
    <div class="block hover"></div>
    <div class="block hover"></div>
    <div class="block hover"></div>
    <div class="block hover"></div>
<br>
    <div class="block hover"></div>
    <div class="block hover"></div>
    <div class="block hover"></div>
    <div class="block hover"></div>
<br>
    <div class="block hover"></div>
    <div class="block hover"></div>
    <div class="block hover"></div>
    <div class="block hover"></div>
<br>
    <div class="block hover"></div>
    <div class="block hover"></div>
    <div class="block hover"></div>
    <div class="block hover"></div>
</body>

The CSS

.block {
    height:100px;
    width:100px;
    border-radius:10px;
    display:inline-block;
    background-color:#33CCFF;
}
#button {
    height:100px;
    width:410px;
    border-radius:10px;
    display:inline-block;
    background-color:#FF6666;
    margin-bottom:10px;
}
.on {
    background-color:#D633FF;
}

The JavaScript/jQuery

var main = function () {
    var checkAll = function () {
        var allDivs = $("div.block");
        var classedDivs = $("div.block.on");

        var allDivsHaveClass = (allDivs.length === classedDivs.length);

        if (allDivsHaveClass) {
            allDivs.removeClass("on");
        }
    };
    $("div").mouseenter(function () {
        $(this).fadeTo("slow", 0.25);
        $(this).css('cursor', 'pointer');
    });
    $("div").mouseleave(function () {
        $(this).fadeTo("slow", 1);
        $(this).css('cursor', 'default');
    });
    $(".block").click(function () {
        $(this).toggleClass("on");
        $(this).prev().toggleClass("on");
        $(this).nextAll().eq(4).toggleClass("on");
        $(this).next().toggleClass("on");
        $(this).prevAll().eq(4).toggleClass("on");
        checkAll();
    });
    $("#button").click(function () {
        $(".block").removeClass("on");
    });
    $(document).keydown(function (key) {
        if (event.which === 32) {
            $(".block").removeClass("on");
        }
    });
};

$(document).ready(main);

Any help is welcome!

Upvotes: 2

Views: 7433

Answers (2)

balexandre
balexandre

Reputation: 75083

First of all, nice concept...

Secondly, you have some issues, let's start with the basics so you can move on with your game:

...it starts out a 4 by 4 grid...

have you ever ear the expression, if your code looks like copy/paste, you're doing it wrong? well, let's start with a grid:

your code to start is:

<br>
<div class="block hover"></div><div class="block hover"></div><div class="block hover"></div><div class="block hover"></div>
<br>
<div class="block hover"></div><div class="block hover"></div><div class="block hover"></div><div class="block hover"></div>
<br>
<div class="block hover"></div><div class="block hover"></div><div class="block hover"></div><div class="block hover"></div>
<br>
<div class="block hover"></div><div class="block hover"></div><div class="block hover"></div><div class="block hover"></div>

how about if you do this dynamic?

function buildGrid(elm, rows, columns){
    for(iRow = 0; iRow < rows; iRow++)
    {
        elm.append("<br>");
        for(iCol = 0; iCol < columns; iCol++)
        {
            elm.append('<div class="block hover"></div>');
        }
    }
}

and then just called:

buildGrid($("body"), 4, 4);

example: http://jsbin.com/tunun/1/edit?html,css,js,output

you can easily added the grid size in a global variable as

var globalRows = 4, globalColumns = 4;

$(function() {
  buildGrid($("body"), globalRows, globalColumns);
});

makes it easier to append rows/cols later on...


I want to add another column and row...

So, you want 2 things: add a new column/row and make all events work in the new add row/columns

1 - from the example above, you can simply do:

buildGrid($("body"), ++globalRows, ++globalColumns);

or more, manually:

globalRows++; // same as globalRows = globalRows + 1;
globalColumns++;  // same as globalColumns = globalColumns + 1;
buildGrid($("body"), globalRows, globalColumns);

2 - to make all evens work with the new dynamically added objects (html nodes) you need to change your javascript a bit, as when you do:

$("div").mouseenter(function () {
    $(this).fadeTo("slow", 0.25);
    $(this).css('cursor', 'pointer');
});

jQuery will attach that event to all EXISTING div's ... not the ones added after this code was executed, for that, jQuery has the method on and the code above would be written as:

$("body").on("mouseenter", "div", function () {
    $(this).fadeTo("slow", 0.25);
    $(this).css('cursor', 'pointer');
});

I hope this helps you on your task

Upvotes: 2

Stephan Muller
Stephan Muller

Reputation: 27600

While I think both your HTML and you JavaScript can use a lot more improvements, here's the bare minimum to get this working:

First of all, because the amount of blocks per row (and the amount of rows) is going to change, you can't use your hardcoded .eq(4) filter anymore. You will need to track a variable with that number and add 1 to it for every new level.

var blocksPerRow = 4;

Replace all hardcoded .eq(4) to .eq(blocksPerRow) now.

Whenever you want to add a new block to each row you will have to find a <br> element and add a new block after it. You can simply create a new block by cloning a random one (I chose the first one). Do use the true argument when cloning to also copy the events bound to it:

var newBlock = $('.block:first');
$('br').after( newBlock.clone(true) ); 

You also want to add an entire row, so you could either use the variable from before and add that many blocks, or just grab the last br plus all the items that follow and clone those. Append them after the last block.

var newRow = $('br:last').nextAll().andSelf();
$('.block:last').after( newRow.clone(true) );

Now is the time to also update your variable

blocksPerRow++;

Last thing to do is fix the styling. You use inline blocks and rely on the spaces between the elements to create whitespace. That breaks when you clone the last row, but it's better to rely on actual margins for spacing anyway. This did the trick:

.block {
    float: left;
    display: block;
    margin: 3px;
}
br {
    clear: both;
}

Here you see a working example: jsFiddle

As you can see I added a "cheat" button so you can quickly check for yourself that it works.

Upvotes: 3

Related Questions