Combining Three Plus/Minus Buttons With Five Number Counters - javascript

As per title I have three plus/minus buttons, the three buttons have to be independent from each other i.e when one is clicked the output in the other two is not affected. All three need to show their total output in the two stand alone outputs.
I've researched this and tried some trial and error stuff with no luck as yet. I hope I've explained myself OK, Pen here https://codepen.io/anon/pen/RjeGQy and code below. I can use jquery if that helps.
<input type="text" value="0" class="count"><br><br>
<input type="text" value="0" class="count"><br><br>
<input type="button" value="-" onclick="minus()">
<input type="text" value="0" class="count">
<input type="button" value="+" onclick="plus()"><br><br>
<input type="button" value="-" onclick="minus()">
<input type="text" value="0" class="count">
<input type="button" value="+" onclick="plus()"><br><br>
<input type="button" value="-" onclick="minus()">
<input type="text" value="0" class="count">
<input type="button" value="+" onclick="plus()">
var count = 1;
var countEl = document.querySelectorAll(".count");
function plus(){
count++;
countEl.value = count;
}
function minus(){
if (count > 1) {
count--;
countEl.value = count;
}
Update
Thanks for your answers so far. To clarify what I'm trying to achieve as it's quite complex to explain:
The three button/counters could at anytime have three different outputs, say 1 2 3 totalling 6, that 6 needs to be shown in the two standalone counters with this number being added to or taken away from every time the button/counters are used.
Update1
New code and Pen, please see my comment below
<input type="number" name="quantity1" value="0">
<input type="number" name="quantity1" value="0"><br><br><br>
<input type="button" class="" data-quantity="minus" data-field="quantity1" value="-">
<input type="number" name="quantity1" value="0">
<input type="button" class="" data-quantity="plus" data-field="quantity1" value="+">
<input type="button" class="" data-quantity="minus" data-field="quantity2" value="-">
<input type="number" name="quantity2" value="0">
<input type="button" class="" data-quantity="plus" data-field="quantity2" value="+">
<input type="button" class="" data-quantity="minus" data-field="quantity3" value="-">
<input type="number" name="quantity3" value="0">
<input type="button" class="" data-quantity="plus" data-field="quantity3" value="+">
jQuery(document).ready(function() {
// This button will increment the value
$('[data-quantity="plus"]').click(function(e) {
// Stop acting like a button
e.preventDefault();
// Get the field name
fieldName = $(this).attr("data-field");
// Get its current value
var currentVal = parseInt($("input[name=" + fieldName + "]").val());
// If is not undefined
if (!isNaN(currentVal)) {
// Increment
$("input[name=" + fieldName + "]").val(currentVal + 1);
} else {
// Otherwise put a 0 there
$("input[name=" + fieldName + "]").val(0);
}
});
// This button will decrement the value till 0
$('[data-quantity="minus"]').click(function(e) {
// Stop acting like a button
e.preventDefault();
// Get the field name
fieldName = $(this).attr("data-field");
// Get its current value
var currentVal = parseInt($("input[name=" + fieldName + "]").val());
// If it isn't undefined or its greater than 0
if (!isNaN(currentVal) && currentVal > 0) {
// Decrement one
$("input[name=" + fieldName + "]").val(currentVal - 1);
} else {
// Otherwise put a 0 there
$("input[name=" + fieldName + "]").val(0);
}
});
});
https://codepen.io/anon/pen/NwOLNL

Instead of using querySelectorAll to find every element of the class count, I would give each input box an ID such as "input1", "input2", "input3".
Then I would change the plus and minus functions to accept a parameter to indicate which row it was from.
Finally, I would update the correct input with the new value.
It would look something like this:
<input type="button" value="-" onclick="minus(1)">
<input type="text" value="0" class="count" id="input1">
<input type="button" value="+" onclick="plus(1)"<br><br>
function minus(int row){
var inputElem = document.getElementById("input" + row.ToString());
inputElem.value--;
}

As you've tagged this jQuery, I'm using jQuery to facilitate some parts. And I'm not sure why you'd need to output the same data to multiple locations, but that should be pretty painless too.
EDIT NOTE: You indicate in your comment that you want the three fields to sum (add all three values) rather than concatenate (create a string of all three values). That's actually a very minor change, simply change the processing within the loop where we iterate over all the plusMinusWidgets. It's a matter of removing the comma line, and changing how we combine the fields into the resultEl field -- by default, they're treated as a string. I've edited the code to cast (force) them into a Number value, and add them to the current resultEl field (which I also cast into a Number value).
var resultEl = $(".resultSet");
$(".plusMinusThing").on("click", ".minusBtn", function(){
var currentWidget = $(this).parents(".plusMinusThing");
var countEl = currentWidget.find(".count");
countEl.val(Number(countEl.val())-1);
countEl.trigger("change");
}).on("click", ".plusBtn", function(){
var currentWidget = $(this).parents(".plusMinusThing");
var countEl = currentWidget.find(".count");
countEl.val(Number(countEl.val())+1);
countEl.trigger("change");
}).on("change keyup", ".count", function(){
resultEl.val("");
/******
* This is the only piece changed in order to sum the fields,
* rather than concatenate them. I've removed the comma,
* and I've cast the element values to numbers, then added.
******/
$(".plusMinusThing").each(function(index, element){
// Set the value of the resultEl to itself plus the next
// count el. Note it will work if the value is negative.
resultEl.val( Number(resultEl.val() ) + Number($(element).find(".count").val() ) );
})
})
fieldset {
border: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<fieldset class="results">
<input type="text" class="resultSet" />
</fieldset>
<hr/>
<fieldset class="plusMinusThing">
<input type="button" class="minusBtn" value="-">
<input type="text" value="0" class="count">
<input type="button" class="plusBtn" value="+">
<br>
</fieldset>
<fieldset class="plusMinusThing">
<input type="button" class="minusBtn" value="-">
<input type="text" value="0" class="count">
<input type="button" class="plusBtn" value="+">
<br>
</fieldset>
<fieldset class="plusMinusThing">
<input type="button" class="minusBtn" value="-">
<input type="text" value="0" class="count">
<input type="button" class="plusBtn" value="+">
<br>
</fieldset>
Much the same thing is an option without jQuery, although it is a bit more complicated. The following presents much the same functionality. Biggest difference is that I don't output to multiple target els. Otherwise, it handles much the same.
// Store references that all functions can use.
var resultEl = document.querySelector(".resultSet"),
plusMinusWidgets = document.querySelectorAll(".plusMinusThing");
// Attach the handlers to each plus-minus thing
for (var i = 0; i < plusMinusWidgets.length; i++) {
plusMinusWidgets[i].querySelector(".minusBtn").addEventListener("click", clickHandler);
plusMinusWidgets[i].querySelector(".plusBtn").addEventListener("click", clickHandler);
plusMinusWidgets[i].querySelector(".count").addEventListener("change", changeHandler);
}
/*****
* both plus and minus use the same function, but value is set by the class of the
* button
*****/
function clickHandler(event) {
// reference to the count input field
var countEl = event.target.parentNode.querySelector(".count");
if (event.target.className.match(/\bminusBtn\b/)) {
countEl.value = Number(countEl.value) - 1;
} else if (event.target.className.match(/\bplusBtn\b/)) {
countEl.value = Number(countEl.value) + 1;
}
// When we programmatically change the value, we need to manually trigger
// the change event.
triggerEvent(countEl, "change");
};
/*****
* changeHandler() processes whenever a plusMinusWidget's count el is changed.
* It iterates over all plusMinusWidgets, gets their count, and outputs that
* to the given resultEl input field.
*****/
function changeHandler(event) {
// remove all value from the result el.
resultEl.value = 0;
/******
* Here is the only functional change, per your comment. Rather
* concatenating a string, you want to sum values of the
* plusMinusWidget. To do this, we need to cast the value of each
* plusMinusWidget to a Number value, and add that to the Number
* value of the resultEl.
*****/
for (var i = 0; i < plusMinusWidgets.length; i++) {
// Add the current plusMinusWidget value to the resultEl value.
resultEl.value = Number(resultEl.value) + Number(plusMinusWidgets[i].querySelector('.count').value);
}
};
/*****
* triggerEvent() -- function to trigger an HTMLEvent on a given element.
* similar to jquery's trigger(), simply a convenience function. Not the
* point of this exercise.
*****/
function triggerEvent(el, type){
if ('createEvent' in document) {
// modern browsers, IE9+
var e = document.createEvent('HTMLEvents');
e.initEvent(type, false, true);
el.dispatchEvent(e);
} else {
// IE 8
var e = document.createEventObject();
e.eventType = type;
el.fireEvent('on'+e.eventType, e);
}
}
fieldset {
border: 0;
}
.plusMinusThing {
display: block;
width: 206px;
padding: 0;
border: 1px solid #ccc;
}
.plusMinusThing input {
float: left;
margin: 0;
border: 0;
}
<fieldset class="results">
<input type="text" class="resultSet" />
</fieldset>
<fieldset class="plusMinusThing">
<input type="button" class="minusBtn" value="-">
<input type="text" value="0" class="count">
<input type="button" class="plusBtn" value="+">
<br>
</fieldset>
<fieldset class="plusMinusThing">
<input type="button" class="minusBtn" value="-">
<input type="text" value="0" class="count">
<input type="button" class="plusBtn" value="+">
<br>
</fieldset>
<fieldset class="plusMinusThing">
<input type="button" class="minusBtn" value="-">
<input type="text" value="0" class="count">
<input type="button" class="plusBtn" value="+">
<br>
</fieldset>
The point of all this, either way, is that the complex element represented by plusMinusWidget (the fieldSet containing the plusBtn, the minusBtn and the count input) should be self-contained. I don't want to have to try to figure which button refers to what element -- the buttons are part of the complex elements, and they refer to their own count input. Try to use the DOM hierarchy to make your life easier, whenever possible.
**EXTRA CREDIT: Because I'm a fan of simplifying, I wanted to create this same effect with objects. The advantage to this approach is, I can create a PlusMinusWidget, and then create as many instances of it as I like. The page designer doesn't have to be aware of my programmatic elements, she simply has to create a container for them. The following code would handle everything else.
/******
* Constructor for my plusMinusWidget complex input element.
* At this point, it contains two functions:
* -- __init() initializes the DOM elements and the event listeners for
* the current PlusMinusWidget. The double-underscore is a
* lazy attempt at hiding the function.
* -- getHtml() returns the DOM content, so we can append that into
* the DOM itself.
*
* It is designed to be used within a containing element, as i use that
* to handle the recalculation event. I don't want the PlusMinusWidgets
* to have to be aware of much. Ideally, I would have created a container
* complex widget to handle the event listening for the recalculate
* event, but this was purely a prototype. More refinement is always
* an option.
******/
var PlusMinusWidget = function(id){
// when the new PlusMinusWidget gets created, we
// create the DOM node containing everything, and then
// we initialize the DOM content and the listeners.
this.DOMEl = $("<fieldset>").addClass("plusMinusWidget");
this.__init(id);
};
$.extend(PlusMinusWidget.prototype, {
// init() gets called above, when we create the DOM structure and
// set up the listeners.
__init: function(id){
// create a reference to the DOMEl. This isn't necessary for creating
// the structures, but within the listeners, we can't use 'this.DOMEl'
// as the value of 'this' has changed. Thus, we create a reference here.
var domEl = this.DOMEl;
// If we don't get an ID, we don't want to error out, so set it to "".
var id = id || "";
// The three DOM components that will be part of the PlusMinusWidget
var minusEl = $("<input>")
.addClass("minusBtn")
.attr("type", "button")
.val("-");
var valueEl = $("<input>")
.addClass("quantity")
.attr("type", "text")
.val("0");
var plusEl = $("<input>")
.addClass("plusBtn")
.attr("type", "button")
.val("+");
// set the ID of the PlusMinusWidget, and insert the DOM els.
domEl.attr("id", id).append(minusEl, valueEl, plusEl);
/*****
* Setting up the listeners. There are three events that
* are integral to this PlusMinusWidget, and one that is
* more external and could be handled elsewhere.
* .minusBtn.click
* .plusBtn.click
* .quantity.change / .quantity.keyup
*
* ... and the external listener is the parent node's
* 'plusMinus:recalculate', a custom event that we can
* monitor and handle.
*****/
domEl.on("click", ".minusBtn", function(){
valueEl.val(Number(valueEl.val() ) -1);
valueEl.trigger("change");
}).on("click", ".plusBtn", function(){
valueEl.val(Number(valueEl.val() ) + 1);
valueEl.trigger("change");
}).on("change keyup", ".quantity", function(){
domEl.parent().trigger("plusMinus:recalculate");
});
/*****
* the plusMinus:recalculate event is called on the DOMEl's parent
* node. This is the only el that should be aware of its child nodes,
* thus the only el that should have access to its descendant
* PlusMinusWidget nodes.
*****/
$(document).on("plusMinus:recalculate", domEl.parent(), function(){
resultEl.val(0);
$(".plusMinusWidget").each(function(){
resultEl.val(Number(resultEl.val()) + Number($(this).find(".quantity").val()) )
})
})
},
getHtml: function(){
return this.DOMEl;
}
})
/******************
* Everything above could be moved into
* a separate file, and saved as
* plusMinus.widget.js (for example).
* That piece can be hidden from the end
* user -- all they need to know is the
* code below: how to initialize the
* PlusMinusWidget object, and how to
* use its sole public function, getHtml.
*
******************/
// So here, we actually create an array of our PlusMinusWidget objects.
// As each is created, it's initialized and its DOM el is populated.
var plusMinusWidgets = [new PlusMinusWidget("firstQty"), new PlusMinusWidget("secondQty"), new PlusMinusWidget("thirdQty")];
// Create the reference to our results input and to the container itself.
var resultEl = $(".resultSet");
var plusMinusContainer = $(".container");
// iterate over the array we created just above, and for each member of the
// array, stick its DOM structure into the containing element. Note that this
// handles all the DOM, all the listeners, everything.
$.each(plusMinusWidgets, function(){
plusMinusContainer.append(this.getHtml());
})
fieldset {
border: 0;
}
.plusMinusThing {
display: block;
width: 206px;
padding: 0;
border: 1px solid #ccc;
}
.plusMinusThing input {
float: left;
margin: 0;
border: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<fieldset class="results">
<input type="text" class="resultSet" />
</fieldset>
<div class="container">
</div>
This was created with jQuery again, simply because it does simplify the creation of objects and listeners, but its not entirely necessary. Again, the beauty of this approach is that the DOM creation and event listener bits are completely hidden 'under the hood.' The end user really only needs to know how to initialize the PlusMinusWidget, and how to pop it into the DOM. Everything else happens seamlessly.
And again, this is just another approach. Not good, better or best, simply a thought experiment.

Related

Is there a way to show a calculated result (updating anytime there is a change) from a few input boxes without actually pressing a button?

I am currently writing a simple calculator as an exercise.
I have a few input fields where the user can put certain values, then clicking a button
a function is triggered where it does some calculations and shows the output in a table.
The input I am interested in is the following:
<p>Total eligible voters:
<input type="text" id="totalVoters" name="totalVoters" placeholder="0">
</p>
<p>Voter turnout:
<input type="text" id="voterTurnout" name="voterTurnout" placeholder="0">
</p>
<p>Percentage of ineligible bulletins:
<input type="text" id="ineligibleBulletins" name="ineligibleBulletins" placeholder="0">
</p>
<br><br>
Once that data is filled, the user has to fill however many votes they wish each party to receive.
I can't figure out (a simple) way to show however many votes are still unaccounted for.
For example, if the user puts totalVoters = 1000 , voterTurnout = 50% , ineligibleBulletins = 10%
the total unaccounted votes are (1-0.1)(0.51000) = 450.
And as the user starts filling the other field for voters per each party, say party1 = 50, I want to show (somewhere) however many (unaccounted) votes there are left, in this case 400.
I was considering some kind of a loop, but can't really figure out how to update the unaccountedVotes once a change occurs. Using JS.
I tried to stay as close to the OP original code as possible and created a hybrid solution with use of CSS custom properties and Javascript.
Created parent #input wrapper to hold three CSS custom properties with current entered 'Voter' values.
Attached a simple JS function to the inline oninput attribute of each input element. This JS function assigns the currently typed input value to a CSS custom property. Using onchange would work too, but requires the user to hit [Enter] first where oninput is immediate.
Create Javascript function showInput() which retrieves the current input values from the updated CSS custom properties. It calculates the current Unaccounted Voters value, rounds it to two decimals with function toDecimals() and assigns it to the #output element to show the intermediate result.
CSS #output::after shows a little trick how to assign the value of a CSS custom property to the CSS counter() to display it with content. Unfortunately counter() only returns integer values, otherwise use of Javascript function showOutput() could have been skipped.
#input {
--total /* current 'Total eligible voters' value */
--turnout /* current 'Voter turnout' percentage */
--ineligible /* current 'Ineligible bulletins' percentage */
}
#output {
--unaccounted /* calculated value current 'Unaccounted Voters' */
}
Snippet with comments in the code...
// Show updated output
function showOutput() {
// Get reference to the output info element
const output = document.getElementById('output');
const style = getComputedStyle(output); // Compute current style values
// Retrieve the current, inherited CSS variable values
let total = style.getPropertyValue('--total');
let turnout = style.getPropertyValue('--turnout');
let ineligible = style.getPropertyValue('--ineligible');
// Do the calculation and show the intermediate result, rounded to 2 decimals
output.innerHTML = 'Unaccounted Voters: ' + toDecimals((1 - ineligible / 100) * turnout / 100 * total).toFixed(2);
};
// Round a value to a given number of decimals
function toDecimals(value, decimals = 2) { // default is 2 decimals
return Number(Math.round(value+'e'+decimals)+'e-'+decimals);
};
showOutput(); // First run
#input {
/* Initialize CSS custum properties in parent wrapper */
--total : 0; /* these get modified by <input> oninput event */
--turnout : 0;
--ineligible: 0;
}
#output {
/* Calculate current unaccounted value on the fly */
--unaccounted: calc( (1 - var(--ineligible) / 100) * var(--turnout) / 100 * var(--total) );
}
/* Alternative without using JS, rounded to integer by counter mechanism */
/* #output innerHTML gets modified by JS, but attached ::after is done here... */
#output::after {
/* workaround to display content of a CSS custom property */
counter-reset: unaccounted var(--unaccounted); /* Assign the current value */
content: ' / counter(' counter(unaccounted) ')';
}
<div id="input"><!-- main wrapper with defined CSS custom properties -->
<p>Total eligible voters:
<input type="number" id="totalVoters" name="totalVoters" placeholder="0"
min="0" max="1500" step="1" value="0"
oninput="document.getElementById('input').style.setProperty('--total', this.value);
showOutput();">
</p>
<p>Voter turnout %:
<input type="number" id="voterTurnout" name="voterTurnout" placeholder="0"
min="0" max="100" step="0.01" value="0"
oninput="document.getElementById('input').style.setProperty('--turnout', this.value);
showOutput();">
</p>
<p>Ineligible bulletins %:
<input type="number" id="ineligibleBulletins" name="ineligibleBulletins" placeholder="0"
min="0" max="100" step="0.01" value="0"
oninput="document.getElementById('input').style.setProperty('--ineligible', this.value);
showOutput();">
</p>
<p id="output"></p>
</div>
One would choose kind of a component-based approach which
forces a cleaner / better structured markup,
calls for a scripting approach which in a lean way initializes a component and encapsulates the component related data/references ... and therefore ...
enables code-reuse.
After coming up with an improved markup where a component can be identified by its root-node, one would query any available root-node and start each component's initialization.
As for the OP's case one would implement a handler-function which is this-context aware and therefore receives all relevant component-data via a bound context. Here one would query and bind all relevant element-nodes for input and output which allows both, registering the handler-function which was created by bind and calling the component's initial and updating render-process.
In addition the chosen 'range'-type input-element gets enhanced by rendering its current range-value via an ::after CSS pseudo-element, its content based CSS generated content and a simple input-type event-handler which writes the element's value (the property) into the elements value-attribute.
In both cases, registering the value-update of an enhanced range-element and registering a component's update-handling, one would choose the 'input' event.
function updateRangePseudoContent({ currentTarget }) {
currentTarget
.setAttribute('value', currentTarget.value);
}
function updateUnaccountedVotesFromBoundContext() {
const { output, total, turnout, ineligible } = this;
output
.value = Math.round(
(1 - (ineligible.valueAsNumber / 100)) *
(turnout.valueAsNumber / 100) *
total.valueAsNumber
);
}
function initializeEachUnaccountedVotesCalculator() {
document
.querySelectorAll('[data-unaccounted-votes-calculator] [type="range"]')
.forEach(elmNode =>
elmNode.addEventListener('input', updateRangePseudoContent)
);
document
.querySelectorAll('[data-unaccounted-votes-calculator]')
.forEach(rootNode => {
const output = rootNode
.querySelector('output');
const total = rootNode
.querySelector('[data-name="total-voters"]');
const turnout = rootNode
.querySelector('[data-name="voter-turnout"]');
const ineligible = rootNode
.querySelector('[data-name="ineligible-bulletins"]');
rootNode
.addEventListener(
'input',
updateUnaccountedVotesFromBoundContext
.bind({ output, total, turnout, ineligible })
);
// initialization via all the current element's data.
updateUnaccountedVotesFromBoundContext
.call({ output, total, turnout, ineligible });
});
}
initializeEachUnaccountedVotesCalculator();
fieldset {
width: 70%;
padding-top: 0;
padding-bottom: 0;
}
fieldset, label {
margin: 5px 0;
}
label {
width: 90%;
}
label, label > span, label > input {
position: relative;
display: block;
}
label > span::after {
content: ':';
}
[type="range"] {
width: calc(100% - 10px - 4em);
}
[type="range"]::after {
position: absolute;
left: calc(100% + 10px);
content: attr(value)' %';
width: 4em;
height: 1em,
}
output {
font-weight: bolder;
}
<fieldset data-unaccounted-votes-calculator>
<label>
<span>Total eligible voters</span>
<input type="number" min="0" step="1" value="1000" data-name="total-voters">
</label>
<label>
<span>Voter turnout</span>
<input type="range" min="0" max="100" value="50" step="0.1" data-name="voter-turnout">
</label>
<label>
<span>Percentage of ineligible bulletins</span>
<input type="range" min="0" max="100" value="10" step="0.1" data-name="ineligible-bulletins">
</label>
<label>
<span>Unaccounted votes</span>
<output>0</output>
</label>
</fieldset>
<fieldset data-unaccounted-votes-calculator>
<label>
<span>Total eligible voters</span>
<input type="number" min="0" step="1" value="25000" data-name="total-voters">
</label>
<label>
<span>Voter turnous</span>
<input type="range" min="0" max="100" value="70" step="0.1" data-name="voter-turnout">
</label>
<label>
<span>Percentage of ineligible bulletins</span>
<input type="range" min="0" max="100" value="5" step="0.1" data-name="ineligible-bulletins">
</label>
<label>
<span>Unaccounted votes</span>
<output>0</output>
</label>
</fieldset>
I would try setting up an event listener for changes made to the inputs. Then have it update the output whenever a change is made. But I'm fairly new to programming and there could be a simpler way.

