Javascript - Watch for 1st interaction/change on form element - javascript

I would like to know how to go about watching for the first change event on a series of form fields/input elements (I have multiple selects/dropdowns and text inputs), and trigger something, but only trigger it once. Not every time an item is changed. And any one of the fields can trigger it.
My situation is I have a services calculator that outputs both a quote for self funding and also estimates which government package level will cover their needs, there's a lot of select input elements/dropdowns and I want any one of these to be able to trigger the event above but only once, (first interaction with the calculator basically) but they are not in a form because we don't need to submit anything, just display the results (this is dynamically updated as fields are changed using .onchange). All of this calculation logic is working correctly I don't need help with any of that.
I just want to know how one would approach this with vanilla JS, if at all possible?

Use event delegation: add an input event listener to an element that's a parent of all the <form>s (it could be the document.body):
let hasRun = false;
document.querySelector('.container').addEventListener('input', (e) => {
if (hasRun) return;
hasRun = true;
console.log('Handler running');
});
<div class='container'>
<form>
<select>
<option>foo</option>
<option>bar</option>
</select>
<input />
</form>
<form>
<select>
<option>foo</option>
<option>bar</option>
</select>
<input />
</form>
</div>
Or, with the once option (warning, not supported in IE):
document.querySelector('.container').addEventListener(
'input',
(e) => {
console.log('Handler running');
},
{ once: true }
);
<div class='container'>
<form>
<select>
<option>foo</option>
<option>bar</option>
</select>
<input />
</form>
<form>
<select>
<option>foo</option>
<option>bar</option>
</select>
<input />
</form>
</div>

Related

Multiple triggers for HTMX?

Is it possible to enable multiple trigger types for HTMX? What I want to do is to trigger HTMX on either content change or page load. So far, if I include both trigger types in hx-trigger, only the first trigger is executed; so in the example below, HTMX is triggered only upon content change.
<select name="area" id="area" hx-post="/api/search" hx-trigger="change load" hx-target="#neighborhood" class="block">
<option>eby</option>
<option>nby</option>
<option>pen</option>
<option>sfc</option>
<option>scz</option>
<option>sby</option>
</select>
It's as simple as comma-separating your trigger types:
<select name="area" id="area" hx-post="/api/search" hx-trigger="change, load" hx-target="#neighborhood" class="block">
<option>eby</option>
<option>nby</option>
<option>pen</option>
<option>sfc</option>
<option>scz</option>
<option>sby</option>
</select>

Passing option value to onSubmit?

I have a form being rendered in a React component. Inside the form are an input field, an option dropdown, and a button to submit.
Basically when the button is clicked, I want to pass the selected option into the onSubmit handler, which in the code below is chef.id.
The problem is, all the chef objects are mapped inside the form, and I'm not sure how to extract the selected chef, to pass into onSubmit.
I didnt use this for the event listener methods because I'm using redux, though I suppose that's not relevant to this particular problem.
return (
<div className="form-input">
<form onSubmit={handleSubmitRecipes(**chef.id**)}>
<input onChange={handleChange}/>
<select>
{chefs.map(chef => <option value={chef.name}>{chef.name}</option>)}
</select>
<button>Create</button>
</form>
</div>
)
Thanks in advance!
If you are willing to try some original DOM operations, maybe below codes can help you.
<form>
<input name="name" />
<select name="age">
<option>10</option>
<option>20</option>
<option>30</option>
</select>
<button>submit</button>
</form>
const [form] = document.getElementsByTagName("form");
form.addEventListener("submit", function(event) {
console.log(form.age.value);
console.log(form.name.value);
event.preventDefault();
}, false);

Value is generated by onClick event, but it is not inserted into inner HTML. Why?

