Limit Selectable DOM Checkboxes - javascript

I am trying to limit the number of checkboxes a user can select. These checkboxes are DOM input objects generated for each item in an array. I'm having no luck with this currently, so any help is much appreciated. Thanks!
Fiddle Here: http://jsfiddle.net/vVxM2/222/
names =["Donny","Danny","Ricky","Eric","Jamie","Bobby","Booby"];
var numberOf = names.length;
var text = "<ul>";
for (i = 0; i < numberOf; i++) {
text += "<li class='playerListItem'><label><input type='checkbox' class='playerCheckbox'>" + names[i] + "</label></li>";
}
text += "</ul>";
document.getElementById("recentPlayersContainer").innerHTML = text;
var limit = 3;
$('input.playerCheckbox').on('change', function(event) {
if($(this).siblings(':checked').length >= limit) {
this.checked = false;
}
});

Your problem is in the change event.
Instead of doing:
if($(this).siblings(':checked').length >= limit)
You should do this:
if($('.playerCheckbox:checked').length >= limit)
Also, if your limit is maximum 3 checked, then you should do:
$('.playerCheckbox:checked').length > limit
Because when the event change is raised, the current checkbox is already checked.

Your problem was found here: if($(this).parent().siblings().children(":checkbox:checked").length >= limit). You actually have two parents, so you should have added another parent() and children() function. It should look like if($(this).parent().parent().siblings().children().children(":checkbox:checked").length >= limit)
names = ["Donny", "Danny", "Ricky", "Eric", "Jamie", "Bobby", "Booby"];
var numberOf = names.length;
var text = "<ul>";
for (i = 0; i < numberOf; i++) {
text += "<li class='playerListItem'><label><input type='checkbox' class='playerCheckbox'>" + names[i] + "</label></li>";
}
text += "</ul>";
document.getElementById("recentPlayersContainer").innerHTML = text;
var limit = 3;
$('input.playerCheckbox').on('change', function() {
if ($(this).parent().parent().siblings().children().children(":checkbox:checked").length >= limit) {
$(this).attr('checked', false);
alert('You can only select 3 checkboxes.');
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="recentPlayersContainer">
</div>

DEMO
names =["Donny","Danny","Ricky","Eric","Jamie","Bobby","Booby"];
var numberOf = names.length;
var text = "<ul>";
for (i = 0; i < numberOf; i++) {
text += "<li class='playerListItem'><label><input type='checkbox' class='playerCheckbox'>" + names[i] + "</label></li>";
}
text += "</ul>";
document.getElementById("recentPlayersContainer").innerHTML = text;
var limit = 3;
$('input.playerCheckbox').on('change', function(event) {
if($('input.playerCheckbox:checked').length >= limit + 1) {
alert('enough');
}
});

Related

HTML + JS - Trying to surround some content that is created with a for loop with a div

I am coding an adventure game and have a primitive sortInventory() function. It cycles through the player.inventory array and displays each item in its own <div>. I want to surround the entire completed 'inventory' with a <div class="inv"> - here are the functions:
function sortInventory() {
var rowCount = 0;
var firstRowDone = false;
for(var i = 0; i < player.inventory.length; i++) {
rowCount++;
if(rowCount == 6 && firstRowDone == false) {
firstRowDone = true;
rowCount = 0;
dock.innerHTML += "<br>"
}
if(rowCount == 5 && firstRowDone) {
dock.innerHTML += "<br>"
rowCount = 0;
}
dock.innerHTML += "<div class='inv-item'><img class='inv-img' src='" + player.inventory[i].img + "'></img></div>";
}
}
function showInventory() {
dock.innerHTML = "<div class='inv'>";
sortInventory();
dock.innerHTML += "</div>"
}
This currently outputs:
<div class="inv"></div>
<div class="inv-item">..</div>
<div class="inv-item">..</div>
<!-- and so on -->
But I would like it to output:
<div class="inv">
<div class="inv-item">..</div>
<div class="inv-item">..</div>
<!-- and so on -->
</div>
How could I get it to achieve this and why does it close the tag early? Thanks in advance.
Instead of trying to write it in pieces, store it in a variable and write it all at once.
function sortInventory() {
var rowCount = 0;
var invList = '';
for(var i = 0; i < player.inventory.length; i++) {
rowCount++;
if(rowCount == 6 && firstRowDone == false) {
firstRowDone = true;
rowCount = 0;
dock.innerHTML += "<br>"
}
if(rowCount == 5 && firstRowDone) {
dock.innerHTML += "<br>"
rowCount = 0;
}
invList += "<div class='inv-item'><img class='inv-img' src='" + player.inventory[i].img + "'></img></div>";
}
return invList;
}
function showInventory() {
dock.innerHTML = "<div class='inv'>" + sortInventory() + "</div>";
}
This is happening because an open tag cannot live within the DOM without a close tag, with few exceptions like <br /> which is still valid as <br >, so most browsers will try to compensate for this and write the close tag for you.
In short, writing incrementally into the innerHTML tag is always a bad idea and will lead to unexpected results as most all browsers will try to correct it.
Using innerHTML can be cumbersome, not to mention (at times) dangerous. Instead, I would use the document.createElement and Node.appendChild methods.
function sortInventory() {
var rowCount = 0;
var inv = document.createElement('div');
inv.classList.add('inv');
for(var i = 0; i < player.inventory.length; i++) {
rowCount++;
if(rowCount == 6 && firstRowDone == false) {
firstRowDone = true;
rowCount = 0;
inv.appendChild(document.createElement('br'));
}
if(rowCount == 5 && firstRowDone) {
inv.appendChild(document.createElement('br'));
rowCount = 0;
}
var invItem = document.createElement('div');
invItem.classList.add('inv-item');
var invImg = document.createElement('img');
invImg.classList.add('inv-img');
invImg.setAttribute('src', player.inventory[i].img);
invItem.appendChild(invImg);
inv.appendChild(invItem);
}
dock.appendChild(inv);
}
function showInventory() {
sortInventory();
}
I think it closes the tag prematurely because the value received by .innerHTML removes all of the element's descendants and replaces them with nodes constructed by parsing the HTML given in the string. With constructed nodes, it means (in this case) if there is any unclosed tag, it will close it first (so it is a constructed node).
So in order to solve this, first build the string, and finally use the innerHTML in order to set the built value.
Following your logic, it would be something like this:
var newHtml = "";
function sortInventory() {
var rowCount = 0;
for(var i = 0; i < player.inventory.length; i++) {
rowCount++;
if(rowCount == 6 && firstRowDone == false) {
firstRowDone = true;
rowCount = 0;
newHtml += "<br>"
}
if(rowCount == 5 && firstRowDone) {
newHtml += "<br>"
rowCount = 0;
}
newHtml += "<div class='inv-item'><img class='inv-img' src='" + player.inventory[i].img + "'></img></div>";
}
}
function showInventory() {
newHtml = "<div class='inv'>";
sortInventory();
newHtml += "</div>"
dock.innerHTML = newHtml;
}
In order to create a wrapper element with the class .inv around the elements with .inv-item classes, construct the HTML content at a string in the sortInventory function, then return as the content to use, when setting the dock element's innerHTML:
var boxIcon = 'https://image.flaticon.com/icons/svg/122/122186.svg';
var player = {
inventory: [
{img: boxIcon},
{img: boxIcon},
{img: boxIcon}
]
};
var dock = document.getElementById('dock');
function sortInventory(inv) {
var rowCount = 0;
var content = ''
for (var i = 0; i < player.inventory.length; i++) {
rowCount++;
if (rowCount == 6 && firstRowDone == false) {
firstRowDone = true;
rowCount = 0;
content += "<br>"
}
if (rowCount == 5 && firstRowDone) {
content += "<br>"
rowCount = 0;
}
content += "<div class='inv-item'><img class='inv-img' width='32px' src='" + player.inventory[i].img + "'></img></div>";
}
return content;
}
function showInventory() {
dock.innerHTML = "<div class='inv'>" + sortInventory() + "</div>";
}
showInventory();
.inv {
background: #CCC;
}
<div id="dock"></div>
Credits to Flaticon
You could first create the item with the class "inv" and then get it by class name with document.getElementByClassName("inv") and then add with a forloop document.getElementByClassName("inv").innerHtml += <div class="inv-item">..<div>
Construct the HTML string completely then assign to innerHTML of the div, instead of assigning innerHTML 3 times.
Change sortInventory function to return string, append all the string and assign it as innerHTML at once.

How do I input a number / time of 01:10 from my code?

I have this working code below to input a number/tme in textbox. This code below is functioning well but I want to set my textbox value into 00:00 and edit my function code like the second jsfiddle however my edited code is not going well as my idea. In my second jsfiddle I want to input a time of 05:30 but the code is replacing any number that input by a user from the textbox 0
function MaskedTextboxDPSDeparture() {
var myMask = "__:__";
var myCorrectionOut2 = document.getElementById("Departure");
var myText = "";
var myNumbers = [];
var myOutPut = ""
var theLastPos = 1;
myText = myCorrectionOut2.value;
//get numbers
for (var i = 0; i < myText.length; i++) {
if (!isNaN(myText.charAt(i)) && myText.charAt(i) != " ") {
myNumbers.push(myText.charAt(i));
}
}
//write over mask
for (var j = 0; j < myMask.length; j++) {
if (myMask.charAt(j) == "_") { //replace "_" by a number
if (myNumbers.length == 0)
myOutPut = myOutPut + myMask.charAt(j);
else {
myOutPut = myOutPut + myNumbers.shift();
theLastPos = j + 1; //set current position
}
} else {
myOutPut = myOutPut + myMask.charAt(j);
}
}
document.getElementById("Departure").value = myOutPut;
document.getElementById("Departure").setSelectionRange(theLastPos, theLastPos);
}
document.getElementById("Departure").onkeyup = MaskedTextboxDPSDeparture;
HTML
< input id="Departure" type="text" style="width: 35px; text-align: center" value="__:__" />
JSFIDDLE
JSFIDDLE 2
Any suggestion will accepted. Thanks.

Add alphabets dynamically as html row increments

How to ensure i have a dynamic increment of Alphabets in a new cell on left side, next to each cell in a row which is dynamically created based on the option chosen in Select. This newly generated alphabet will be considered as bullet points/serial number for that particular row's text box.
jsfiddle
js code
$(document).ready(function(){
var select = $("#Number_of_position"), table = $("#Positions_names");
for (var i = 1; i <= 100; i++){
select.append('<option value="'+i+'">'+i+'</option>');
}
select.change(function () {
var rows = '';
for (var i = 0; i < $(this).val(); i++) {
rows += "<tr><td><input type='text'></td></tr>";
}
table.html(rows);
});
});
html
<select id="Number_of_position">
</select> <table id="Positions_names">
</table>
This is essentially a base26 question, you can search for an implementation of this in javascript pretty easily - How to create a function that converts a Number to a Bijective Hexavigesimal?
alpha = "abcdefghijklmnopqrstuvwxyz";
function hex(a) {
// First figure out how many digits there are.
a += 1; // This line is funky
var c = 0;
var x = 1;
while (a >= x) {
c++;
a -= x;
x *= 26;
}
// Now you can do normal base conversion.
var s = "";
for (var i = 0; i < c; i++) {
s = alpha.charAt(a % 26) + s;
a = Math.floor(a/26);
}
return s;
}
So you can do
$(document).ready(function(){
var select = $("#Number_of_position"), table = $("#Positions_names");
for (var i = 1; i <= 100; i++){
select.append('<option value="'+i+'">'+i+'</option>');
}
select.change(function () {
var rows = '';
for (var i = 0; i < $(this).val(); i++) {
rows += "<tr><td>" + hex(i) + "</td><td><input type='text'></td></tr>";
}
table.html(rows);
});
});
Heres the example http://jsfiddle.net/v2ksyy7L/6/
And if you want it to be uppercase just do
hex(i).toUpperCase();
Also - this will work up to any number of rows that javascript can handle
if i have understood you correctly, that's maybe what you want:
http://jsfiddle.net/v2ksyy7L/3/
I have added an array for the alphabet:
var alphabet = "abcdefghijklmnopqrstuvwxyz".split("");
and then added the output to your "render" loop:
rows += "<tr><td>" + alphabet[i] + " <input type='text'></td></tr>";

Populating multidimensional array

The code below came as an included file with a beginner puzzle app tutorial I'm working through. The code works, however now that I've completed the tutorial, I'm trying to read through the files that came preloaded which were not explained.
I'm really tripped up over the "spacecount" variable, and what exactly it's doing. Can anyone comment each line in plain english, so that I can better understand how exactly the code below is populating the rowCount array. Thank you so much.
var totalRows = puzzle.length;
var totalCols = puzzle[0].length;
/* Loop through the rows to create the rowCount array
containing the totals for each row in the puzzle */
var rowCount = [];
for (var i = 0; i < totalRows; i++) {
rowCount[i]="";
spaceCount = 0;
for (var j = 0; j < totalCols; j++) {
if (puzzle[i][j] == "#") {
spaceCount++;
if (j == totalCols-1) rowCount[i] += spaceCount + " ";
} else {
if (spaceCount > 0) {
rowCount[i] += spaceCount + " ";
spaceCount = 0;
}
}
}
Here's a slightly more legible version:
var totalRows = puzzle.length;
var totalCols = puzzle[0].length;
/* Loop through the rows to create the rowCount array
containing the totals for each row in the puzzle */
var rowCount = [];
for (var i = 0; i < totalRows; i++) {
rowCount[i] = "";
spaceCount = 0;
for (var j = 0; j < totalCols; j++) {
if (puzzle[i][j] == "#") {
spaceCount++;
if (j == totalCols - 1) {
rowCount[i] += spaceCount + " ";
}
} else if (spaceCount > 0) {
rowCount[i] += spaceCount + " ";
spaceCount = 0;
}
}
}​
The confusing parts are probably the if blocks in the middle.
if (puzzle[i][j] == "#") { // If a puzzle piece is `#` (a space?)
spaceCount++; // Increment the spaceCount by 1.
if (j == totalCols - 1) { // Only if we are on the last column, add the text
// to the row.
rowCount[i] += spaceCount + " ";
}
} else if (spaceCount > 0) { // If the current piece isn't a `#` but
// spaces have already been counted,
// add them to the row's text and reset `spaceCount`
rowCount[i] += spaceCount + " ";
spaceCount = 0;
}​
From what I can tell, this code counts the number of consecutive pound signs and appends this text to each row.

Changing radio buttons name using Javascript

I'm using a simple JS duplicate function to duplicate a div. Inside is form information with radio buttons, including one group called 'getOrRequest'. Each div represents a book and needs to have its own 'getOrRequest' value.
The name needs to be changed in order to make each duplicated group of radio buttons selectable without affecting every other radio button. What is the best way to change these values?
Here is how I'm duplicating the div, in case that is the issue.
var bookInfo = document.getElementById('bookInformation');
var copyDiv = document.getElementById('addListing').cloneNode(true);
bookInfo.appendChild(copyDiv);
I then have tried a couple methods of changing the name value. Like this:
bookInfo.copyDiv.getOrRequest_0.setAttribute("name", "'getOrRequest' + idNumber + '[]'");
bookInfo.copyDiv.getOrRequest_1.setAttribute("name", "'getOrRequest' + idNumber + '[]'");
As well as this:
bookInfo.copyDiv.getOrRequest_0.name = 'getOrRequest' + idNumber + '[]';
bookInfo.copyDiv.getOrRequest_1.name = 'getOrRequest' + idNumber + '[]';
getOrRequest_0 and getOrRequest_1 are the ID's of the input values, but I've tried it a few ways now and nothing seems to work. Thanks in advance!
EDIT: MORE INFO
Here is the specific code I'm using:
function addAnotherPost(){
var bookInfo = document.getElementById('bookInformation');
var copyDiv = document.getElementById('addListing').cloneNode(true);
var size = copyDiv.childNodes.length;
copyDiv.id = 'addListing' + idNumber;
for(var j = 0; j < size; j++){
if(copyDiv.childNodes[j].name === "getOrRequest[]"){
copyDiv.childNodes[j].name = "getOrRequest" + idNumber + "[]";
}
}
bookInfo.appendChild(copyDiv);
idNumber++;
}
And it just doesn't seem to work.. The divs are duplicating, but the name value is not changing.
You can try this - http://jsfiddle.net/ZKHF3/
<div id="bookInformation">
<div id="addListing">
<input type="radio" name="addListing0[]" />
<input type="radio" name="addListing0[]" />
</div>
</div>
<button id="button">Add Listing</button>
<script>
document.getElementById("button").addEventListener("click", AddListing, false);
var i = 1;
var bookInfo = document.getElementById('bookInformation');
function AddListing() {
var copyDiv = document.getElementById('addListing').cloneNode(true);
var size = copyDiv.childNodes.length;
copyDiv.id = "listing" + i;
for ( var j = 0; j < size; j++ ) {
if ( copyDiv.childNodes[j].nodeName.toLowerCase() == 'input' ) {
copyDiv.childNodes[j].name = "addListing" + i + "[]";
}
}
bookInfo.appendChild(copyDiv);
i++;
}
</script>
The trouble is you are looking for child nodes of the div, but the check boxes are not child nodes, they are descendant nodes. The nodes you are looking for are nested within a label. Update your code to look for all descendant inputs using copyDiv.getElementsByTagName("input"):
var idNumber = 0;
function addAnotherPost() {
var bookInfo = document.getElementById('bookInformation');
var copyDiv = document.getElementById('addListing').cloneNode(true);
copyDiv.id = 'addListing' + idNumber;
var inputs = copyDiv.getElementsByTagName("input");
for(var j = 0; j < inputs.length; j++){
if(inputs[j].name === "getOrRequest[]"){
inputs[j].name = "getOrRequest" + idNumber + "[]";
}
}
bookInfo.appendChild(copyDiv);
idNumber++;
}
http://jsfiddle.net/gilly3/U5nsa/

Categories

Resources