JS doesn't change the value of input

I'm writing cart-box that will change the quantity of products in cart. It works only if I have one box (one product) in cart, but when I have more products in cart it changes the value of the first input only.
This is my html code (earlier in the code I've got loop for my products):
<div class="amount">
<a>
<button type="button" class="minus">-</button>
</a>
<input class="amount-input" th:type="text" th:value="1" th:min="1"/>
<a>
<button type="button" class="plus">+</button>
</a>
</div>
And this is JS code:
$('.minus').click(function () {
var parent = $(this).parent().parent();
var input = parseInt(parent.find(".amount-input").val());
var count = input - 1;
//input['value'] = count;
//parent.closest("input").value = count;
document.querySelector("input").value = count;
});
$('.plus').click(function () {
var parent = $(this).parent().parent();
var input = parseInt(parent.find(".amount-input").val());
var count = input + 1;
//input['value'] = count;
//parent.closest("input").value = count;
document.querySelector("input").value = count;
});
I know that document.querySelector("input").value = count changes the first input only, because it's first on the list, but input['value'] = count doesn't change anything, parent.closest("input").value = count either.
Make sure you use valid HTML, otherwise results are not guaranteed.
Next let's remove duplication and just use the one event listener for both buttons, changing the value added based on the presence of the plus class.
Finally, if you're using jQuery, stick to using jQuery methodology. Also, you are doing nothing here with jQuery that couldn't be done with simple, native, javascript.
//Use one event listener for both
$('.amount button').click(function () {
//Find the nearest ancestor with class amoun
var parent = $(this).closest(".amount");
//Note you need to still use $ with jQuery Objecyd
var input = $(parent).find(".amount-input");
//Set the count based on the class of the button click
var count = parseInt($(input).val()) + ($(this).hasClass("plus") ? 1 : -1 );
//Set the value
$(input).val(count);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="amount">
<button type="button" class="minus">-</button>
<input class="amount-input" type="text" value="1" min="1"/>
<button type="button" class="plus">+</button>
</div>
<div class="amount">
<button type="button" class="minus">-</button>
<input class="amount-input" type="text" value="1" min="1"/>
<button type="button" class="plus">+</button>
</div>

How to manipulate value taken from form

I am taking value from the user inside the form and doing calculations inside new variable by using those values which user input inside the form but I cannot figure out why my code is not working.
function click() {
var l = document.getElementById('l');
var b = document.getElementById('b');
var a = document.getElementById('area');
var area = l.value * b.value;
a.innerHTML = "The ans is " + area;
}
<form>
<label>Length of the triangle: </label>
<br>
<input id="l" type="text" placeholder="Length">
<br>
<label>Base of the triangle</label>
<br>
<input id="b" type="text" placeholder="Base">
<br>
</form>
<p id=area></p>
<button type="button" onclick="click()">Click:</button>
I think i have done everything fine then why on chrome it doesnt show the correct ans.Please help on thsi one
The problem is that inline handlers have a very peculiar scope chain. They're surrounded inside two withs: one for the document, and one for the element on which the inline handler exists. For example, with
<button id="button" onclick="<<CODE HERE>>">
When clicked, the effect will be similar to as if the following was executed:
with (document) {
with (button) {
<<CODE HERE>>
}
}
When you reference click inside one of these handlers, it will first try to find a click property on the element, and it finds one: it refers to HTMLButtonElement.prototype.click:
<form>
<label>Length of the triangle: </label><br>
<input id="l" type="text" placeholder="Length"><br>
<label>Base of the triangle</label><br>
<input id="b" type="text" placeholder="Base"><br>
</form>
<p id=area></p>
<button
id="button"
onclick="console.log(click === button.click, click === HTMLButtonElement.prototype.click)"
>Click:</button>
As a result, clicking the button results in HTMLButton.prototype.click being called on that button, which, here, does nothing, which is why you're not seeing any results, and not even an error message.
Either use a different variable name:
function handleClick() {
var l = document.getElementById('l');
var b = document.getElementById('b');
var a = document.getElementById('area');
var area = l.value * b.value;
a.innerHTML = "The ans is " + area;
}
<form>
<label>Length of the triangle: </label><br>
<input id="l" type="text" placeholder="Length"><br>
<label>Base of the triangle</label><br>
<input id="b" type="text" placeholder="Base"><br>
</form>
<p id=area></p>
<button onclick="handleClick()"
>Click:</button>
Or, even better, avoid inline handlers entirely, since they behave so weirdly - attach the listener properly using Javascript instead. Using addEventListener also lets you avoid global variable pollution, which is inelegant and can lead to bugs and messy code.
document.querySelector('button').addEventListener('click', () => {
var l = document.getElementById('l');
var b = document.getElementById('b');
var a = document.getElementById('area');
var area = l.value * b.value;
a.textContent = "The ans is " + area;
});
<form>
<label>Length of the triangle: </label><br>
<input id="l" type="text" placeholder="Length"><br>
<label>Base of the triangle</label><br>
<input id="b" type="text" placeholder="Base"><br>
</form>
<p id=area></p>
<button>Click:</button>

Javascript getElementById based on ID formed using fixed name and input number

I am trying to create ID dynamically in the HTML object and use of getElementById() in my javascript to access the HTML input value based on the button I clicked and insert into their respective HTML Select list.
My HTML snippets:
<input type="text" id="addDesc1"><input type="button" value="Add" onclick="addDescText(1)">
<input type="text" id="addDesc2"><input type="button" value="Add" onclick="addDescText(2)">
....
....
<select id="desc1">....</select>
<select id="desc2">....</select>
My javascript snippets:
function addDescText(id) {
var descText = document.getElementById("addDesc".concat(id)).value;
var selList = document.getElementById("desc".concat(id));
....
....
some javascript to add the respective description to their respective select list
....
}
concat() is an array method, you can not use that on string. Simply use + to concatenate the parameter with the string.
Demo:
function addDescText(id) {
var descText = document.getElementById("addDesc"+id).value;
var selList = document.getElementById("desc"+id);
console.log(descText);
console.log(selList);
}
<input type="text" id="addDesc1"><input type="button" value="Add" onclick="addDescText(1)">
<input type="text" id="addDesc2"><input type="button" value="Add" onclick="addDescText(2)">
<select id="desc1">....</select>
<select id="desc2">....</select>
I would encourage you to make use of the event parameter that is passed to all event handlers (on-click-event in your case) and add that handler programmatically.
A possible solution would be
HTML
<input type="text" id="text1">
<input type="button" value="Add" class="add-desc-button" data-target="1">
JS
// get all buttons
let allButtons = document.querySelectorAll('.add-desc-button')
// add event handler
for (let i=0; i<allButtons.length; i++) {
allButtons[i].addEventHandler('click', addDescriptionHandler)
}
// event handler
function addDescriptionHandler(event) {
// retrieve the number you passed in before like this
let number = event.target.getAttribute('data-target')
// ... your code here
}

Increase/decrease textfield value with javascript

I'm having trouble in doing a javascript that will do the following:
Increase/decrease number inside textbox when image clicked.
setting a limit for that textbox (not below zero, not above x)
please know i have many text boxes in the same page, so how can this issue be fixed?
You don't need to (and shouldn't) set ids for each and every image and input field. You will need to set name attributes for each input field though (so your server code can tell them apart - but not for JS).
If the "add" section for each row looks like:
<div>
<img src='minus.png' onclick="increment(this.parentNode.getElementsByTagName('input')[0]);" />
<input type='text' name='product_1010101011' />
<img src='plus.png' onclick="decrement(this.parentNode.getElementsByTagName('input')[0]);" />
</div>
use this javascript:
function increment(myInput) {
// use Mike Samuel's code here
myInput.value = (+myInput.value + 1) || 0;
}
function decrement(myInput) {
// use Mike Samuel's code here
myInput.value = (myInput.value - 1) || 0;
}
I think this should get you going:
<form>
<input type="button" id="minus" value="-"
onClick="textb.value = (textb.value-1)">
<input type="text" id="textb" name="name" value="1" />
<input type="button" value="+"
onClick="textb.value = (+textb.value+1)">
</form>
Live example here
To increment
myInput.value = (+myInput.value + 1) || 0;
To decrement
myInput.value = (myInput.value - 1) || 0;
The || 0 will reset any value that doesn't parse as an integer to a default value, 0.

Categories