Target Input and nextElementSibling With forEach Loop / event.Target Property - JavaScript - javascript

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 = ....

Related

how to get lowest value to turn red and back to black when it gets higher?

im trying to make a script to turn the lowest value to red and back to black when it gets higer again.
function findLowest() {
// Get the input elements
var value1 = document.getElementById("value1");
var value2 = document.getElementById("value2");
var value3 = document.getElementById("value3");
// Find the lowest number value
var lowestValue = Math.min(parseInt(value1.value), parseInt(value2.value), parseInt(value3.value));
// Check which element has the lowest number value and add the "lowest" class to it
if (parseInt(value1.value) === lowestValue) {
value1.classList.add('lowest');
} else if (parseInt(value2.value) === lowestValue) {
value2.classList.add('lowest');
} else if (parseInt(value3.value) === lowestValue) {
value3.classList.add('lowest');
}
}
.lowest {
color: red;
}
input:not(.lowest) {
color: black;
}
<form>
<label for="value1">Value 1:</label><br>
<input type="number" id="value1" name="value1" oninput="findLowest()"><br>
<br>
<label for="value2">Value 2:</label><br>
<input type="number" id="value2" name="value2" oninput="findLowest()"><br>
<br>
<label for="value3">Value 3:</label><br>
<input type="number" id="value3" name="value3" oninput="findLowest()"><br>
</form>
i got this to work but i cant get it back to black. my goal with this is to create a result tab on the left where it points out the lowest number with red.
not in the text field.
Resetting the values all back to black in the beginning of the function should leave you with only one red number at the end of it.
function findLowest() {
// Get the input elements
var value1 = document.getElementById("value1");
var value2 = document.getElementById("value2");
var value3 = document.getElementById("value3");
// Remove class "lowest" to turn all numbers black
value1.classList.remove('lowest');
value2.classList.remove('lowest');
value3.classList.remove('lowest');
// Find the lowest number value
var lowestValue = Math.min(parseInt(value1.value), parseInt(value2.value), parseInt(value3.value));
// Check which element has the lowest number value and add the "lowest" class to it
if (parseInt(value1.value) === lowestValue) {
value1.classList.add('lowest');
} else if (parseInt(value2.value) === lowestValue) {
value2.classList.add('lowest');
} else if (parseInt(value3.value) === lowestValue) {
value3.classList.add('lowest');
}
}
maybe that ?
Use:
A- .valueAsNumber to get a input[type=number] number value ( not a string)
B- classList.toggle with it force boolean argument
C- event input directly on the form (not on each element)
const
myForm = document.forms['my-form']
, inNums = [...myForm.querySelectorAll('input[type=number]')]
;
myForm.oninput = event =>
{
let min = inNums.reduce((min,el)=>Math.min(el.valueAsNumber, min), Infinity);
inNums.forEach( el => el.classList.toggle('lowest', el.value == min));
}
body {
font-family : Arial, Helvetica, sans-serif;
font-size : 16px;
}
.lowest {
color : red;
}
label, input {
display : block;
}
label {
font-size : .8rem;
margin : .8rem
}
input {
font-size : 1rem;
padding : 0 0 0 0.5em;
width : 6rem;
}
<form name="my-form">
<label>Value 1:
<input type="number" name="value1" value="0" >
</label>
<label>Value 2:
<input type="number" name="value2" value="0">
</label>
<label>Value 3:
<input type="number" name="value3" value="0">
</label>
</form>
You can do it simply by remove the lowest class from all inputs before doing anything in the function, and then determine the new lowest to give it the class, and this is the simple but big way.
To take a short and clear way, just do that:
function findLowest() {
var inputs = [...document.querySelectorAll("input[type=number]")]
let values = inputs.map(input => input.value)
var lowest = Math.min(...values)
inputs.forEach(input => {
input.classList[ input.value == lowest ? "add" : "remove" ]("lowest")
})
}
.lowest { color: red; }
input:not(.lowest) { color: black; }
<form>
<label for="value1">Value 1:</label><br>
<input type="number" id="value1" name="value1" oninput="findLowest()"><br>
<br>
<label for="value2">Value 2:</label><br>
<input type="number" id="value2" name="value2" oninput="findLowest()"><br>
<br>
<label for="value3">Value 3:</label><br>
<input type="number" id="value3" name="value3" oninput="findLowest()"><br>
<label for="value4">Value 4 => "text":</label><br>
<input type="text" id="value4" name="value4"><br>
</form>
We're getting the inputs as an array, then get the values of the inputs with the map method, then get the lowest value with Math.min method, and finally loop over all inputs using the forEach method, and conditionally choose to add or remove the lowest class from the input that has the lowest value.

