Edit - Updated JS code to display suggestions made in comments, still having issues.. Now the button <input id="edit" type="submit" value="Submit"> won't go to edit.html, instead it is returning action.html? It is nested inside of the editForm?
I have a simple form which I have managed to learn to submit, add, remove, and display bookings using the localStorage (thanks to those who helped on here!).
My last task is to amend a booking, I think I am almost there with it, but not sure how to call the indexes (excuse my jargon), to replace the values.
The form submits and the web address reads something like edit.html?OldFirstName=NewFirstName&OldLastName=NewLastName, however the values don't update in storage, and it throws an error saying
Uncaught TypeError: Cannot read property 'fname' of undefined`.
I expected this to happen as I know I am not finding the values correctly, but I can't figure out how I should be writing it out? My thought process was that it would be similar to the original submit function but with the [i] values for fname and lname?
Here's my JS code - if you need anything else from me let me know:
// ~~~ add bookings to localStorage
var bookings = localStorage.getItem("bookings");
$("#submit").click(function () {
bookings = (bookings) ? JSON.parse(bookings) : [];
var newBookings = {
fname: $('#fname').val(),
lname: $('#lname').val()
}
bookings.push(newBookings);
var json = JSON.stringify(bookings);
window.localStorage.setItem("bookings", json);
});
// ~~~ edit bookings in localStorage
$("#edit").click(function (e) {
e.preventDefault();
bookings = (bookings) ? JSON.parse(bookings) : [];
var parent_form = $('#editForm');
var fname = parent_form.find('.input:eq(0)').val();
var lname = parent_form.find('.input:eq(1)').val();
var newBookings = {
fname: fname,
lname: lname
}
bookings.push(newBookings);
var json = JSON.stringify(bookings);
window.localStorage.setItem("bookings", json);
});
// ~~~ display bookings in browser
function showBooking(i) {
var bookingResult = document.getElementById("result");
var ul = document.createElement("ul");
var bookingItems = JSON.parse(localStorage.getItem("bookings")) || [];
bookingResult.innerHTML = "";
for (let i = 0; i < bookingItems.length; i++) {
bookingResult.innerHTML += `<div class="card card-body bg-light m-4">
<h3>${bookingItems[i].fname + " " + bookingItems[i].lname}
<button onclick="deleteBooking(${i})" class="btn btn-danger text-light ">Delete</button>
<button onclick="editBooking(${i})" class="btn btn-danger text-light ">Edit</button>
</h3>
</div>`;
}
}
// ~~~ edit bookings in browser
function editBooking(i) {
var bookingResult = document.getElementById("editAppt");
var bookingItems = JSON.parse(localStorage.getItem("bookings")) || [];
bookingResult.innerHTML =
`<form id="editForm" name="editForm" onsubmit="return editForm(this)" class="col-sm-6">
<div class="row">
<input type="text" class="input" id="fname_${i}" placeholder="${bookingItems[i].fname}" name="${bookingItems[i].fname}" required>
<input type="text" id="lname_${i}" class="input" placeholder="${bookingItems[i].lname}" name="${bookingItems[i].lname}" required>
<input id="edit" type="submit" value="Submit">
</div>
</form>`;
}
// ~~~ delete bookings from localStorage
function deleteBooking(i){
var bookingItems = JSON.parse(localStorage.getItem("bookings"));
bookingItems.splice(i, 1);
localStorage.setItem("bookings", JSON.stringify(bookingItems));
showBooking();
}
// ~~~ form submit handlers
function setAction(form) {
form.action = "action.html";
}
function editForm(form) {
form.action = "edit.html";
}
I can see that the issue comes from this like :
$("#edit").click(function (i) {
You expect the click event to return an index but it's not, the i will represent the event object, so you may need to use $(this) to get the related inputs like :
$("#edit").click(function (e) {
var parent_form = $(this.form);
var fname = parent_form.find('.input:eq(0)').val();
var lname = parent_form.find('.input:eq(1)').val();
....
NOTE: The id must not be duplicated, so you need to avoid that, you may use prefix like:
<input type="text" class="input" id="fname_${i}" placeholder="${bookingItems[i].fname}" name="${bookingItems[i].fname}" required>
<input type="text" class="input" id="lname_${i}" placeholder="${bookingItems[i].lname}" name="${bookingItems[i].lname}" required>
I have a form with multiple checkboxes in it and when I click them, I want to add/remove the key-value pairs (name of the input + true/false) in one single cookie.
When I click on the checkboxes only the first pair gets shown in console.log.
This is what I ended up with so far:
HTML:
<form class="form">
<input class="input" name="expert_id_1" type="checkbox" />
<input class="input" name="expert_id_2" type="checkbox" />
<input class="input" name="expert_id_3" type="checkbox" />
<input class="input" name="expert_id_4" type="checkbox" />
</form>
JS:
function setCookie() {
var customObject = {};
var inputName = $('.input').attr('name');
customObject[inputName] = $('.input').prop('checked');
var jsonString = JSON.stringify(customObject);
document.cookie = 'cookieObject=' + jsonString;
console.log(jsonString);
}
function getCookie() {
var nameValueArray = document.cookie.split('=');
var customObject = JSON.parse(nameValueArray[1]);
$('.input').prop('checked') = customObject[inputName];
}
$('.input').each(function() {
$(this).on('click', function() {
if ($(this).is(':checked')) {
$(this).attr('value', 'true');
} else {
$(this).attr('value', 'false');
}
setCookie();
});
});
Your cookie is being overrided and it might only store the first checkbox info. Also to set the prop value, you have to pass it as a second parameter.
This should update the cookie when clicked and also be able to set the values from the cookie.
function updateCookie($input) {
var cookieObject = getCookieObject();
var inputName = $input.attr('name');
cookieObject[inputName] = $input.attr('value');
var jsonString = JSON.stringify(cookieObject);
document.cookie = 'cookieObject=' + jsonString;
console.log(jsonString);
}
function setFromCookie(){
var cookieObject = getCookieObject();
for(var inputName in cookieObject)
if(cookieObject.hasOwnProperty(inputName))
$(`.input[name="${inputName}"]`).prop('checked', cookieObject[inputName]);
}
function getCookieObject() {
var nameValueArray = document.cookie.split('=');
var cookieObject = {};
if(nameValueArray.length >= 2)
cookieObject = JSON.parse(nameValueArray[1]);
return cookieObject;
}
$('.input').each(function() {
var $this = $(this);
$this.on('click', function() {
$this.attr('value', String($this.is(':checked')))
updateCookie($this);
});
});
Although I would recomend you to use a URLSearchParams object to encode and decode the parameters, since you are relying on the fact that "=" is not inside the JSON string.
I tried to create a Javascript List with an Input Field to add new Names. My Goal is it to have a name list where i can add new ones. I want also to not add a value if the input field is empty.
My current Problem is that if i add a new name and i press the button all the already created names are added once again.
I dont know why! I am fairly new to Javascript and Jquery.
var names = ['Peter', 'Thomas', 'Nick', 'James'];
var x = 1;
$(document).ready(function() {
function display_array() {
$.each(names, function(index, value) {
$('#names').append(value + '<br />');
});
}
display_array();
$('#insert').click(function() {
var name = document.getElementById('name');
if(name != ''){
name[x] = name;
display_array();
}
x = x + 1;
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input id="name" type="text">
<input id="insert" type="button" value='Insert new Name'>
<div id="names"></div>
const names = ['Peter', 'Thomas', 'Nick', 'James'];
function display_array() {
$('#names').empty(); // Clear list before rendering
$.each(names, function(index, value) {
$('#names').append(value + '<br />');
});
}
$(document).ready(function() {
display_array();
$('#insert').click(function() {
const name = document.getElementById('name').value; // Get value of input field
if(name != ''){
names.push(name); // Push to names list
display_array(); // Re-render list
}
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input id="name" type="text">
<input id="insert" type="button" value='Insert new Name'>
<div id="names"></div>
it is because you always append values
you should stick either to javascript or jquery. your code is a mixture between the two and this might puzzle you.
var names = ['Peter', 'Thomas', 'Nick', 'James'];
var x = 1;
$(document).ready(function() {
function display_array() {
$('#names').html(names.join('<br/>'));
}
display_array();
$('#insert').click(function() {
var name = $('#name');
if(name !== ''){
names.push(name.val());
display_array();
}
});
});
Your code does not work for three reasons:
You have to clear the shown namelist on display_array() using $('#names').empty();, otherwise you will add the whole list again and again
With var name = document.getElementById('name') you're setting a DOM-element to name. But you need the value of it. For this you can use document.getElementById('name').value; or with jQuerys $('#name').val();
They way you want to push the new name into the array will not work. Use names.push(name) instead
I think codecademy could be interesting for you, to get in touch with the JavaScript basics. Its really cool and for free. :)
var names = ['Peter', 'Thomas', 'Nick', 'James'];
$(document).ready(function() {
function display_array() {
$('#names').empty();
$.each(names, function(index, value) {
$('#names').append(value + '<br />');
});
}
display_array();
$('#insert').click(function() {
var name = $('#name').val();
if(name != ''){
names.push(name);
display_array();
}
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input id="name" type="text">
<input id="insert" type="button" value='Insert new Name'>
<div id="names"></div>
I'm willing to use two textfields to pass on values via url.
Here are my textfields:
<h3 class="title1">Email</h3>
<input type="text" id="myTextField1" />
<br/><br/>
<h3 class="title2">Secret</h3>
<input type="text" id="myTextField2" />
<br/><br/>
There's a link below them:
<a id="myLink" href="index2.php"></a>
Then there's a function I use, which should create something like:
index2.php?email=value1&secret=value2
However what I am getting is:
index2.php?email=value1, secret=value1&email=value2, secret=value2
This is the function I use:
document.querySelector('#myBtn').addEventListener('click', function change() {
function isInvalid(input) {
return input.value.length == 0;
}
var inputs = [...document.querySelectorAll('[id^="myTextField"]')];
var anchor = document.getElementById('myLink');
var querystring = inputs.map((input) => {
// Remove all leading non-digits to get the number //ex bladiebla1 = 1
var number = input.id.replace( /^\D+/g, '');
var titles = [...document.querySelectorAll('.title'+ number)];
titles.forEach((title) => title.innerHTML = input.value);
return `email=${input.value}`+` secret=${input.value}`;
});
anchor.href = `index2.php?${querystring.join('&')}`;
document.getElementById('result').innerHTML = querystring;
});
I realize that it is wrong and I get why this doesn't return what I want however I do not know how to fix this..
Could anybody tweek my code and point me in the right direction?
You're overcomplicating things here a bit.
You have the inputs in the inputs variable. If they had a name attribute in the html you can simply map over them and get the values out.
You don't really need the bit where you parse the number from the ID.
document.querySelector('#myBtn').addEventListener('click', function change() {
function isInvalid(input) {
return input.value.length == 0;
}
var inputs = [...document.querySelectorAll('[id^="myTextField"]')];
var anchor = document.getElementById('myLink');
var querystring = inputs.map((input) => {
return `${input.name}=${input.value}`;
});
anchor.href = `index2.php?${querystring.join('&')}`;
document.getElementById('result').innerHTML = querystring.join('&');
});
<h3 class="title1">Email</h3>
<input type="text" name="email" id="myTextField1" />
<br/><br/>
<h3 class="title2">Secret</h3>
<input type="text" name="secret" id="myTextField2" />
<br/><br/>
<button id=myBtn>Run the function</button>
<a id=myLink>Target Link</a>
<h3>Results:</h3>
<div id=result></div>
You iterate through each input and set email and secret for each of two inputs. Just add check for id. Something like return number === 1 ? email=${input.value} : &secret=${input.value};
I have a form with many input fields.
When I catch the submit form event with jQuery, is it possible to get all the input fields of that form in an associative array?
$('#myForm').submit(function() {
// get all the inputs into an array.
var $inputs = $('#myForm :input');
// not sure if you wanted this, but I thought I'd add it.
// get an associative array of just the values.
var values = {};
$inputs.each(function() {
values[this.name] = $(this).val();
});
});
Thanks to the tip from Simon_Weaver, here is another way you could do it, using serializeArray:
var values = {};
$.each($('#myForm').serializeArray(), function(i, field) {
values[field.name] = field.value;
});
Note that this snippet will fail on <select multiple> elements.
It appears that the new HTML 5 form inputs don't work with serializeArray in jQuery version 1.3. This works in version 1.4+
Late to the party on this question, but this is even easier:
$('#myForm').submit(function() {
// Get all the forms elements and their values in one step
var values = $(this).serialize();
});
The jquery.form plugin may help with what others are looking for that end up on this question. I'm not sure if it directly does what you want or not.
There is also the serializeArray function.
Sometimes I find getting one at a time is more useful. For that, there's this:
var input_name = "firstname";
var input = $("#form_id :input[name='"+input_name+"']");
$('#myForm').bind('submit', function () {
var elements = this.elements;
});
The elements variable will contain all the inputs, selects, textareas and fieldsets within the form.
Here is another solution, this way you can fetch all data about the form and use it in a serverside call or something.
$('.form').on('submit', function( e )){
var form = $( this ), // this will resolve to the form submitted
action = form.attr( 'action' ),
type = form.attr( 'method' ),
data = {};
// Make sure you use the 'name' field on the inputs you want to grab.
form.find( '[name]' ).each( function( i , v ){
var input = $( this ), // resolves to current input element.
name = input.attr( 'name' ),
value = input.val();
data[name] = value;
});
// Code which makes use of 'data'.
e.preventDefault();
}
You can then use this with ajax calls:
function sendRequest(action, type, data) {
$.ajax({
url: action,
type: type,
data: data
})
.done(function( returnedHtml ) {
$( "#responseDiv" ).append( returnedHtml );
})
.fail(function() {
$( "#responseDiv" ).append( "This failed" );
});
}
Hope this is of any use for any of you :)
http://api.jquery.com/serializearray/
$('#form').on('submit', function() {
var data = $(this).serializeArray();
});
This can also be done without jQuery using the XMLHttpRequest Level 2 FormData object
http://www.w3.org/TR/2010/WD-XMLHttpRequest2-20100907/#the-formdata-interface
var data = new FormData([form])
Had a similar issue with a slight twist and I thought I'd throw this out. I have a callback function that gets the form so I had a form object already and couldn't easy variants on $('form:input'). Instead I came up with:
var dataValues = {};
form.find('input').each(
function(unusedIndex, child) {
dataValues[child.name] = child.value;
});
Its similar but not identical situation, but I found this thread very useful and thought I'd tuck this on the end and hope someone else found it useful.
This piece of code will work
instead of name, email enter your form fields name
$(document).ready(function(){
$("#form_id").submit(function(event){
event.preventDefault();
var name = $("input[name='name']",this).val();
var email = $("input[name='email']",this).val();
});
});
Associative? Not without some work, but you can use generic selectors:
var items = new Array();
$('#form_id:input').each(function (el) {
items[el.name] = el;
});
jQuery's serializeArray does not include disabled fields, so if you need those too, try:
var data = {};
$('form.my-form').find('input, textarea, select').each(function(i, field) {
data[field.name] = field.value;
});
Don't forget the checkboxes and radio buttons -
var inputs = $("#myForm :input");
var obj = $.map(inputs, function(n, i) {
var o = {};
if (n.type == "radio" || n.type == "checkbox")
o[n.id] = $(n).attr("checked");
else
o[n.id] = $(n).val();
return o;
});
return obj
Seems strange that nobody has upvoted or proposed a concise solution to getting list data. Hardly any forms are going to be single-dimension objects.
The downside of this solution is, of course, that your singleton objects are going to have to be accessed at the [0] index. But IMO that's way better than using one of the dozen-line mapping solutions.
var formData = $('#formId').serializeArray().reduce(function (obj, item) {
if (obj[item.name] == null) {
obj[item.name] = [];
}
obj[item.name].push(item.value);
return obj;
}, {});
$("#form-id").submit(function (e) {
e.preventDefault();
inputs={};
input_serialized = $(this).serializeArray();
input_serialized.forEach(field => {
inputs[field.name] = field.value;
})
console.log(inputs)
});
I had the same problem and solved it in a different way.
var arr = new Array();
$(':input').each(function() {
arr.push($(this).val());
});
arr;
It returns the value of all input fields. You could change the $(':input') to be more specific.
Same solution as given by nickf, but with array input names taken into account
eg
<input type="text" name="array[]" />
values = {};
$("#something :input").each(function() {
if (this.name.search(/\[\]/) > 0) //search for [] in name
{
if (typeof values[this.name] != "undefined") {
values[this.name] = values[this.name].concat([$(this).val()])
} else {
values[this.name] = [$(this).val()];
}
} else {
values[this.name] = $(this).val();
}
});
I hope this is helpful, as well as easiest one.
$("#form").submit(function (e) {
e.preventDefault();
input_values = $(this).serializeArray();
});
If you need to get multiple values from inputs and you're using []'s to define the inputs with multiple values, you can use the following:
$('#contentform').find('input, textarea, select').each(function(x, field) {
if (field.name) {
if (field.name.indexOf('[]')>0) {
if (!$.isArray(data[field.name])) {
data[field.name]=new Array();
}
data[field.name].push(field.value);
} else {
data[field.name]=field.value;
}
}
});
Inspired by answers of Lance Rushing and Simon_Weaver, this is my favourite solution.
$('#myForm').submit( function( event ) {
var values = $(this).serializeArray();
// In my case, I need to fetch these data before custom actions
event.preventDefault();
});
The output is an array of objects, e.g.
[{name: "start-time", value: "11:01"}, {name: "end-time", value: "11:11"}]
With the code below,
var inputs = {};
$.each(values, function(k, v){
inputs[v.name]= v.value;
});
its final output would be
{"start-time":"11:01", "end-time":"11:01"}
I am using this code without each loop:
$('.subscribe-form').submit(function(e){
var arr=$(this).serializeArray();
var values={};
for(i in arr){values[arr[i]['name']]=arr[i]['value']}
console.log(values);
return false;
});
For multiple select elements (<select multiple="multiple">), I modified the solution from #Jason Norwood-Young to get it working.
The answer (as posted) only takes the value from the first element that was selected, not all of them. It also didn't initialize or return data, the former throwing a JavaScript error.
Here is the new version:
function _get_values(form) {
let data = {};
$(form).find('input, textarea, select').each(function(x, field) {
if (field.name) {
if (field.name.indexOf('[]') > 0) {
if (!$.isArray(data[field.name])) {
data[field.name] = new Array();
}
for (let i = 0; i < field.selectedOptions.length; i++) {
data[field.name].push(field.selectedOptions[i].value);
}
} else {
data[field.name] = field.value;
}
}
});
return data
}
Usage:
_get_values($('#form'))
Note: You just need to ensure that the name of your select has [] appended to the end of it, for example:
<select name="favorite_colors[]" multiple="multiple">
<option value="red">Red</option>
<option value="green">Green</option>
<option value="blue">Blue</option>
</select>
When I needed to do an ajax call with all the form fields, I had problems with the :input selector returning all checkboxes whether or not they were checked. I added a new selector to just get the submit-able form elements:
$.extend($.expr[':'],{
submitable: function(a){
if($(a).is(':checkbox:not(:checked)'))
{
return false;
}
else if($(a).is(':input'))
{
return true;
}
else
{
return false;
}
}
});
usage:
$('#form_id :submitable');
I've not tested it with multiple select boxes yet though but It works for getting all the form fields in the way a standard submit would.
I used this when customising the product options on an OpenCart site to include checkboxes and text fields as well as the standard select box type.
serialize() is the best method. # Christopher Parker say that Nickf's anwser accomplishes more, however it does not take into account that the form may contain textarea and select menus. It is far better to use serialize() and then manipulate that as you need to. Data from serialize() can be used in either an Ajax post or get, so there is no issue there.
Hope this helps somebody. :)
// This html:
// <form id="someCoolForm">
// <input type="text" class="form-control" name="username" value="...." />
//
// <input type="text" class="form-control" name="profile.first_name" value="...." />
// <input type="text" class="form-control" name="profile.last_name" value="...." />
//
// <input type="text" class="form-control" name="emails[]" value="..." />
// <input type="text" class="form-control" name="emails[]" value=".." />
// <input type="text" class="form-control" name="emails[]" value="." />
// </form>
//
// With this js:
//
// var form1 = parseForm($('#someCoolForm'));
// console.log(form1);
//
// Will output something like:
// {
// username: "test2"
// emails:
// 0: ".#....com"
// 1: "...#........com"
// profile: Object
// first_name: "..."
// last_name: "..."
// }
//
// So, function below:
var parseForm = function (form) {
var formdata = form.serializeArray();
var data = {};
_.each(formdata, function (element) {
var value = _.values(element);
// Parsing field arrays.
if (value[0].indexOf('[]') > 0) {
var key = value[0].replace('[]', '');
if (!data[key])
data[key] = [];
data[value[0].replace('[]', '')].push(value[1]);
} else
// Parsing nested objects.
if (value[0].indexOf('.') > 0) {
var parent = value[0].substring(0, value[0].indexOf("."));
var child = value[0].substring(value[0].lastIndexOf(".") + 1);
if (!data[parent])
data[parent] = {};
data[parent][child] = value[1];
} else {
data[value[0]] = value[1];
}
});
return data;
};
All answers are good, but if there's a field that you like to ignore in that function? Easy, give the field a property, for example ignore_this:
<input type="text" name="some_name" ignore_this>
And in your Serialize Function:
if(!$(name).prop('ignorar')){
do_your_thing;
}
That's the way you ignore some fields.
Try the following code:
jQuery("#form").serializeArray().filter(obje =>
obje.value!='').map(aobj=>aobj.name+"="+aobj.value).join("&")