i want to have multiple elements with same class that act independently, after 1 night of seeking if "forEach" has any 'forEach:active' i end up with code below, but i feel kind of little shame with 'nextSibling of parent of parent' but if is supported by atleast any modern browsers, then is better than nothing.
on codePen is working fine,as well as snippet here.
i wonder if i can find a better version in vanila js for it or if is there anything deprecated that i should change.
//get + button
const up = document.querySelectorAll('.up');
//tell to + to increase his previous frend value
[].forEach.call(up, function(element) {
element.addEventListener('click', function() {
this.previousElementSibling.value =
parseInt(this.previousElementSibling.value) + 1;
});
})
//get -
const down = document.querySelectorAll('.down');
//tell to - to decrease his next frend value && and hide
//dynamic
//input if == 0 && show firstAdd button
[].forEach.call(down, function(element) {
element.addEventListener('click', function() {
this.nextElementSibling.value =
parseInt(this.nextElementSibling.value) - 1;
if (this.nextElementSibling.value == 0) {
this.parentElement.parentElement.style.display = 'none';
this.parentElement.parentElement.nextElementSibling.style.display = 'initial';
}
});
})
//get firstAdd button
const fAdd = document.querySelectorAll('.firstAdd');
//tell to it to add dynamic input && to vanish itself after &&
//set input value = 1
[].forEach.call(fAdd, function(element) {
element.addEventListener('click', function() {
this.previousElementSibling.style.display = 'initial';
this.previousElementSibling.children[1].children[1].value = 1;
this.style.display = 'none'
});
})
.form-group {
width: 30%;
margin: 30px;
display: none;
}
.input-group {
flex-direction: row;
display: flex;
}
body {
background: #111;
}
<div class='one'>
<div class="form-group">
<label>value: </label>
<div class="input-group">
<button class="down">-</button>
<input type="text" class="myNumber" value='1'>
<button class="up">+</button>
</div>
</div>
<button class='firstAdd'>Add</button></div>
<br>
<div class='two'>
<div class="form-group">
<label>value: </label>
<div class="input-group">
<button class="down">-</button>
<input type="text" class="myNumber" value='1'>
<button class="up">+</button>
</div>
</div>
<button class='firstAdd'>Add</button></div>
Related
I have a input field that takes numeric inputs. Then i have a button which display the number of divs as per that input. after displaying div there is two radio-box buttons (paired end and single end) if I select paired end then i want two file upload fields in each divs. and if i select single end then i want only one file upload fields in each div.
I have tried but fileupload fields working on only first div.
function CreateText() {
var text = `<div class="row border-top py-3">
<div class="col-md-3">
<label">sample name *</label></br>
<input type="sample" id="sample" name="sample[]">
</div>
<div class="col-md-3" style="display:none" id="showsingle">
<div class="form-group">
<label for="form_upload">Upload file *</label></br>
<input type="file" id="myFile" name="filename1[]">
</div>
</div>
<div class="col-md-3" style="display:none" id="showpair">
<div class="form-group">
<label for="form_upload">Upload file *</label></br>
<input type="file" id="myFile" name="filename2[]">
<label for="form_upload">Upload file *</label></br>
<input type="file" id="myFile" name="filename2[]">
</div>
</div>
<div class="col-md-3 d-grid">
<div class="form-group">
<button class="btn btn-danger remove_add_btn">Remove</button>
</div>
</div>
</div>`;
var textCount = document.getElementById('textInput').value;
var html = '';
for (var i = 0; i < $('#textInput').val(); i++) {
html = document.getElementById('divDynamicTexts').innerHTML;
document.getElementById('divDynamicTexts').innerHTML = html + text.replace('', i);
}
}
function onlyOne() {
let SradioBox = document.getElementById("singleradio"),
Sfileupload = document.getElementById("showsingle"),
PradioBox = document.getElementById("pairedradio"),
Pfileupload = document.getElementById("showpair");
if (SradioBox.checked == true) {
Sfileupload.style.display = "block",
Pfileupload.style.display = "none";
} else if (PradioBox.checked == true) {
Pfileupload.style.display = "block",
Sfileupload.style.display = "none";
} else {
Pfileupload.style.display = "none",
Sfileupload.style.display = "none";
}
};
$(document).ready(function() {
$(document).on('click', '.remove_add_btn', function(e) {
e.preventDefault();
let row_item = $(this).parent().parent().parent();
$(row_item).remove();
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="text-center">
<input type="text" id="textInput" value="" />
<input type="button" id="" value="Create upload fields" onclick="CreateText();" />
<div class="col-md-4" id="filebutton">
<div class="form-group ">
<label for="form_need">Library Type *</label>
</br>
<div class="px-2">
<label for="myradio">Single end:</label>
<input type="radio" id="singleradio" name="check" onclick="onlyOne();">
<label for="myradio">Paired end:</label>
<input type="radio" id="pairedradio" name="check" onclick="onlyOne();">
</div>
</div>
</div>
</div>
<div id="divDynamicTexts"></div>
ID attributes must be unique. It would be better to remove the IDs altogether ( or change to dataset attributes perhaps ) and use a delegated event listener to process the various clicks related to the task of adding/removing dynamic elements.
In the code below all ID attributes were either removed entirely or changed to data-id type values.
To avoid the need to process different form file input fields at the server the file-input fields are named the same but have an index so can be identified more readily in PHP ( or whatever backend you have )
The delegated listener, because it is bound to the document, will work for all elements whether or not they are static or added dynamically and makes heavy use of the event.target property to help identify the element that invoked the event.
The label element was being used incorrectly previously. If the form-input is within the label then there is no need for the for="ID" syntax ( note that the ID should be the ID of the input element to which the label belongs! ) - as it was the label's appeared to have a for attribute which did not related to an element in the form!
Using querySelector and querySelectorAll you can easily identify nodes of interest within the DOM so button clicks or radio button selection can fire a query to find nodes that are relevant - thus simplifying the hiding/showing of the file input elements.
const strhtml = `
<div data-id="dynrow" class="row border-top py-3">
<div class="col-md-3">
<label>sample name *<input type="text" name="sample[]"></label>
</div>
<div class="col-md-3" style="display:none" data-id="single" data-role="file-field">
<div class="form-group">
<label>Upload file *<input type="file" name="filename[1]" /></label>
</div>
</div>
<div class="col-md-3" style="display:none" data-id="pair" data-role="file-field">
<div class="form-group ">
<label>Upload file *<input type="file" name="filename[1]" /></label>
<label>Upload file *<input type="file" name="filename[2]" /></label>
</div>
</div>
<div class="col-md-3 d-grid">
<div class="form-group">
<button class="btn btn-danger remove_add_btn" data-id='remove'>Remove</button>
</div>
</div>
</div>`;
const _radio = document.querySelectorAll('[type="radio"][data-id]');
const _bttn = document.querySelector('[type="button"][data-id="add"]');
const _div = document.querySelector('#divDynamicTexts');
const _input = document.querySelector('input[type="number"][data-id="textInput"]');
let choice = false;
let qty = false;
/*
Disable radio buttons and the "Create" button initially
and enable when changes are made in the correct sequence.
1: select quantity -> enable radio bttns
2: select single or double -> enable "create" bttn
3: click bttn, create as per radio selection
*/
_input.addEventListener('change', e => {
_radio.forEach(n => {
n.disabled = e.target.value > 0 ? false : true;
});
qty=e.target.value;
});
document.addEventListener('click', e => {
if (e.target instanceof HTMLInputElement && e.target.dataset.id != null) {
/*
set global "choice" variable
and enable "Create" bttn.
*/
if (e.target.type == 'radio') {
choice = e.target.dataset.id;
_bttn.disabled = false;
}
}
/*
If the "choice" has been made the radio
buttons will be enabled. Based on radio
button selected create new HTML and then
unhide the appropriate single/pair DIV
element
*/
if (choice && qty > 0 && e.target.type == 'button') {
_div.innerHTML = '';
for (let i = 0; i < qty; i++) _div.insertAdjacentHTML('afterbegin', strhtml);
let expr = `div[data-id="${choice}"]`;
document.querySelectorAll(expr).forEach(n => n.style.display = 'block');
}
/*
unchanged: delete DIV & contents when "Remove" bttn is clicked.
*/
if (e.target instanceof HTMLButtonElement && e.target.dataset.id != null) {
if (e.target.dataset.id == 'remove') {
_div.removeChild(e.target.closest('[data-id="dynrow"]'));
}
}
});
body {
font-family: arial;
}
label {
display: block;
}
.px-2 {
display: inline-block;
}
.px-2 label {
display: inline-block;
margin: 0.5rem;
}
h2 {
font-size: 1.1rem;
margin: 1rem 0 0 0;
display: inline-block;
width: auto;
}
.inline {
display: inline;
margin: 0 1rem 0 0;
}
#divDynamicTexts {
min-height: 1rem;
margin: 2rem auto
}
div.row {
padding: 0.5rem;
border: 1px dotted grey;
margin: 0.5rem;
}
div[data-id='single'] .form-group label {
background: aliceblue
}
div[data-id='pair'] .form-group label {
background: lightsteelblue
}
div[data-id] .form-group label {
outline: 1px solid grey;
padding: 0.5rem;
margin: 0.5rem 0
}
.bold {
font-weight: bold
}
[disabled]{
border:1px solid red;
outline:2px solid red;
background:rgba(255,0,0,0.25);
}
<div class='text-center'>
<label class='inline bold'>Quantity:<input type='number' data-id='textInput' /></label>
<div class='col-md-4'>
<div class='form-group'>
<h2>Library Type</h2>
<div class='px-2'>
<label>Single end: <input type='radio' data-id='single' name='check' disabled /></label>
<label>Paired end: <input type='radio' data-id='pair' name='check' disabled /></label>
</div>
</div>
</div>
<input type='button' data-id='add' value='Create upload fields' disabled />
</div>
<div id='divDynamicTexts'></div>
I have a series of forms on a page which each have a simple text counter on the input element (to illustrate the length of a title as it is being typed). When I was working out how to do the counter it was on a singular instance of the form.
How do I have it so the counter works in relation to the nextElementSibling when there are multiple instances of the form? I would've thought it would be done with e.target property, but I can't work out how to store the input element as a target so to speak? I thought e.target = item in the code below would work but this doesn't.
Codepen: https://codepen.io/thechewy/pen/powZppR
var title = document.querySelectorAll(".image-title-upload"),
charsRemaining = document.querySelectorAll(".image-title-upload").nextElementSibling,
maxValue = 125;
title.forEach((item) => {
item.addEventListener("input", (e) => {
//e.target = item; thought this might work but it doesn't
remaining = maxValue - item.value.length; // work out how many characters are left
charsRemaining.textContent = remaining;
});
});
form {
margin-bottom: 2rem;
}
span {
display: block;
margin-top: 4px;
}
<form>
<input class="image-title-upload" type="text" name="image-title" placeholder="Title">
<span class="tl characters-remaining">125</span>
</form>
<form>
<input class="image-title-upload" type="text" name="image-title" placeholder="Title">
<span class="tl characters-remaining">125</span>
</form>
this way
const
titleInput = document.querySelectorAll(".image-title-upload")
, maxValue = 125;
titleInput.forEach( item =>
{
item.oninput = e =>
{
item.nextElementSibling.textContent = maxValue - item.value.length
}
})
form {
margin-bottom: 2rem;
}
span {
display: block;
margin-top: 4px;
}
<form>
<input class="image-title-upload" type="text" name="image-title" placeholder="Title">
<span class="tl characters-remaining">125</span>
</form>
<form>
<input class="image-title-upload" type="text" name="image-title" placeholder="Title">
<span class="tl characters-remaining">125</span>
</form>
you can also use
e.target.closest('form').querySelector('.characters-remaining').textContent = ....
<pre>
<div class="quantity">
<input type="number" name="qty" id="qty" value="1" class="form-qty form-control" min="1">
<div class="quantity-nav">
<div class="quantity-button quantity-up qty-up">+</div>
<div class="quantity-button quantity-down qty-down">-</div>
</div>
</div>
<pre>
This is loop.
I want to get input value when i click quantity up & down button each time. There are multiple elements.
How to find input value in javascript by clicking button up & down.
You can add onClick event with parents feature to detect the inputs near to the button.
$(document).on('click','.quantity-up',function(){
$qtyElemnt = $(this).parents('.quantity').find('.form-qty');
$qty = $qtyElemnt.val();
$qtyElemnt.val(Number($qty)+1);
});
$(document).on('click','.quantity-down',function(){
$qtyElemnt = $(this).parents('.quantity').find('.form-qty');
$qty = $qtyElemnt.val();
$qtyElemnt.val(Number($qty)-1);
});
.quantity {
padding: 10px;
}
.quantity-nav{
display: inline-block;
}
.quantity-button {
display: inline-block;
padding: 5px;
background-color: #c7c5c5;
border: 1px solid #585353;
cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
<div class="quantity">
<input type="number" name="qty" value="1" class="form-qty form-control" min="1">
<div class="quantity-nav">
<div class="quantity-button quantity-up qty-up">+</div>
<div class="quantity-button quantity-down qty-down">-</div>
</div>
</div>
<div class="quantity">
<input type="number" name="qty" value="1" class="form-qty form-control" min="1">
<div class="quantity-nav">
<div class="quantity-button quantity-up qty-up">+</div>
<div class="quantity-button quantity-down qty-down">-</div>
</div>
</div>
<div class="quantity">
<input type="number" name="qty" value="1" class="form-qty form-control" min="1">
<div class="quantity-nav">
<div class="quantity-button quantity-up qty-up">+</div>
<div class="quantity-button quantity-down qty-down">-</div>
</div>
</div>
</div>
Thanks :-)
Actually your problem is quite easy to solve.
Try to add this script at the end of your <body>.
I suggest you to make some modifications in your html too: use <button> or <input type="button"or even <a> tags for your controls.
I added some logic about the min/max/step attributes you can set on a <input type="number"> but this is optional. It's up to you to change this.
document.addEventListener("DOMContentLoaded", function() {
const qtyWraps = document.getElementsByClassName('quantity');
for (let i = 0; i < qtyWraps.length; i++) {
const qtyWrap = qtyWraps.item(i);
const input = qtyWrap.querySelector('.form-qty');
const up = qtyWrap.querySelector('.qty-up');
const down = qtyWrap.querySelector('.qty-down');
const output = qtyWrap.querySelector('.output');
up.addEventListener('click', function(e) {
e.preventDefault();
addValue(1);
});
down.addEventListener('click', function(e) {
e.preventDefault();
addValue(-1);
});
input.addEventListener('input', function() {
output.textContent = input.value
});
const addValue = function(value) {
const current = parseInt(input.value);
const min = input.getAttribute('min') || -Infinity;
const max = input.getAttribute('max') || Infinity;
const step = input.getAttribute('step') || 1;
const newValue = Math.min(max, Math.max(min, current + value * step));
input.value = newValue;
if (newValue <= min) down.setAttribute('disabled', 'disabled');
else down.removeAttribute('disabled');
if (newValue >= max) up.setAttribute('disabled', 'disabled');
else up.removeAttribute('disabled');
input.dispatchEvent(new Event('input'));
}
addValue(0)
}
});
.quantity {
display: block;
width: 500px;
margin: auto;
text-align: center;
}
.quantity .form-qty {
display: inline-block;
}
.quantity .quantity-nav {
display: inline-block;
}
.quantity .output {
background: yellow;
width: 500px;
margin: 1em auto 0;
}
<div class="quantity">
<input type="number" name="qty" id="qty" value="1" class="form-qty form-control" min="1">
<div class="quantity-nav">
<button class="quantity-button quantity-up qty-up">+</button>
<button class="quantity-button quantity-down qty-down">-</button>
</div>
<!-- I put it here to show the output result -->
<div class="output">1</div>
</div>
You can use localStorage to store the value of your quantity, this would make the data persistent.
Please check the below code snippet:
const down = document.querySelector('.down');
const up = document.querySelector('.up');
const input = document.querySelector('.quantity');
// store utility function
const store = {
existsIn: function(key) {
return this.getFromKey(key) !== null;
},
getFromKey: function(key) {
return window.localStorage.getItem(key);
},
add: function(key, value) {
const storeSource = window.localStorage.setItem(key, value);
}
}
const quantity = Object.create(store);
quantity.exists = function() {
return this.existsIn('quantity');
}
quantity.increase = function() {
let storedQuantity = this.exists() ? parseFloat(this.getFromKey('quantity')) : 0;
storedQuantity = storedQuantity + 1;
this.add('quantity', storedQuantity);
}
quantity.decrease = function() {
let storedQuantity = this.exists() ? parseFloat(this.getFromKey('quantity')) : 0;
if(storedQuantity > 0) {
storedQuantity = storedQuantity - 1;
}
this.add('quantity', storedQuantity);
}
quantity.show = function() {
return this.exists() ? this.getFromKey('quantity') : 0;
}
// event listeners for up and down buttons
up.addEventListener('click', function() {
quantity.increase();
// update input on button click
input.value = quantity.show();
})
down.addEventListener('click', function() {
quantity.decrease();
// update input on button click
input.value = quantity.show();
})
// update input on page load
input.value = quantity.show();
There you can find a working fiddle:
https://jsbin.com/tavalocoti/5/edit?html,js,console,output
I am trying to change the display property of some text using JS, upon button click.
I have confirmed that the function is firing and running correctly using debugger, but for some reason, I can't grab the specific element I need to change, and assign it to a variable. I also have jquery set up on the page.
I have tried using the console, and document.getElementById('warning-textID') returns the correct element, but when I try to set it to a variable in console, it returns undefined. Am I missing something super obvious here?
Here is the HTML, function and css.
//adding event listener
$(function() {
document.getElementById("submitdiscount").addEventListener("click", putCookie);
});
// click function
function putCookie() {
var enteredValue = document.getElementById("nameBox").value;
var validParam = "test";
var warning = document.getElementById("warning-textID");
var cookieCreated = false;
if(enteredValue == validParam){
console.log('do the thing')
if(cookieCreated == false && enteredValue == validParam){
warning.innerText = "Please enable cookies";
warning.style.display = "";
return;
} else {
warning.innerText = "Please enter the correct code."
warning.style.display = "";
enteredValue.value = "";
return;
}
}
.warning-text {
color: red; text-align: center;
margin-bottom: 0px;
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="employee-code-input-wrapper" id="employee-code-input">
<div class="employee-code-input-header">
<h2>Enter the employee code you received via email</h2>
</div>
<div class="search-bar emplyoee-code-input-input-wrapper" >
<input class="emplyoee-code-input-input" type="text" placeholder="Enter Employee Code" code="" id="nameBox" name="pass">
<button class="btn btn--submit-employee-form" value="Submit" id="submitdiscount" type="button">submit</button>
</div>
<h2 class="warning-text" id="warning-textID">
Please enter the correct code.
</h2>
</div>
I fixed some mistakes and it worked.
//adding event listener
$(function() {
document.getElementById("submitdiscount").addEventListener("click", putCookie);
// click function
function putCookie() {
var enteredValue = document.getElementById("nameBox").value;
var validParam = "test";
var warning = document.getElementById("warning-textID");
var cookieCreated = false;
if (enteredValue === validParam) {
console.log('do the thing')
if (cookieCreated == false && enteredValue === validParam) {
warning.innerText = "Please enable cookies";
warning.style.display = "block";
return;
}
} else {
warning.innerText = "Please enter the correct code."
warning.style.display = "block";
enteredValue.value = "";
return;
}
}
});
.warning-text {
color: red;
text-align: center;
margin-bottom: 0px;
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="employee-code-input-wrapper" id="employee-code-input">
<div class="employee-code-input-header">
<h2>Enter the employee code you received via email</h2>
</div>
<div class="search-bar emplyoee-code-input-input-wrapper">
<input class="emplyoee-code-input-input" type="text" placeholder="Enter Employee Code" code="" id="nameBox" name="pass">
<button class="btn btn--submit-employee-form" value="Submit" id="submitdiscount" type="button">submit</button>
</div>
<h2 class="warning-text" id="warning-textID">
Please enter the correct code.
</h2>
</div>
I am using - and + buttons to change the number of the text box, I am having troubles dealing with different text fields, here is my code:
var unit = 0;
var total;
// if user changes value in field
$('.field').change(function() {
unit = this.value;
});
$('.add').click(function() {
unit++;
var $input = $(this).prevUntil('.sub');
$input.val(unit);
unit = unit;
});
$('.sub').click(function() {
if (unit > 0) {
unit--;
var $input = $(this).nextUntil('.add');
$input.val(unit);
}
});
button {
margin: 4px;
cursor: pointer;
}
input {
text-align: center;
width: 40px;
margin: 4px;
color: salmon;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id=field1>
field 1
<button type="button" id="sub" class=sub>-</button>
<input type="text" id="1" value=0 class=field>
<button type="button" id="add" class=add>+</button>
</div>
<div id=field2>
field 2
<button type="button" id="sub2" class=sub>-</button>
<input type="text" id="2" value=0 class=field>
<button type="button" id="add2" class=add>+</button>
</div>
And here's the DEMO
You can see in the demo that the values change correctly only if you click buttons on the same field, but if you alternate between fields the values don't change properly.
This should be all you need:
$('.add').click(function () {
$(this).prev().val(+$(this).prev().val() + 1);
});
$('.sub').click(function () {
if ($(this).next().val() > 0) $(this).next().val(+$(this).next().val() - 1);
});
By using the unit variable you were tying both inputs together. And the plus in +$(this) is a shorthand way to take the string value from the input and convert it to a number.
jsFiddle example
You're using the same variable to hold the values of your two inputs. One simple option would be to use two variables instead of one:
var unit_1 = 0;
$('#add1').click(function() {
unit_1++;
var $input = $(this).prev();
$input.val(unit_1);
});
/* Same idea for sub1 */
var unit_2 = 0;
$('#add2').click(function() {
unit_2++;
var $input = $(this).prev();
$input.val(unit_2);
});
/* Same idea for sub2 */
and unit = unit just assigns the value of unit to itself, so that's no very useful and you can certainly leave it out.
An alternative approach is to use data attributes and have each element store its own value. Edit: it already stores its own value. Just access it.
var total;
// if user changes value in field
$('.field').change(function() {
// maybe update the total here?
}).trigger('change');
$('.add').click(function() {
var target = $('.field', this.parentNode)[0];
target.value = +target.value + 1;
});
$('.sub').click(function() {
var target = $('.field', this.parentNode)[0];
if (target.value > 0) {
target.value = +target.value - 1;
}
});
button {
margin: 4px;
cursor: pointer;
}
input {
text-align: center;
width: 40px;
margin: 4px;
color: salmon;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id=field1>
field 1
<button type="button" id="sub" class=sub>-</button>
<input type="text" id="1" value=0 class=field>
<button type="button" id="add" class=add>+</button>
</div>
<div id=field2>
field 2
<button type="button" id="sub2" class=sub>-</button>
<input type="text" id="2" value=0 class=field>
<button type="button" id="add2" class=add>+</button>
</div>