Concate two input string instantly without a button(as soon as we move the cursor out of the second box)

A javascript program to concate the first name and last name, but the concated string gets displayed as the cursor moves out from the last name text box
`
<!DOCTYPE html>
<html lang="en">
<head>
<title>Practical 3</title>
<style>
#concatenator {
background-color: white;
height: 150px;
width: 330px;
border-width: 4px;
border-color: black;
border-style: solid;
padding: 5px;
}
</style>
<script>
function concat() {
fst = String(myform.fst.value);
snd = String(myform.snd.value);
result = fst.concat(" ", snd);
myform.result.value = result;
}
function refresh() {
location.reload();
}
</script>
</head>
<body id="concatenator">
<form name="myform">
Enter first name: <input type="text" name="fst"><br><br>
Enter second name: <input type="text" name="snd"><br><br>
<input type="Button" name="" value="Refresh" onclick="refresh()">
<input type="Button" name="" value="Full Name" onclick="concat()"><br><br>
Full Name: <input type="text" name="result">
</form>
</body>
</html>
`
I have to makes changes in this so that the full name button is gone and the two name are concatenated instantly
To achieve that result you may use a keyup event handler on your input elements so that a given logic will be executed every time the user type something.
Such logic just fetches the values of those input elements, concatenates the two string and sets the value of the return input element.
I used a general approach as far as possible so that the conditions to fetch those two input elements are defined as css selectors in the targetSelectors array.
//selectors relative to the root document for the input element to concat
const targetSelectors = ['#myform [name=fst]', '#myform [name=snd]'];
//adds a keyup event handler to all the elements in targetSelectors
targetSelectors.forEach( (targetSelector) => {
document.querySelector(targetSelector)
.addEventListener('keyup', (event) => {
//concats the fields value
const concatenated = concatFields(' ');
//refreshes the result input field value with the new one
refreshField('input[name=result]', concatenated);
});
});
//sets the value of the input element found with targetSelector
function refreshField(targetSelector, value){
document.querySelector(targetSelector).value = value;
}
//returns the concatenated values from the input elements in targetSelectors (separated by spacer)
function concatFields(spacer = ''){
return targetSelectors.map( targetSelector => document.querySelector(targetSelector).value ).join(spacer);
}
<!DOCTYPE html>
<html lang="en">
<head>
<title>Practical 3</title>
<style>
#concatenator {
background-color: white;
height: 150px;
width: 330px;
border-width: 4px;
border-color: black;
border-style: solid;
padding: 5px;
}
</style>
<script>
function concat() {
fst = String(myform.fst.value);
snd = String(myform.snd.value);
result = fst.concat(" ", snd);
myform.result.value = result;
}
function refresh() {
location.reload();
}
</script>
</head>
<body id="concatenator">
<form id="myform">
Enter first name: <input type="text" name="fst"><br><br>
Enter second name: <input type="text" name="snd"><br><br>
Full Name: <input type="text" name="result">
</form>
</body>
</html>
And this an attempt went too far with the generalization able to keep an arbitrary number of inputs bound to each other in the aim of concatenating their values inside an output element when the change event occurs on any of those inputs.
*the answer was accepted already.. it was for the sake of making sense of the generalized approach and nothing else
const c = new Concatenator(
retrieveClassSelectors('#showingMaxPotential input.concat'),
'#showingMaxPotential input[name=result]');
//returns an array of selector (sorted) based on the class attribute belonging to all the elements grabbed by the matchingSelector
function retrieveClassSelectors(matchingSelector){
const specificSelectors =
[...document.querySelectorAll(matchingSelector)]
.map(target => {
const classesSelector =
target.getAttribute('class')
.replace(/[^\s]+/g, '.$&')
.replace(/\s/g, '');
return classesSelector;
}).sort();
return specificSelectors;
}
function Concatenator(targetSelectors, outputSelector) {
this.init = () => {
//adds a keyup event handler to all the elements in targetSelectors
this.targetSelectors.forEach((targetSelector) => {
document.querySelector(targetSelector)
.addEventListener('keyup', (event) => {
//refreshes the result input field value with the new one
this.refreshField(this.outputSelector, this.concatFields(' '));
});
});
}
//sets the value of the input element found with targetSelector
this.refreshField = (targetSelector, value) => {
document.querySelector(targetSelector).value = value;
}
//returns the concatenated values from the input elements in targetSelectors (separated by spacer)
this.concatFields = (spacer = '') => {
return this.targetSelectors.map(targetSelector => document.querySelector(targetSelector).value).join(spacer);
}
this.targetSelectors = targetSelectors;
this.outputSelector = outputSelector;
this.init();
}
form#showingMaxPotential{
border: solid 1px darkgray;
padding: 1em;
}
form#showingMaxPotential > label,
form#showingMaxPotential > input{
display: block;
}
form#showingMaxPotential > input{
margin-bottom: 1em;
}
<form id="showingMaxPotential">
<label>Enter <b>first</b> item name:</label>
<input type="text" name="i1" class="concat item-1">
<label>Enter <b>last</b> item name:</label>
<input type="text" name="i3" class="concat item-3">
<label>Enter <b>middle</b> item name:</label>
<input type="text" name="i2" class="concat item-2">
<label>Full Name:</label>
<input type="text" name="result" disabled>
</form>