When I return the value from the javascript function on the onClick event, it is getting inserted but the form refreshes again and I lose the selection and the values that I have inserted.
Why does this happen and how can i avoid it?
Below is a sample of my code:
<form id="lengthConvert">
<p><b>Enter a value : </b></p><input type="number" name="inputValue" />
<p><b>Convert from : </b></p>
<select name="fromUnit">
<option value="Centimeter">Centimeter</option>
<option value="Meter">Meter</option>
<option value="Kilometer">Kilometer</option>
<option value="Miles">Miles</option>
</select>
<p><b>Convert to : </b></p>
<select name="toUnit">
<option value="Centimeter">Centimeter</option>
<option value="Meter">Meter</option>
<option value="Kilometer">Kilometer</option>
<option value="Miles">Miles</option>
</select>
<br/><p id="Output"></p>
<button type="submit" form="lengthConvert" value="Submit" onclick="getElementById('Output').innerHTML=convert()">Convert</button>
</button>
</div>
</body>
</html>
<script>
function convert(){
var value = document.getElementsByName('inputValue')[0].value;
var fromUnit= document.getElementsByName('fromUnit')[0].value;
var toUnit= document.getElementsByName('toUnit')[0].value;
if(fromUnit==toUnit){
return value;
}
}
</script>
when I am returning the value from the javascript method on onclick event, it is getting inserrted but the form refreshes again and I am loosing all the selection and values which i have inserted.
Why? and how can i avoid that?
When you click the button you're submitting your form because you're not doing anything to stop the default behavior. Change
<button type="submit"...
to
<button type="button"...
As a side note, your HTML needs to be fixed as you have an extra </button>, no closing </form>, and an unopened </div>. Also, your function doesn't appear to do any actual conversion.
You need to do two things:
Pass event object from onclick() function
Prevent form submission inside convert function by using preventDefault();
function convert(e) {
e.preventDefault();
var value = document.getElementsByName('inputValue')[0].value;
var fromUnit = document.getElementsByName('fromUnit')[0].value;
var toUnit = document.getElementsByName('toUnit')[0].value;
if (fromUnit == toUnit) {
return value;
}
}
<form id="lengthConvert">
<p><b>Enter a value : </b></p><input type="number" name="inputValue" />
<p><b>Convert from : </b></p>
<select name="fromUnit">
<option value="Centimeter">Centimeter</option>
<option value="Meter">Meter</option>
<option value="Kilometer">Kilometer</option>
<option value="Miles">Miles</option>
</select>
<p><b>Convert to : </b></p>
<select name="toUnit">
<option value="Centimeter">Centimeter</option>
<option value="Meter">Meter</option>
<option value="Kilometer">Kilometer</option>
<option value="Miles">Miles</option>
</select>
<br/>
<button type="submit" form="lengthConvert" value="Submit" onclick="getElementById('Output').innerHTML=convert(event)">Convert</button>
<div id='Output'></div>
</form>
You are submitting your form, which causes the page to reload, thus wiping out whatever was updated on it prior to the submit. Instead, you'll want to use a regular button (<button type="button">).
But, beyond that, your code is very outdated and inefficient. .getElementsByName() is generally not recommended for performance reasons, but in your case it's even worse because you only want one element, so you're scanning the entire DOM, getting a set of matching elements and then throwing away all but one of them. Use the modern .querySelector() and .querySelectorAll() for most of your DOM searches.
Your HTML is also invalid because you have an extra closing button tag an no closing form tag.
Also, the use of inline event attributes (onclick) should not be used. This is a 25+ year old technique that just won't die because it's easy and people just copy/paste other code they've found that seems to work. There are a lot of reasons not to do this.
There are a number of other concerns in your code as well. Here's your solution, cleaned up and modernized (make sure to see the HTML, CSS, and JS comments):
/* We can style the rows any way we want: */
div.row { margin-top:1em; margin-bottom:1em; font-weight:bold; }
<form id="lengthConvert">
<!--
The us of <p> elements here is really not correct as they mean paragraph, which
itself means "thought or idea". You are just using them for vertical spacing, and
we should not be using HTML for presentation, that's for CSS. Along the same vein,
<b> isn't appropriate here either because you are just using it for presentation.
Instead, a semantically neutral tag like <div> should be used for rows.
CSS classes can be added to control the presentation
-->
<div class="row">Enter a value : </div>
<div class="row">
<!--
Don't use self-termination syntax <tag />.
That syntax is very old an only applies to XHTML, which is not used
very much these days. Adding that syntax buys you nothing.
-->
<input type="number" name="inputValue">
</div>
<div class="row">Convert from :</div>
<div class="row">
<!-- You don't need to set a value for an <option> when
you want the value of an <option> to be the same as
the text of the <option>. The text of the selected
<option> will become the value of the <select> by default.
-->
<select name="fromUnit">
<option>Centimeter</option>
<option>Meter</option>
<option>Kilometer</option>
<option>Miles</option>
</select>
</div>
<div class="row">Convert to :</div>
<div class="row">
<select name="toUnit">
<option>Centimeter</option>
<option>Meter</option>
<option>Kilometer</option>
<option>Miles</option>
</select>
</div>
<div class="row" id="Output"></div>
<!-- The form attribute is only used when a form element is placed outside of the
form it relates to.
Also, don't use inline HTML event attributes.
And, there is no need to add a value attribute unless you want the value
to be something different than the text of the element.
-->
<button type="button">Convert</button>
</form>
<script>
// Get all the element references you know you'll need
let btn = document.querySelector("button[type='button'");
let output = document.getElementById('Output');
// You only have one element with a name of "inputValue". Use
// .querySelector() with a valid CSS selector as an argument
// to find the first item that matches the selector.
// Also, don't assign variables to properties of an element because
// if you ever want to get a second property value, you'll have to
// scan the document all over again for the element. Just store a
// reference to the element itself, then you can access that as often
// as you like.
let input = document.querySelector("input[name='inputValue']");
let fromUnit = document.querySelector("select[name='fromUnit']");
let toUnit = document.querySelector("select[name='toUnit']");
// Set up your event handling in JavaScript, not HTML
btn.addEventListener("click", convert);
function convert(){
console.log(fromUnit.value, toUnit.value);
if(fromUnit.value == toUnit.value){
// Use .textContent when getting/setting text that
// does not contain any HTML. Its's quicker and
// safer.
output.textContent = input.value;
}
}
</script>

