I have a button that adds new rows, but I would like it to stop after adding three new rows.
<td>
<input type="button" class="add-move-button" id="add-move-button" value="Add Move" onclick="addRow()">
</td>
How would I go about approaching this? My thinking is I have to somehow count how many times the button was clicked and then send an alert saying "You can't click me anymore". Something like that I hope?
<td>
<input type="button" class="add-move-button" id="add-move-button" value="Add Move" onclick="addRow()">
</td>
<script>
var btnCount = 0;
function addRow() {
btnCount++;
if(btnCount > 3) {
alert("You can't click me anymore");
return;
}
}
</script>
In javascript, you have to initialize a global variable for example
var count = 0;
And when you click the button call to a Javascript method for example
function checkRowCount(){
if(count > 2){
alert("Count is exceeded");
}else{
++count;
}
}
Note : when you going to remove a row make sure you are decreasing the count value by 1 ( --count; )
You can use localstorage to check how many rows are added and then act accordingly.
localStorage.setItem('rows-added', 0);
const addRow = () => {
let current_rows_added = localStorage.getItem('rows-added');
if (localStorage.getItem('rows-added') == 3){
alert("you have already added 3 rows")
}else{
// your code that adds the row
localStorage.setItem('rows-added', current_rows_added + 1);
}
}
Related
In my HTML form, it's possible to add additional inputs dynamically by clicking a button. I've got this part to work, however I need each input to have a unique name.
This is my code so far,
<div class="control-group field_wrapper">
<label class="control-label"><strong> Phone Number 1</strong></label>
<input type="text" class="input-medium" name="phone_number[]">
<button class="btn btn-success add-number" type="button" title="Add">Add</button>
</div>
<div class="additionalNumber"></div>
My JS as below,
$(document).ready(function(){
var maxField = 10;
var addButton = $('.add-number');
var wrapper = $('.additionalNumber');
function fieldHTML(inputNumber) {
return `<div class="control-group field_wrapper">\
<label class="control-label"><strong> Phone Number ${inputNumber}</strong></label>\
<input type="text" class="input-medium" name="phone_number[${inputNumber}]">\
<button class="btn btn-danger remove" type="button">Remove</button>\
</div>`;
}
var x = 1;
$(addButton).on('click', function(e) {
if (x < maxField) {
x++;
$(wrapper).append(fieldHTML(x));
}
if (x >= maxField) {
alert('Limited to 10.');
}
});
$(wrapper).on('click', '.remove', function(e) {
e.preventDefault();
$(this).parents('.control-group').remove();
x--;
});
});
Using this code, I can get unique name for each input which are created by dynamically. But my problem is name[x] index not works properly when it is removing. That mean, just think I have added 3 input and delete second one and again I am adding new one, then it has same name twice. In this case, it is phone_number[3] for second input and phone_number[3] for thirt one also.
This is the fiddle from above code. Any help is appreciated.
You don't need to index the inputs for PHP either - 3x inputs named phone_number[] will automatically be indexed 0 - 2 on the back end:
<input type="text" name="phone_number[]">
<input type="text" name="phone_number[]">
<input type="text" name="phone_number[]">
[phone_number] => Array
(
[0] => a
[1] => b
[2] => c
)
That doesn't help with your plain text Phone Number n label though. And maybe you have your own reasons to want an input name index.
If you think about it, if you're going to allow deletions of any item in the list, and you need the results to be sequential, the only option is to renumber everything each time you make a change. You don't need to include any numbering when you add a new element, just regenerate all numbering.
Here's a working snippet doing that. My changes:
No need to pass the count x to fieldHTML(), we're going to renumber everything after you add the element;
Add a <span class='count'></span> in your label, which we can target and update;
Add a reNumber() function which will iterate over all inputs on the page and number them sequentially;
Call that function after any change;
Notes:
The 2 separate tests if (x < maxField) and if (x >= maxField) can be combined into a single if/else;
If you want to get rid of the duplication of your HTML block, you could give the first one an id like template, and then instead of duplicating that HTML in your JS, just copy the template, eg :
let $copy = $('#template').clone();
wrapper.append($copy);
wrapper and addButton are already jQuery objects, no need to wrap them with $() a second time to use them;
If you do want to number your input names, for consistency the first should probably be phone_number[1];
$(document).ready(function() {
var x = 1;
var maxField = 10;
var addButton = $('.add-number');
var wrapper = $('.additionalNumber');
function fieldHTML() {
return `<div class="control-group field_wrapper">\
<label class="control-label"><strong> Phone Number <span class='count'></span></strong></label>\
<input type="text" class="input-medium" name="phone_number[]">\
<button class="btn btn-danger remove" type="button">Remove</button>\
</div>`;
}
/**
* Iterate over all inputs and renumber sequentially
*/
function reNumber() {
let count;
wrapper.find('.field_wrapper').each(function (i) {
// .each() index is 0-based, and input #1 is already on the page,
// so extras start at #2
count = i + 2;
$('.count', $(this)).html(count);
// If you want to index your input names, but you can safely leave
// this out, PHP will index them anyway
$('input', $(this)).attr('name', 'phone_number[' + count + ']')
});
}
addButton.on('click', function(e) {
if (x < maxField) {
x++;
wrapper.append(fieldHTML());
reNumber();
} else {
alert('Limited to 10.');
}
});
wrapper.on('click', '.remove', function(e) {
e.preventDefault();
$(this).parents('.control-group').remove();
x--;
reNumber();
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="control-group field_wrapper">
<label class="control-label"><strong> Phone Number 1</strong></label>
<input type="text" class="input-medium" name="phone_number[]">
<button class="btn btn-success add-number" type="button" title="Add">Add</button>
</div>
<div class="additionalNumber"></div>
I'm very new to Javascript and want to build a vending machine for my first Project. I have the problem that I want to make it so that if the right amount is paid, there is an alert saying 'You have paid for your item', but currently it's not working when the display reaches 0. I think it's because the variable amount isn't changed and instead it just displays a different number. How do I get it to actually alert when I have inserted the right amount of 1 cent coins. I tried to google my problem but I don't even know how exactly to describe it.
var item1 = 100;
var ct1 = 1;
function showPrice1()
{
document.getElementById("display").innerHTML = item1;
}
function insert1cent()
{
document.getElementById("display").innerHTML = item1 -= ct1;
}
if (item1 == 0)
{
alert('You have paid for your item');
}
and this is the HTML:
<body>
<div id="display">
</div>
<button id="button1" type="button" onclick="showPrice1()">
1
</button>
<button id="ct1" type="button" onclick="insert1cent()">
1ct
</button>
</body>
Thank you in Advance for your help.
The if statement should be inside your function to check on every click and it should return false to avoid decrementing once your counter reaches 0. As demonstrated in the fiddle.
var item1 = 10;
var ct1 = 1;
function showPrice1() {
document.getElementById("display").innerHTML = item1;
}
function insert1cent() {
if (item1 == 0) {
alert('You have paid for your item');
return false;
}
item1 -= ct1;
document.getElementById("display").innerHTML = item1;
}
<div id="display">
</div>
<button id="button1" type="button" onclick="showPrice1()">
1
</button>
<button id="ct1" type="button" onclick="insert1cent()">
1ct
</button>
EDIT: I have updated the code with the answers.
I have a increment function that is working fine. However:
1. I would like to set some limits based on the total number available in one of the span. For example, 10. So the incrementing can't be more than 10. #DONE
Another issue is that I am planning to have multiple rows and before I save I want to make sure if we count the increments in every row it should not be more than 10 as well. If it decrease the total number (span) dynamically would be nice.
I'm adding rows dynamically with the ADD button, how can I add news rows that actually work with the current functions? Mine rows just clone the first one and the increment function is disabled.
document.addEventListener('DOMContentLoaded', async function() {
document.querySelector('#addlocationdest').addEventListener('click', add);
});
function add() {
var x = 1;
var container = document.getElementById('destination');
var detail = document.getElementById('row');
var clone = detail.cloneNode(true);
clone.id = "destination" + x;
x++;
container.appendChild(clone);
}
window.addEventListener("load", () => {
let elTotalQuantity = document.querySelector("#totalqty");
let totalQuantity = parseInt(elTotalQuantity.innerHTML);
function getSumOfRows() {
let sum = 0;
for (let input of document.querySelectorAll("form .row > input.quantity"))
sum += parseInt(input.value);
return sum;
}
for (let row of document.querySelectorAll("form .row")) {
let input = row.querySelector("input");
row.querySelector(".increment").addEventListener("click", () => {
if (getSumOfRows() >= totalQuantity) return;
input.value++;
elTotalQuantity.innerHTML = totalQuantity - getSumOfRows();
});
row.querySelector(".decrement").addEventListener("click", () => {
if (input.value <= 0) return;
input.value--;
elTotalQuantity.innerHTML = totalQuantity - getSumOfRows();
});
}
});
<div id="location" class="hide">
<div class="title">Transfer details</div><br>
<div class="line padded-s">Total Quantity: <span>10</span></div>
<br>
<form>
<label>New Total Quantity at this location: <span id="totalqty">10</span></label>
<br>
<div id="destination">
<div id="row" class="row">
<button type="button" class="decrement">-</button>
<input type="text" class="quantity" value="0" readonly/>
<button type="button" class="increment">+</button>
<a>Location: </a>
<input type="text" class="location" value="0" readonly/>
</div>
</div>
</form>
<label>Total being transfer: <p id="total-sum"></p></label>
<br>
<button type="button" id="addlocationdest">ADD</button>
<button type="button" id="removelocationdest">REMOVE</button>
</div>
Prologue
As long as the total quantity is fixed at the beginning of the script-execution, this works. Otherwise, it would be best to save the actual allowed total quantity as an attribute, and observe it using a MutationObserver. That way you can update your max. value in your code dynamically, when the total quantity-attribute changes. You can define custom attributes by naming them "data-*" where "*" is a custom name.
Solution for your problem
You are using the same ID on multiple elements. What you meant were classes, so change id="increment" to class="increment", and the same for decrement.
Since we don't want to input something with the buttons, but add listener to them, I'd say it is better to actually use <button>. In forms, buttons act as type="submit", which we don't want, so we need to change it to type="button".
Since the rows and the total quantity actually belong together, it is wiser to place them together into one <form>-element. However, you can still group the buttons and inputs as a row together using <div>.
Now regarding the in-/decrementing of the row's values and the total quantity:
Save the allowed total quantity in a variable
Add event-listener to the corresponding buttons
If action is valid, change row's value
Update total quantity number to totalQuantity - getSumOfRows()
To add new rows dynamically, we create and setup such an element, and append it to the form. See the appendNewRow()-function below.
Sidenote
I have added the readonly attribute to the input-fields so that you cannot enter numbers via keyboard.
window.addEventListener("load", () => {
let elTotalQuantity = document.querySelector("#totalqty");
let totalQuantity = parseInt(elTotalQuantity.innerHTML);
function getSumOfRows() {
let sum = 0;
for (let input of document.querySelectorAll("form .row > input.quantity"))
sum += parseInt(input.value);
return sum;
}
function updateTotalQuantity() {
elTotalQuantity.innerHTML = totalQuantity - getSumOfRows();
}
function appendNewRow() {
let row = document.createElement("div");
row.classList.add("row");
let child;
// input.quantity
let input = document.createElement("input");
input.classList.add("quantity");
input.value = "0";
input.setAttribute("readonly", "");
input.setAttribute("type", "text");
row.append(input);
// button.increment
child = document.createElement("button");
child.classList.add("increment");
child.innerHTML = "+";
child.setAttribute("type", "button");
child.addEventListener("click", () => {
if (getSumOfRows() >= totalQuantity) return;
input.value++;
updateTotalQuantity();
});
row.append(child);
// button.increment
child = document.createElement("button");
child.classList.add("decrement");
child.innerHTML = "-";
child.setAttribute("type", "button");
child.addEventListener("click", () => {
if (input.value <= 0) return;
input.value--;
updateTotalQuantity();
});
row.append(child);
// button.remove-row
child = document.createElement("button");
child.classList.add("remove-row");
child.innerHTML = "Remove";
child.setAttribute("type", "button");
child.addEventListener("click", () => {
row.remove();
updateTotalQuantity();
});
row.append(child);
document.querySelector("form .rows").append(row);
}
document.querySelector("form .add-row").addEventListener("click", () => appendNewRow());
appendNewRow();
});
<form>
<label>Total Quantity: <span id="totalqty">10</span></label>
<br>
<div class="rows">
</div>
<button type="button" class="add-row">Add new row</button>
</form>
QuerySelector only selects the first occurrence so you haven't really added a listener to the second "row". You should use querySelectorAll but, instead of unique ids, use classes.
<input class="increment" type="button" value="+" />
Now you can use document.querySelectorAll(".increment") to get all elements in an array.
You can traverse in the DOM by using parentElement. By knowing which button you clicked, you can traverse up to the form element and then select the first child - which is an input. A more dynamic way would be to use querySelector to select the input, in case the HTML change in the future. Anyway, that's how you can know which input to manipulate based on where the buttons are in the DOM.
I added two global variables, totalSum and maxSum. maxSum is fetched from your span element (which I assigned an unique id to). totalSum makes sure that all inputs combined doesn't exceed maxSum.
You had some duplicate code, so I refactored it into a new method: changeValue.
In all, I think the code speaks for itself.
Oh, this code doesn't take into account that the user can change the value inside the input. I will leave that for you to figure out with an "oninput" listener on each text input.
var totalSum = 0; // 3
var maxSum = 0
var totalSumElement = null;
document.addEventListener('DOMContentLoaded', async function() {
totalSumElement = document.getElementById('total-sum');
maxSum = document.getElementById('max-sum').innerText;
var incrementElements = document.querySelectorAll('.increment'); // 1
var decrementElements = document.querySelectorAll('.decrement');
addListener('click', incrementElements, incrementValue);
addListener('click', decrementElements, decrementValue);
});
function addListener(type, elementArr, func) {
for (element of elementArr) {
element.addEventListener(type, func);
}
}
function withinRange(newValue) {
var maxReached = newValue > maxSum; // 3
var zeroReached = newValue < 0;
return !maxReached && !zeroReached;
}
function changeValue(event, change) { // 4
if (withinRange(totalSum + change)) {
let parent = event.currentTarget.parentElement; // 2
let input = parent.children[0];
let value = parseInt(input.value) || 0;
if (withinRange(value + change)) {
input.value = value + change;
totalSum = totalSum + change;
}
}
totalSumElement.textContent = `Total: ${totalSum}`;
}
function incrementValue(event) {
changeValue(event, 1);
}
function decrementValue(event) {
changeValue(event, -1);
}
#totalqty {
padding-bottom: 1rem;
}
<div id="totalqty" class="line padded-s">Total Quantity: <span id="max-sum">10</span></div>
<form>
<input type="text" value="0" />
<input class="increment" type="button" value="+" />
<input class="decrement" type="button" value="-" />
</form>
<form>
<input type="text" value="0" />
<input class="increment" type="button" value="+" />
<input class="decrement" type="button" value="-" />
</form>
<p id="total-sum"></p>
I want to assign the value of input id qty1 to input id qty1send and then send it via POST method when the button Add to cart is pressed. How do I do it? Help!!
<button class="qtyBtn" onclick="increase_by_one('qty1');">+</button>
<input id="qty1" type="text" value="1" name="J1" />
<button class="qtyBtn" onclick="decrease_by_one('qty1');" />-</button>
<form action="somehwere.php" method="POST">
<input id="qty1send" type="hidden" name="qty1" value="" >
<button type="submit"> Add to cart </button>
</form>
my JS code
// Quantity spin buttons
function increase_by_one(field) {
nr = parseInt(document.getElementById(field).value);
document.getElementById(field).value = nr + 1;
}
function decrease_by_one(field) {
nr = parseInt(document.getElementById(field).value);
if (nr > 0) {
if ((nr - 1) > 0) {
document.getElementById(field).value = nr - 1;
}
}
}
You need to create a function and then assign value of qty1 to qty1send using onclick function for submit button. The following code need to be incorporated into your code. Hope it helps :)
HTML Code:
<button type="submit" onclick="myFunction()"> Add to cart </button>
JS Code:
function myFunction() {
document.getElementById("qty1send").value = document.getElementById("qty1").value;
}
The other option is to use the following statement in both of your increase and decrease functions as mentioned by #Rob Moll
document.getElementById("qty1send").value = document.getElementById("qty1").value;
You could add this to each function:
document.getElementById("qty1send").value = document.getElementById(field).value;
So your js would look like:
// Quantity spin buttons
function increase_by_one(field) {
nr = parseInt(document.getElementById(field).value);
document.getElementById(field).value = nr + 1;
document.getElementById("qty1send").value = document.getElementById(field).value;
}
function decrease_by_one(field) {
nr = parseInt(document.getElementById(field).value);
if (nr > 0) {
if ((nr - 1) > 0) {
document.getElementById(field).value = nr - 1;
document.getElementById("qty1send").value = document.getElementById(field).value;
}
}
}
Honestly though, that would just add more bad code to this unusual approach. No disrespect intended, but you should look at some examples and maybe start over with this. Intended as constructive criticism.
So I have a small issue with getting some values on radiobuttons. I've made a foreach loop in where the html makes radiobuttons. These are Yes/No buttons and Each yes/no set needs a value.
Like question 1 will have value 1, 2 will have 2, 3 will have 4, 4 will have 8 etc.
In the end it needs to add up to a total score, BUT if NO is selected (eg. question 4 with value of 8 is NO, then the value becomes 0)
Ive tried doing a Javascript function shown below that makes it sort of work. But if all answers are NO and you make question 4 YES(which should have a value of 8) then it just says that my value is 2. I knew that this wouldnt work but I'm wondering if I can change this in a way that I can make it work the way that I want to
#foreach (var item in Model)
{
<div class="box">
<p>#Html.DisplayFor(modelItem => item.Question)</p>
<label>
<input id="yes" type="radio" name="#item.Id" checked="">
<span class=" yes randobtn">Ja</span>
</label>
<label>
<input id="no" type="radio" name="#item.Id">
<span class="no randobtn">Nee</span>
</label>
</div>
}
<button class="btn btn-primary" onclick="GetCount()">check</button>
#section Scripts{
<script type="text/javascript">
$(document).on('click',
'#btn',
function() {
console.log('test');
location.href = "/Symptom/GetProblems?TotalPoints=" +
count;
});
var count = 1;
$(document).on('click',
'.randobtn',
function() {
GetCount();
});
function GetCount() {
var checkedRadioBtns = $('input[type="radio"]:checked');
count = 1;
for (var i = 0; i < checkedRadioBtns.length; i++) {
if (checkedRadioBtns[i].id === 'no') {
console.log('in de if');
continue;
} else {
count = count * 2;
}
}
alert(count);
}
</script>
}
This is what I want: http://prntscr.com/o6zrqd
But as you can see in the alert it just says 1 when NO is selected
put value of true and false in the array
and then
value="#item.true_value"