independent elemants onclick, same class name vanila js

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>

Button to clear text and reset search input not working

Ok, so I have a filterable search form that returns certain images in a grid, which works great, it resets when I delete the text in the search input, but when I click the "Clear" button, which should do the same thing as deleting the text, it doesn't work. Here is the HTML and JQuery used:
<form id="live-search" action="" class="styled" method="post" style="margin: 2em 0;">
<div class="form-group">
<input type="text" class="form-control" id="filter" value="" style="width: 80%; float: left;" placeholder="Type to search"/>
<span id="filter-count"></span>
<input type="button" class="clear-btn" value="Clear" style="background: transparent; border: 2px solid #af2332; color: #af2332; padding: 5px 15px; border-radius: 3px; font-size: 18px; height: 34px;">
</div>
</form>
This is the JQuery for the clearing text:
jQuery(document).ready(function(){
jQuery("#filter").keyup(function(){
// Retrieve the input field text and reset the count to zero
var filter = jQuery(this).val(), count = 0;
// Loop through the comment list
jQuery(".watcheroo").each(function(){
jQuery(this).removeClass('active');
// If the list item does not contain the text phrase fade it out
if (jQuery(this).text().search(new RegExp(filter, "i")) < 0) {
jQuery(this).fadeOut();
// Show the list item if the phrase matches and increase the count by 1
} else {
jQuery(this).show();
count++;
}
});
// Update the count
var numberItems = count;
});
//clear button remove text
jQuery(".clear-btn").click( function() {
jQuery("#filter").value = "";
});
});
Any help would greatly be appreciated.
value is a property on a DOMElement, not a jQuery object. Use val('') instead:
jQuery(document).ready(function($) {
$("#filter").keyup(function() {
var filter = $(this).val(),
count = 0;
$(".watcheroo").each(function(){
var $watcheroo = $(this);
$watcheroo.removeClass('active');
if ($watcheroo.text().search(new RegExp(filter, "i")) < 0) {
$watcheroo.fadeOut();
} else {
$watcheroo.show();
count++;
}
});
var numberItems = count;
});
$(".clear-btn").click(function() {
$("#filter").val(''); // <-- note val() here
});
});
Note that I amended your code to alias the instance of jQuery passed in to the document.ready handler. This way you can still use the $ variable safely within the scope of that function.
As the accepted answer doesn't solve the problem.
Try input event instead of keyup
$("#filter").on("input", function() {.....
& then clear the filter input field on which event you want.
$(".clear-btn").on("click", function() {
$("#filter").val("").trigger("input");
});
Add this to your CSS:
input[type="search"]::-webkit-search-cancel-button {
-webkit-appearance: searchfield-cancel-button;
}
<form>
<input type="search" name="search" placeholder="Search...">
</form>

Multiple plus and minus buttons

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>

Categories