Change form action target without JavaScript

I have a form with select box. With JavaScript on, I take the change event to define the options-values as location.hrefs:
$('select').change(function(){
window.location.href = $(this).val();
});
With JavaScript off, I have a basic form with a submit button. To follow the targets given in the option values, I have to set them to the form action. Do you have any idea how I could get only the selected option as form target e.g. with any CSS selector or something like that?
The form:
<form action="test-1.html">
<fieldset>
<select id="lorem">
<option value="test-1.html">test1</option>
<option value="test-2.html">test2</option>
<option value="test-3.html">test3</option>
</select>
<input type="submit" value="senden" class="submit" />
</fieldset>
</form>
You will have to do this in server-side code. Without JavaScript enabled, there is no way to dynamically change anything in an HTML DOM.
So, submit to some intermediary page that's sole purpose is to redirect and perform the logic there.

jqtransform onclick events not firing

I have a form using the jqtransform jQuery plugin that gives forms an aesthetic makeover. However, I can't get my onclick events to fire.
I have a form setup similar to this:
<select name="person">
<option value="1">Yes</option>
<option value="2">No</option>
<option class="maybe" value="0">Maybe</option>
</select>
I also have a hidden div container which expands the form:
<div class="expander" style="display:none;">
More info <input type="text" name="moreinfo" />
</div>
Then the final piece of the puzzle:
<script>
$(".maybe").click(function () {
$(".expander").show("slow");
});
</script>
Any help would be greatly appreciated.
try using the change event instead of click.
http://api.jquery.com/change
here's a working example: http://jsfiddle.net/dwick/Sh4PA/
This is a dirty workaround, but works for me...
change the type of your input field to reset, then add an onclick event handler
<input type='reset' value='submit' onclick='$(#myFormId).submit()' />

Categories