I am trying to use Javascript/jQuery to get data from a form and save the value to a variable. There is only a single text input and submit button in the form, and only one piece of data will need to be retrieved. I pieced together this code from examples online but it isn't giving me any output.
$("#submit").onclick = function() {
var input = "";
$("#binary-input").click(function() {
var x = $("form").serializeArray();
$.each(x, function(i, field) {
input = field.value;
});
});
console.log("Input: ");
console.log(input);
}
A fix for my code is what I'm requesting, but a more efficient approach would also be much appreciated.
First off jQuery doesn't have an 'onclick' event handler. You can either use 'click' (https://api.jquery.com/click/) like so:
$("#submit").click(function()...
Or use 'on' (https://api.jquery.com/on/) and specify the type of event you want to handle
This is what I'd normally do:
$("#submit").on("click", function(){
// Get the input and its value
var inputValue = $("#binary-input").val();
// Output the value
console.log(inputValue);
}
Hope that helps.
Related
I can save and restore a user input in a text field, based on the ID of the field - the code works as i expect, like:
function save_options() {
var api = document.getElementById('text_field').value;
chrome.storage.sync.set({
savedApi: api,
});
}
document.getElementById("save").addEventListener("click", save_options);
function restore_options() {
chrome.storage.sync.get({"savedApi": ''}, function(items) {
document.getElementById('text_field').value = items.savedApi;
});
}
document.addEventListener('DOMContentLoaded', restore_options);
Now i want to save the check status of multiple checkboxes. Should i really repeat this construction for every checkbox? Could somebody point me to a smarter way to save status of multiple checkboxes?
IF this inputs are in side a form you can use this method to get all form data
First way (It is 2019 and there's a better way to do this):
const form = document.querySelector('form'):
const data = new URLSearchParams(new FormData(form).entries());
Second way (or if you want a plain Object instead):
const form = document.querySelector('form');
const data = Object.fromEntries(new FormData(form).entries());
I am using a backend where it is ideal that I send an ajax post request rather than using the default action on forms.
With this in mind, I need to extract the final fields that are selected in my form.
I have various text fields, radio buttons, checkboxes, etc.
I've always struggled gaining a good understanding of event delegation and event propagation. I'm not entirely sure if this is the topic I should be worried about with what I am trying to achieve.
I know I can write code that grabs all of the information in my form by placing an ID on each field and a have a function extract each value on the ID such as:
function example(){
var field0 = $('#field0').val();
var field1 = $('#field1').parent().hasClass('active')
// ... and more
}
I've used this pattern for a while and I don't feel like it is efficient.
I have two pattern idea, but I am still not sure if this is a "common practice"
Since I am not concerned about the data in each field until the form is submitted, I could run a loop on all of my input based fields on my form and extract the contents, instead of assigning an ID to each individual input field.
I can listen to changes on the form (I am not exactly sure how to do this, this is where event delegation/propagation will come into play). Instead of waiting for the submit button to gather all the info in the form, I will have some type of listener that detects a change on the form (not sure if that is possible).
I've been using my current pattern for several months and would like to improve myself, If anyone has any suggestions, links, or criticism about my thoughts on a new approach I'd appreciate it.
So, you basically propose 3 ways to get all form fields with a value on submit (or a similar event):
hard-code IDs and retrieve their values, e.g.
var field_a = document.getElementById('a')
, field_b = document.getElementById('b')
, form = document.getElementById('my_form');
form.addEventListener('submit', function() {
fetch('//your/api/endpoint', {
method: 'POST',
body: JSON.stringify({a: field_a.value, b: field_b.value})
});
});
loop all and retrieve their values, e.g.
var form = document.getElementById('my_form');
form.addEventListener('submit', function() {
var values = [].reduce.call(
form.querySelectorAll('input, textarea, select'),
function(values, element) {
values[element.name] = element.value;
return values;
},
{}
);
fetch('//your/api/endpoint', {
method: 'POST',
body: JSON.stringify(values)
});
});
watch for changes inside the form, accumulate them
var form = document.getElementById('my_form')
, state = {};
form.addEventListener('change', function(e) {
state[e.srcElement.name] = e.value;
});
form.addEventListener('submit', function() {
fetch('//your/api/endpoint', {
method: 'POST',
body: JSON.stringify(state)
});
});
From a performance perspective, option 1. will be the fastest, followed by 2 followed by 3 (with the last 2 I'm not 100% certain, querySelectorAll can be expensive, but listening for tons of change events might be as well -- depends on how often change events are triggered I'd say).
From development perspective (how long does it take to set up a form), 2 and 3 should not be that different as they are both generic (and you can use my code sample as a start).
"Real" data-binding (like Angular) or "pure state" (like React) pretty much come down to options 2/3 as well (just that the framework will perform the heavy lifting for you).
Regarding option 3 (listening for a change on the whole form): https://stackoverflow.com/a/4616720/1168892 explains quite well how event bubbling in JavaScript happens. To use that you have to make sure that no element inside the form cancels the change event (otherwise it would not bubble to the form itself). To not cancel events is the default behavior, so you would have to explicitly make this wrong (and with that you can just have an eye on it in your implementation).
I didn't use jQuery in my examples as that can all be done by browsers directly now. What I used are Element.querySelectorAll, Array.reduce and window.fetch.
Pattern #1 (use serializeArray)
$('#formId').on('submit', function(e){
var allData;
e.preventDefault();
allData = $(this).serializeArray();
// use the allData variable when sending the ajax request
});
Pattern #2 (use the delegated form of $container.on('event', 'selector', ..) and the change event)
$('#formId').on('change', 'input,textarea,select', function(){
var element = $(this), // element that changed
value = element.val(); // its new value
// do what you want ..
});
Without jquery I once wrote a function that return in an object all input value tie with its name.
I think it's better than plain id link, because you don't have to worry about what's inside your form, as long as your giving a name attribute to your inputs.
function getFormData(form) {
var data = {};
for (var i = 0; i < form.elements.length; i++) {
var input = form.elements[i];
if (input.value && input.type !== 'submit' && input.type !== 'button') {
data[input.name] = input.value;
}
}
return data;
}
All you need to do is passing your form like this:
var form = document.querySelector('.monFormulaire');
// your form data
var data = getFormData(form);
I have a function which uses an onload event, lets say it looks like this
var doOnload = function(){
onload = function(){
//do stuff and return data
return data;
}
onerror = function(){
//handle error
return errormsg;
}
}
In the beginning I used a console.log output, but now I need the data to be processed.
The doOnload-function is called by another function. This other function creates an iframe and is writing the data into a form and this is working fine with other functions. Now after the form is filled I want to send the data via POST. This is also working fine. Only the doOnload function is returning 'undefined'.
The iframe/form-filling function looks something like this:
//...
input = this.createInputElement('nameOfField1',
function1());
form.appendChild(input);
input = this.createInputElement('nameOfField2',
doOnload());
form.appendChild(input);
// ...
form.appendChild(input);
form.submit();
and submits the form at the end.
The function 'createInputElement(name, value)' creates an input DOM element with attributes name and value and returns the element. I tried to work with a callback, but i didn't get it to work / did something wrong. I have not much experience working with callbacks.
This is how the createInputElement function looks like:
this.createInputElement = function(name, value) {
var input = document.createElement("input");
input.name = name;
input.value = value;
return input;
}
Please only tips in js and not in jQuery, thanks.
So how can i send the Post after the onload event is finished and the data is written into the form element?
Thanks in advance!
Regards,
David
I've been messing around with a two forms and would like to combine them. Each form has a separate JS.
I'd like to be able to take the values in Form #1 and have them placed in the Form#2 answers.
Could somebody please assist?
Form #1
$(window).load(function(){
jQuery(function($) {
var multiTags = $("#multi");
function handler(e) {
var jqEl = $(e.currentTarget);
var tag = jqEl.parent();
switch (jqEl.attr("data-action")) {
case "add":
tag.after(tag.clone().find("input").val("").end());
break;
case "delete":
tag.remove();
break;
}
return false;
}
function save(e) {
var tags = multiTags.find("input.tag").map(function() {
return $(this).val();
}).get().join(',');
alert(tags);
return false;
}
multiTags.submit(save).find("a").live("click", handler);
});
});
</script>
Form #2
$(document).ready(function(){
$('.submit').click(function(){
var answers = [];
$.each($('.field'), function() {
answers.push($(this).val());
});
if(answers.length == 0) {
answers = "none";
}
alert(answers);
return false;
});
});
I'll make my comment an answer, and elaborate a little bit more.
I made a simple little fiddle that you can use as a jumping off point for this. Basically, it will grab all values of the inputs on the page and assign them to a variable. From there, your script could send that variable to your mailer script which processes everything...
var data = "";
$("input").each(function(index, element) {
data += $(this).val() + ", ";
});
alert(data);
The script looks for all <input> tags, and then gets the value from them via .val(). In your form, you'd run this on click, $("input[type=submit]").click(function(){ ... }); where the ... would be the code above. Obviously, you wouldn't want to alert what the user had typed into the box (they typed it, after all), so you'd then pass that variable on to your mailing script (I'd google on how to do this, as your mailer script is probably written in PHP, so google something like pass jQuery variable onto PHP).
Fiddle: http://jsfiddle.net/charlescarver/4AfTR/2/
Is there a way to group the inputs so that data only uses input boxes 1,2,3 (for example).
Yes, this line here...
$("input")
...finds all <input> tags on the page. If you only want <input> boxes 1,2 and 3 to have their value assigned to a variable, then give them a class and change "input" to ".classname". Ex.) $(".tag") will only assign <input> boxes with the class .tag to a variable (<input class="tag />).
I have a pretty simple HTML form where users can enter in information about a person. Below that form is a button which allows them to 'add more'. When clicked, the 'person' form is copied and appended to the page.
The way I used to do this was to take my HTML file, copy out the relevant section (the part that gets 'added more') and then save it into a variable in the Javascript. This became rather annoying when I had to make changes to the form as I would then have to make the same changes to the Javascript variable.
My new method is to create the variable dynamically in Javascript. When the page loads, I use jQuery to grab out the 'add more' part of the code and cache the HTML into a variable. Then when the 'add more' button is clicked, I append that cached HTML to the page.
The problem is with form inputs. The server-side code autofills the form with the user's data from the database. I want to cache that HTML data with no form inputs...
My current function looks like this:
function getHTML($obj, clean)
{
if (clean)
{
var $html = $obj.clone();
$html.find('input').each(function() { $(this)[0].value = ''; });
}
else
{
var $html = $obj;
}
var html = $html.wrap('<div></div>').parent()[0].innerHTML;
$html.unwrap();
return html;
}
It doesn't work. I'm also unsure if this is the best approach to solving the problem.
Any ideas?
I don't know why this wouldn't work. I can't see how the function is being called, or what is being passed to it.
I guess one thing I'd do differently would be to create a .clone() whether or not you're "cleaning" the inputs. Then you're not wrapping and unwrapping an element that is in the DOM. Just use the if() statement to decide whether or not to clean it.
Something like this:
function getHTML($obj, clean) {
var $clone = $obj.clone();
if (clean) {
$clone.find('input').each(function() { this.value = ''; });
}
return $clone.wrap('<div></div>').parent()[0].innerHTML;
}
Or a little more jQuery and less code:
function getHTML($obj) {
return $obj.clone().find('input').val('').end().wrap('<div/>').parent().html();
}
A little less efficient, but if it only runs once at the page load, then perhaps not a concern.
Or if it is going to be made into a jQuery object eventually anyway, why not just return that?
function getHTML($obj) {
return $obj.clone().find('input').val('').end();
}
Now you've returned a cleaned clone of the original that is ready to be inserted whenever you want.
EDIT:
Can't figure out right now why we can't get a new string.
Here's a function that will return the DOM elements. Beyond that, I'm stumped!
function getHTML($obj, clean) {
var $clone = $obj.clone();
if (clean) {
$clone.find('input').each(function() {
this.value = '';
});
}
return $clone.get(); // Return Array of DOM Elements
}
EDIT: Works now.
I ditched most of the jQuery, and used .setAttribute("value","") instead of this.value.
Give it a try:
function getHTML($obj, clean) {
var clone = $obj[0].cloneNode(true);
var inputs = clone.getElementsByTagName('input');
console.log(inputs);
for(var i = 0, len = inputs.length; i < len; i++) {
inputs[i].setAttribute('value','');
}
return $('<div></div>').append(clone)[0].innerHTML;
}
I would wrap the part of the form that needs to be cloned in a <fieldset>:
<form id="my_form">
<fieldset id="clone_1">
<input name="field_1_1">
<input name="field_2_1">
<input name="field_3_1">
</fieldset>
</form>
Add one more
Then for the jQuery script:
$("#fieldset_clone").click(function(event) {
// Get the number of current clones and set the new count ...
var cloneCount = parseInt($("fieldset[id^=clone_]").size());
var newCloneCount = cloneCount++;
// ... then create new clone based on the first fieldset ...
var newClone = $("#clone_1").clone();
// .. and do the cleanup, make sure it has
// unique IDs and name for server-side parsing
newClone.attr('id', 'clone_' + newCloneCount);
newClone.find("input[id^=clone_]").each(function() {
$(this).val('').attr('name', ($(this).attr('name').substr(0,7)) + newCloneCount);
});
// .. and finally insert it after the last fieldset
newClone.insertAfter("#clone_" + cloneCount);
event.preventDefault();
});
This would not only clone and clean the set of input fields, but it would also set new ID's and names so once the form is posted, their values would not be overwritten by the last set.
Also, in case you want to add the option of removing sets as well (one might add too many by mistake, or whatever other reason), having them wrapped in a <fieldset> that has an unique ID will help in accessing it and doing a .remove() on it.
Hope this helps.