I have a set of number fields, each with a class "product-quantity", and a set of empty divs. the number fields are set with a data-attr small, medium, and goes up to 5xl. The empty div's are set with a data-attr small, medium, and goes up to 5xl as well because the small number field is associated with the small div and so one.
When you increase or decrease the number inside the small number field a div "small" should insert after the empty div with the attr small.
When you increase or decrease the number inside the medium number field a div "medium" should insert after the empty div with the attr medium.... and so on
additionally, all of the above belongs to a product x container, and there are multiple products on a page.
I have this jsfiddle that simulates what I am trying to do:
http://jsfiddle.net/7PhJZ/25/
however, right now when I add/subtract a number to the small number fields, it adds/subtracts a div to both the empty small/ medium div as well as in both products. and same for the medium.
I am having a hard time trying to associate which number field belongs to which empty div, which belongs to which product.
html:
<div id="product-1">
<div class="size-field">
<div id="size-label">
s
</div>
<div class="number-input">
<input id="Small" class="product-quantity" type="number" name="Small" min="0"
max="9999" data-product-id="1">
</input>
</div>
</div>
<div id="size-label">
m
</div>
<div class="number-input">
<input id="Medium" class="product-quantity" type="number" name="Medium"
min="0" max="9999" data-product-id="1">
</input>
</div>
<div class="name-number-header"><h5>HEADER<h5></div>
<div class="name-number-field-container" data-size="Small">small:
</div>
<div class="name-number-field-container" data-size="Medium">medium:
</div>
</div>
<br clear="all">
<div id="product-2">
<div class="size-field">
<div id="size-label">
s
</div>
<div class="number-input">
<input id="Small" class="product-quantity" type="number" name="Small" min="0"
max="9999" data-product-id="2">
</input>
</div>
</div>
<div id="size-label">
m
</div>
<div class="number-input">
<input id="Medium" class="product-quantity" type="number" name="Medium"
min="0" max="9999" data-product-id="2">
</input>
</div>
<div class="name-number-header"><h5>HEADER<h5></div>
<div class="name-number-field-container" data-size="Small">small:
</div>
<div class="name-number-field-container" data-size="Medium">medium:
</div>
</div>
js:
$('.product-quantity').on('change',function(){
$('.name-number-field').remove();
var val = $(this).val();
for (var i = 0; i < parseInt(val); i++){
$('<div/>',{'class':'name-number-field'}).insertAfter($("[data-size]"));
}
});
$('.product-quantity').on('change', function () {
var val = $(this).val(),
ele = $(this).closest('[id^="product"]').find('[data-size="'+this.name+'"]');
ele.nextUntil('[data-size]').remove();
for (var i = 0; i < parseInt(val); i++) {
$('<div/>', {
'class': 'name-number-field'
}).insertAfter(ele);
}
});
FIDDLE
EDIT:
Based on the comments, what you're really trying to do is just add one if the value increments, and remove the last if the value decrements, and for that the approach would be somewhat different:
$('.product-quantity').each(function() {
$(this).data('val', this.value);
}).on('change', function () {
var val = $(this).val(),
old = $(this).data('val'),
ele = $(this).closest('[id^="product"]').find('[data-size="'+this.name+'"]'),
inc = val >= old;
if (inc) {
$('<div/>', {
'class': 'name-number-field'
}).insertAfter(ele);
}else {
$('.name-number-field', ele.parent()).last().remove();
}
$(this).data('val', this.value);
});
FIDDLE
Make Use of your data-product-id and hook the textbox's parent and target the required elements.
Try this,
$('.product-quantity').on('change',function(){
$('.name-number-field').remove();
var val = $(this).val();
for (var i = 0; i < parseInt(val); i++){
$('<div/>',{'class':'name-number-field'})
.insertAfter($(this).parents('#product-' + $(this).data('product-id')).find("[data-size]"));
}
});
DEMO
Edit:
$('.product-quantity').on('change',function(){
$('.name-number-field').remove();
var val = $(this).val();
for (var i = 0; i < parseInt(val); i++){
$('<div/>',{'class':'name-number-field'})
.insertAfter($(this).parents('#product-' + $(this).data('product-id')).find("[data-size='"+ $(this).attr('name') +"'][data-size]"));
}
});
NEW - DEMO
Related
I have a problem with the script.
I am trying to count two input fields, and insert the result into the third field.
But it doesn't work, and unfortunately I can't figure out what's wrong.
function sum() {
var txtFirstNumberValue = document.querySelectorAll('#firstID > div > div > div > input').value;
var txtSecondNumberValue = document.querySelectorAll('#second > div > div > div > input').value;
if (txtFirstNumberValue == "")
txtFirstNumberValue = 0;
if (txtSecondNumberValue == "")
txtSecondNumberValue = 0;
var result = parseInt(txtFirstNumberValue) / parseInt(txtSecondNumberValue);
if (!isNaN(result)) {
document.querySelectorAll('#third > div > div > div > input').value = result;
}
}
<div id="firstID"><div>
<label>first</label>
<div>
<div>
<input name="drts[field_first][0]" type="number" value="" maxlength="255">
</div>
</div>
</div></div>
<div id="second"><div>
<label>second</label>
<div>
<div>
<input name="drts[field_second][0]" type="number" maxlength="255">
</div>
</div>
</div></div>
<div id="third"><div>
<label>third</label>
<div>
<div>
<input name="drts[field_third][0]" type="number" value="" maxlength="255">
<div></div>
</div>
</div>
</div></div>
There are a few problems here.
Are you actually calling sum? I've added a call in the example code so you can run it.
Your query selectors are not right. There isn't actually anything in the divs with the IDs you query. I've moved the input boxes into the correct places. When debugging, you should check that you are actually finding elements in your querySelectorAll call before proceeding.
querySelectorAll doesn't have a value property. You would need to iterate over each element before getting the items. Given you specifically want one item, it would be better to use something more specific like getElementById. I've kept the original querySelectorAll but changed the IDs on the divs to classes so we can have more than one result for this example. Then, I iterate over them pulling out the value to add to result. I've moved the parseInt to the running calculation otherwise it would perform a string concatenation.
Even better than the above would be to access the input directly. There's probably no point accessing a div and drilling down to the input. I've included this example to output the result.
I've removed redundant html. It's not related to the answer but try to keep your markup clean.
function sum() {
var inputElements = document.querySelectorAll('.user-input > div > div > input');
var result = 0;
inputElements.forEach(element => {
result += element.value ? parseInt(element.value) : 0
})
document.getElementById('third').value = result
}
document.getElementById('run-button').addEventListener('click', sum)
<div class="user-input">
<label>first</label>
<div>
<div>
<input name="drts[field_first][0]" type="number" maxlength="255">
</div>
</div>
<div>
<div class="user-input">
<label>second</label>
<div>
<div>
<input name="drts[field_second][0]" type="number" maxlength="255">
</div>
</div>
<div>
<label>third</label>
<div>
<div>
<input id="third" name="drts[field_third][0]" type="number" value="" maxlength="255">
<div></div>
</div>
</div>
<div>
<button type="button" id="run-button">Run</button>
Try like this
function sum() {
let txtFirstNumberValue = document.querySelector('#firstID input').value;
let txtSecondNumberValue = document.querySelector('#second input').value;
let result = parseInt(txtFirstNumberValue) / parseInt(txtSecondNumberValue);
if (!isNaN(result)) {
document.querySelector('#third input').value = result;
} else {
document.querySelector('#third input').value = '';
}
}
<div id="firstID"><div>
<label>first</label>
<div>
<div>
<input name="drts[field_first][0]" type="number" value="" maxlength="255">
</div>
</div>
</div></div>
<div id="second"><div>
<label>second</label>
<div>
<div>
<input name="drts[field_second][0]" type="number" maxlength="255">
</div>
</div>
</div></div>
<div id="third"><div>
<label>third</label>
<div>
<div>
<input name="drts[field_third][0]" type="number" value="" maxlength="255" disabled>
<div></div>
</div>
</div>
<div>
<button id="button" onclick="sum()">Calculate</button>
</div>
</div>
</div>
const input1 = document.querySelector('#input1');
const input2 = document.querySelector('#input2');
const input3 = document.querySelector('#input3');
const storeInputs = [input1, input2];
for(let i = 0; i < storeInputs.length; i++) {
storeInputs[i].addEventListener('input', function() {
// multiply input1 and input2 with 1 for converting there values from string to number
input3.value = input1.value * 1 + input2.value * 1;
});
};
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<label for="input1">First Input</label>
<input id="input1" type="number" value="0"></input>
<label for="input2">Second Input</label>
<input id="input2" type="number" value="0"></input>
<label for="input3">Third Input</label>
<input id="input3" type="number" value="0"></input>
</body>
</html>
Having an issue with peoplePaid() looping through all the inputs with the .persons class on a page through an add button. I believe this issue is that #paidTotal is trying to add contents from an array in .persons but can't access them (gives me an undefined error in console).
This variable works but only if there's one .persons class with a variable...
var personsCheck = parseFloat(document.getElementsByClassName('persons')[0].value);
However I need it to dynamically loop the values of the array that is created through .persons elements. What am I missing?
function peoplePaid() {
var checkTotal = parseFloat(document.getElementById('check').value);
var personsCheck = document.getElementsByClassName('persons');
var paidTotal = document.getElementById('paidTotal');
for (var i = 1; i < personsCheck.length; i += 1) {
paidTotal += personsCheck[i];
}
paidTotal.innerHTML = checkTotal - personsCheck;
}
$ <input type="text" id="check" value="" />
<h3>Number of People: <span id="numberOfPeople"></span></h3>
<div>
<div id="userNumbers">
<input type="text" class="persons" name="person">
</div>
</div>
<button onclick="peoplePaid()">Calculate</button>
<!--Paid Amount-->
<div>
<h3>Paid Amount: <span id="paidTotal"></span></h3>
</div>
paidTotal is an element. I believe you do not want to use += on the element itself. You should add the total to a variable.
Also, as the index of collections are 0 based, you have to start the value of i from 0. You have to take the value property from each element.
Please Note: It is good practice to use textContent instead of innerHTML when dealing with text only content.
Try the following way:
function peoplePaid() {
var checkTotal = parseFloat(document.getElementById('check').value);
var personsCheck = document.getElementsByClassName('persons');
var paidTotal = document.getElementById('paidTotal');
var pCheck = 0;
for (var i = 0; i < personsCheck.length; i += 1) {
pCheck += personsCheck[i].value;
}
paidTotal.textContent = checkTotal - pCheck;
}
$ <input type="text" id="check" value="" />
<h3>Number of People: <span id="numberOfPeople"></span></h3>
<div>
<div id="userNumbers">
<input type="text" class="persons" name="person">
</div>
</div>
<button onclick="peoplePaid()">Calculate</button>
<!--Paid Amount-->
<div>
<h3>Paid Amount: <span id="paidTotal"></span></h3>
</div>
Some mistakes exists in your code:
paidTotal is an element but in paidTotal += personsCheck[i]; you have used it some a numeric variable.
in your loop, index must starts from zero not one.
in this line: paidTotal += personsCheck[i]; you have added personsCheck[i] element to paidTotal instead of its value.
the corrected code is like this:
function peoplePaid() {
var checkTotal = parseFloat(document.getElementById('check').value);
var personsCheck = document.getElementsByClassName('persons');
var paidTotal = 0;
for (var i = 0; i < personsCheck.length; i += 1) {
paidTotal += personsCheck[i].value * 1;
}
document.getElementById('paidTotal').innerHTML = checkTotal - paidTotal;
}
$ <input type="text" id="check" value="" />
<h3>Number of People: <span id="numberOfPeople"></span></h3>
<div>
<div id="userNumbers">
<input type="text" class="persons" name="person">
</div>
</div>
<button onclick="peoplePaid()">Calculate</button>
<!--Paid Amount-->
<div>
<h3>Paid Amount: <span id="paidTotal"></span></h3>
</div>
I'm trying to calculate the %share which is simply an addition of share1+share2 == 100. However, I want it to work only on the two checked checkboxes.
How do I go about detecting the selected checkbox and apply the function accordingly?
var MAX = 2;
$('input.addnominee').click(function() {
($('input.addnominee:checked').length == MAX) ? $('input.addnominee').not(':checked').attr('disabled',true):$('input.addnominee').not(':checked').attr('disabled',false);
});
$("#share1").focusout(function() {
var share1 = $("#share1").val();
var answer = 100 - share1;
$("#share2").val(answer);
});
$("#share2").focusout(function() {
var share2 = $("#share2").val();
var answer = 100 - share2;
$("#share1").val(answer);
});
label {
display: block;
}
.block {
background-color: #eee;
padding: 15px;
margin-bottom: 5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.2/jquery.min.js"></script>
<h6>You can choose a maximum of 2 users</h6>
<div class="block">
<label class="checkbox"> Add User
<input class="addnominee" type="checkbox" data-toggle="collapse" data-target="#fnominee">
</label>
<div class="form-group">
<input type="number" pattern="[0-9]*" id="share1" class="form-control" placeholder="% share" required>
</div>
</div>
<div class="block">
<label class="checkbox"> Add User
<input class="addnominee" type="checkbox" data-toggle="collapse" data-target="#fnominee">
</label>
<div class="form-group">
<input type="number" pattern="[0-9]*" id="share2" class="form-control" placeholder="% share" required>
</div>
</div>
<div class="block">
<label class="checkbox"> Add User
<input class="addnominee" type="checkbox" data-toggle="collapse" data-target="#fnominee">
</label>
<div class="form-group">
<input type="number" pattern="[0-9]*" id="share3" class="form-control" placeholder="% share" required>
</div>
</div>
<div class="block">
<label class="checkbox"> Add User
<input class="addnominee" type="checkbox" data-toggle="collapse" data-target="#fnominee">
</label>
<div class="form-group">
<input type="number" pattern="[0-9]*" id="share4" class="form-control" placeholder="% share" required>
</div>
</div>
Do you have a specific reason to use focusout?
You could catch the ID's of the two "selected" elements inside your checkbox function. Or to be precise, get id of input that is in the next div inside the clicked checkbox's parent:
var active1, active2;
var MAX = 2;
$('input.addnominee').click(function() {
($('input.addnominee:checked').length == MAX) ? $('input.addnominee').not(':checked').attr('disabled',true):$('input.addnominee').not(':checked').attr('disabled',false);
let checked = $('input.addnominee:checked');
active1 = $(checked[0]).parent().next('div').children('input').attr('id');
//Let's assign active2 only if we have multiple selected checkboxes:
if(checked.length > 1) active2 = $(checked[1]).parent().next('div').children('input').attr('id');
});
Here's example with click. To simplify it a bit, I added stepper class into every number input, and we're now detecting click for the class stepper:
$(document).on('click','.stepper',function(){
if($(this).attr('id') == active1){ //Check which one user clicked
if(active2 != undefined){ //Make the math only if we have another active element
var share1 = $('#'+active1).val();
var answer = 100 - share1;
$('#'+active2).val(answer);
}
}else if($(this).attr('id') == active2){
if(active1 != undefined){
var share2 = $('#'+active2).val();
var answer = 100 - share2;
$('#'+active1).val(answer);
}
}
});
Fiddle: https://jsfiddle.net/xpvt214o/677733/
This surely works also with focusout, but you need to remember that clicking stepper wont focus the input, so it wouldn't be very functional.
And with this same idea you could also disable the inputs which are not 'active'.
I hope this helps!
EDIT:
Maybe a bit simplified version with the same idea:
jQuery(document).ready(function($) {
var MAX = 2;
$('input.addnominee').click(function() {
($('input.addnominee:checked').length == MAX) ? $('input.addnominee').not(':checked').attr('disabled',true):$('input.addnominee').not(':checked').attr('disabled',false);
});
$(document).on('click','.stepper',function(){
var checked = $('input.addnominee:checked');
if(checked.length > 1){
var active1 = $(checked[0]).parent().next('div').children('input');
var active2 = $(checked[1]).parent().next('div').children('input');
var share = $(this).val();
var answer = 100 - share;
if($(this).attr('id') == $(active1).attr('id')){
$(active2).val(answer);
}else if($(this).attr('id') == $(active2).attr('id')){
$(active1).val(answer);
}
}
});
});
Fiddle: https://jsfiddle.net/128uzmj3/
I have few inputs, and it comes with values from 1 to 100 in it, but user can alter those values. I have sorted my inputs in Ascending order. Now I want that each time user changes an input, they should be re-arranged in ascending order.
Here is my HTML template:
var sortedArray = $("div[class^='wrap_']").get().sort(function(a, b) {
var idx = parseInt($(a).find(".sort_by").val(),10);
var idx2 = parseInt($(b).find(".sort_by").val(),10);
return idx > idx2;
});
$(sortedArray).appendTo("body");
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div class="wrap_0">
<input class="sort_by" value="10"/>
</div>
<div class="wrap_1">
<input class="sort_by" value="3"/>
</div>
<div class="wrap_2">
<input class="sort_by" value="7"/>
</div>
Right now they appear as:
3
7
10
if user changes 3 to 12, I want my output to be automatically changed to:
7 10 12.
I want Jquery solutions only. Thanks in advance.
$(document).ready(function(){
sort();
$(".sort_by").change(function(){
sort();
});
function sort(){
var sortedArray = $("div[class^='wrap_']").get().sort(function(a, b) {
var idx = parseInt($(a).find(".sort_by").val(),10);
var idx2 = parseInt($(b).find(".sort_by").val(),10);
return idx > idx2;
});
console.log(sortedArray);
$(sortedArray).appendTo("body");
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div class="wrap_0">
<input class="sort_by" value="10"/>
</div>
<div class="wrap_1">
<input class="sort_by" value="3"/>
</div>
<div class="wrap_2">
<input class="sort_by" value="7"/>
</div>
There...you change a value and press enter...your sort code is executed.
You can use the input event and apply the sort method on the parent div jQuery collection. Please note that I added class wrap so the divs can be easily selected. The code .trigger('input') ensures that the input (actually parent div) elements are sorted when the page loads.
$(function() {
$('.sort_by').on('focusout', function() {
var arr = $('div.wrap');
arr = arr.sort(function(a,b) {
return +$(a).find('.sort_by').val() - +$(b).find('.sort_by').val();
});
$('body').append( arr );
})
.trigger('focusout');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="wrap_0 wrap">
<input class="sort_by" value="10"/>
</div>
<div class="wrap_1 wrap">
<input class="sort_by" value="3"/>
</div>
<div class="wrap_2 wrap">
<input class="sort_by" value="7"/>
</div>
I have a set of number fields with the class product-quantity. When I add a number to the input field a div class name-number-field should appear after the class name-number-header. When a number is taken away from the field, the last name-number-field should be removed.
when val= 8 and size= 0 8 div's should be added
when val= 8 and size= 3 5 div's should be added
this what I came up with, but I am stuck
$(document).ready(function() {
$('.product-quantity').on('change',function(){
selector = "#product-"+$(this).attr('data-product-id')+
"[data-size-field='"+$(this).attr('data-size') +"']";
if ($(this).val > $(selector).size) {
for (var i = 0; i < (val-size); i++){
$('.size-field').insertAfter($(".name-number-header"));
}
}
if ($(this).val < $(selector).size) {
for (var i = 0; i < (size-val); i++){
$('.size-field :last').remove();
}
}
});
});
http://s24.postimg.org/x4njd7r44/Screen_Shot_2013_12_12_at_6_03_47_PM.jpg
here is a link to a screen shot of the html inspection ^^^^^^^^^^^^^^^^^
html:
<div class="size-column">
<div class="size-field">
<div id="size-label"></div>
<div class="number-input">
<input id="XSmall" class="product-quantity" type="number" name="XSmall" min="0"
max="9999" data-size="XSmall" data-product-id="1"></input>
</div>
</div>
<div class="size-field">
<div id="size-label"></div>
<div class="number-input">
<input id="Small" class="product-quantity" type="number" name="Small" min="0"
max="9999" data-size="Small" data-product-id="1"></input>
</div>
</div>
<div class="size-field">
<div id="size-label"></div>
<div class="number-input">
<input id="Medium" class="product-quantity" type="number" name="Medium" min="0"
max="9999" data-size="Medium" data-product-id="1"></input>
</div>
</div>
....up to 5xl
<div class="name-number-form" data-switch="1" style="display: none;">
<div class="name-number-header"></div>
<div id="number-field-set">
<div class="name-number-field" data-size="XSmall">
</div>
<div class="name-number-field" data-size="Small">
</div>
<div class="name-number-field" data-size="Medium">
</div>
...up to 5xl
Edited code:
$(document).ready(function() {
$('.product-quantity').on('change',function(){
selector = "#product-"+$(this).attr('data-product-id')+
" [data-size-field='"+$(this).attr('data-size') +"']";
var val = $(this).val();
var size = $(selector).size();
if (val > size) {
for (var i = 0; i < (val-size); i++){
$('hi').insertAfter($(".name-number-header"));
}
}
if (val < size) {
for (var i = 0; i < (size-val); i++){
$('.name-number-field :last').remove();
}
}
});
});
I created a fiddle that simulates something like what I am trying to do. What I dont want is the second input to effect the adding and removing of the div in the first column.
http://jsfiddle.net/7PhJZ/19/
$('.size-field').insertAfter($(".name-number-header"));
searches for elements with the class size-field.
If i understood your question correctly you want to create new size-field divs and append them.
If so, try it like that:
$('<div/>',{'class':'size-field'}).insertAfter($(".name-number-header"));
This will create a new div with class size-field and adds it after .name-number-header.