How do I display multiple inputs? - javascript

const form = document.querySelector("#user-form");
const userInput = document.querySelector("#name", "#surname", "#age", "#country");
const userList = document.querySelector(".list-group");
const firstCardBody = document.querySelectorAll(".card-body")[0];
const secondCardBody = document.querySelectorAll(".card-body")[1];
const filter = document.querySelector("#filter");
const clearButton = document.querySelector("#clear-users");
<form id="user-form" name="form">
<div class="form-row">
<div class="form-group col-md-6">
<input class="form-control" type="text" name="name" id="name" placeholder="İsim">
</div>
<div class="form-group col-md-6">
<input class="form-control" type="text" name="surname" id="surname" placeholder="Soyadı">
</div>
<div class="form-group col-md-6">
<input class="form-control" type="text" name="age" id="age" placeholder="Yaş">
</div>
<div class="form-group col-md-6">
<input class="form-control" type="text" name="country" id="country" placeholder="Ülke">
</div>
</div>
<button type="submit" class="btn btn-primary">Bilgilerinizi Kaydedin</button>
</form>
My form looks like this.
But when I run my JS code, it only shows me the name not surname, age or country. How do I display all of them?
enter image description here

document.querySelector cannot be use the way you use it as it returns the first matched element (in your case the name input). To get all input fields you can do it like this:
const userInput = document.querySelectorAll(".form-control");
This returns all 4 input fields in an array which can be iterated via
userInput.forEach(input => { ... });
Get a specific element like this:
Array.from(userInput).find(input => input.id === "name");
Another approach would be to get the input fields via their ID's:
const name = document.querySelector("#name");
const surname= document.querySelector("#surname");
const age = document.querySelector("#age");
const country = document.querySelector("#country");

Related

How can I validate form fields using JavaScript in Multi-step HTML Form?

I'm working on registration form that has three sections. A user moves to the next section of the form when the button "Next" is clicked. Everything is working well except that validation errors are only showing on the last section of the Form. I would like to validate the form before moving to the next section. For now, when "Next" button is clicked, the user can move to the next section even without filling the fields. I'm not so experienced in JavaScript, please help.
HTML:
<section>
<div class="container">
<form>
<div class="step step-1 active">
<div class="form-group">
<label for="firstName">First Name</label>
<input type="text" id="firstName" name="first-name">
</div>
<div class="form-group">
<label for="lastName">Last Name</label>
<input type="text" id="lastName" name="last-name">
</div>
<div class="form-group">
<label for="nickName">Nick Name</label>
<input type="text" id="nickName" name="nick-name">
</div>
<button type="button" class="next-btn">Next</button>
</div>
<div class="step step-2">
<div class="form-group">
<label for="email">Email</label>
<input type="text" id="email" name="email">
</div>
<div class="form-group">
<label for="phone">Phone</label>
<input type="number" id="phone" name="phone-number">
</div>
<button type="button" class="previous-btn">Prev</button>
<button type="button" class="next-btn">Next</button>
</div>
<div class="step step-3">
<div class="form-group">
<label for="country">country</label>
<input type="text" id="country" name="country">
</div>
<div class="form-group">
<label for="city">City</label>
<input type="text" id="city" name="city">
</div>
<div class="form-group">
<label for="postCode">Post Code</label>
<input type="text" id="postCode" name="post-code">
</div>
<button type="button" class="previous-btn">Prev</button>
<button type="submit" class="submit-btn">Submit</button>
</div>
</form>
</div>
</section>
JavaScript:
const steps = Array.from(document.querySelectorAll("form .step"));
const nextBtn = document.querySelectorAll("form .next-btn");
const prevBtn = document.querySelectorAll("form .previous-btn");
const form = document.querySelector("form");
nextBtn.forEach((button) => {
button.addEventListener("click", () => {
changeStep("next");
});
});
prevBtn.forEach((button) => {
button.addEventListener("click", () => {
changeStep("prev");
});
});
form.addEventListener("submit", (e) => {
e.preventDefault();
const inputs = [];
form.querySelectorAll("input").forEach((input) => {
const { name, value } = input;
inputs.push({ name, value });
});
console.log(inputs);
form.reset();
});
function changeStep(btn) {
let index = 0;
const active = document.querySelector(".active");
index = steps.indexOf(active);
steps[index].classList.remove("active");
if (btn === "next") {
index++;
} else if (btn === "prev") {
index--;
}
steps[index].classList.add("active");
}
If you want to validate one section of the form before moving on to the next one you should do something like this:
nextBtn.forEach(button => {
button.addEventListener("click", () => {
handleEvent("next")
})
})
prevBtn.forEach(button => {
button.addEventListener("click", () => {
handleEvent("prev")
})
})
where handleEvent is:
function handleEvent(btn) {
if (!handleFormValidation(btn)) return "error message here";
changeStep(btn)
}
Here handleFormValidation would be a function that checks weather the input is correct and returns true if it is and false if it isn't
If you want to make sure the user fills in the first form first before going to the second you can do it by making the second form appear only after the next button is pressed, but that would require a major rework of your system. (i do however advise it because when i copied your code to test it i noticed quite a lot of bugs)
Here are some mdn articles describing how to make, delete and append elements using javascript:
making an element
removing an element
removing an element
appending an element to another element
appending an element to another element
I highly encourage you to do your own research as well.
I also just want to apologise if anything in my answer isn't understandable. I'm new at contributing to this community so there will likely be mistakes I've made.

How do I group inputs in Local storage to be one "Event" categorized by my Date time input

In my app I collect information from the user and store it in Local storage using javascript like this.
Event Name (1 to 20 characters):
<input type="text" id="eventname" name="eventname" required
minlength="1" maxlength="20" size="20">
<label for="datetime">Event Date and Time:</label>
<input type="datetime-local" id="date" name="date" required
minlength="1" maxlength="20" size="20">
<label for="eventlocation">Event Location (1 to 20 characters):</label>
<input type="text" id="location" name="location" required
minlength="1" maxlength="20" size="20">
<label for="notes">Notes (0 to 50 characters): </label>
<input type="text" id="notes" name="notes" required
minlength="0" maxlength="50" size="50">
<script src="app.js"></script>
I then have an app.js document which puts it into local storage
const locationTxt = document.querySelector('#location');
locationTxt.addEventListener('change', (event) => {
localStorage.setItem('location', event.target.value);
function getSavedData() {
console.log('location', localStorage.getItem('location'));
(except i have these fucntions for each of the inputs.)
How Would i go about taking all these inputs in locale storage and displaying it as 1 event that is able to be categorized by time?
One way would be to store event data in an object:
{
'01-02-1900': [
... // Array of events
],
'01-01-1900': [
... // Array of events
],
...
}
And then using JSON.parse and JSON.stringify to read/write to localStorage. 😊
For instance:
/**
* This override localStorage in Stack Snippet
*/
const customStorage = { data: {} };
customStorage.getItem = index => customStorage.data[index] || null;
customStorage.setItem = (index, payload) =>
(customStorage.data[index] = payload);
/**
* Replace customStorage with localStorage below.
*/
const inputs = document.querySelectorAll("input");
const storageIndex = "myTestStorage";
const storeInLocal = formData => {
const { date, event } = formData;
const toStore = JSON.parse(customStorage.getItem(storageIndex)) || {};
if (!toStore[date]) toStore[date] = [];
toStore[date].push(event);
customStorage.setItem(storageIndex, JSON.stringify(toStore));
};
const readForm = () => {
let values = {};
inputs.forEach(({ name, value }) => {
values[name] = value;
});
const { date, eventname, location, notes } = values;
return {
date,
event: {
eventname,
location,
notes
}
};
};
const outputStorage = () => {
const storage = customStorage.getItem(storageIndex) || "";
document.getElementById("output").innerText = storage;
};
document.getElementById("eventForm").addEventListener("submit", e => {
e.preventDefault();
const formData = readForm();
storeInLocal(formData);
outputStorage();
});
<!DOCTYPE html>
<html lang="en">
<head>
<title>Store form data in localStorage</title>
<link
href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css"
rel="stylesheet"
/>
<style>
pre {
white-space: pre-wrap;
}
</style>
</head>
<body>
<main id="app" role="main" class="container">
<form id="eventForm">
<div class="form-group row">
<label for="eventname">Event Name</label>
<div class="col-sm-6">
<input
type="text"
id="eventname"
name="eventname"
required
minlength="1"
maxlength="20"
/>
</div>
</div>
<div class="form-group row">
<label for="datetime">Event Date and Time:</label>
<div class="col-sm-6">
<input
type="datetime-local"
id="date"
name="date"
required
minlength="1"
maxlength="20"
/>
</div>
</div>
<div class="form-group row">
<label for="eventlocation">Event Location</label>
<div class="col-sm-6">
<input
type="text"
id="location"
name="location"
required
minlength="1"
maxlength="20"
/>
</div>
</div>
<div class="form-group row">
<label for="notes">Notes</label>
<div class="col-sm-6">
<input
type="text"
id="notes"
name="notes"
required
minlength="0"
maxlength="50"
/>
</div>
</div>
<button type="submit" class="btn btn-primary">Save</button>
</form>
<h1 class="h4">Output</h1>
<p>Hit "save" multiple times, and change the date occasionally.
<p>
<pre id="output"></pre>
</p>
</main>
</body>
</html>

How to dynamically add a required HTML element to a form using javascript?

In the form I am making, there is a section that requires users to enter the amount of people in their family. After they provide it, the form generates enough input fields so that the user can enter information for each family member.
What I am having trouble with is none of the attributes that I am trying to apply to the input element actually work.
function addHouseMembers(that){
var family = document.getElementById("family-input-container");
while(family.hasChildNodes()){
family.removeChild(family.lastChild);
}
for(var i = 1; i < that.value; i++){
family.appendChild(document.createTextNode("Family Member " + (i+1)));
family.appendChild(document.createElement("br"));
//name
family.appendChild(document.createTextNode("Name: " ));
var input = document.createElement("input");
input.type = "text";
input.name = "member" + i + "_name";
input.pattern = "/^[a-zA-Z ]*$/";
input.required = true;
family.appendChild(input);
family.appendChild(document.createElement("br"));
}
}
The parameter that refers to the input where the user would put in the number of people in their family.
And here is the relevant HTML:
<form>
<div class="form-group">
<label class="col-lg-3 control-label">What is the total amount of people living in your household?</label>
<div class="col-lg-3 inputGroupContainer">
<div class = "input-group">
<input type="text" class="form-control" name="household-size" required onchange="addHouseMembers(this);"/>
</div>
</div>
</div>
<div class="form-group", id="family-info">
<label class="col-lg-12">Information for other Family Members</label>
<div class="col-lg-3 inputGroupContainer">
<div class = "input-group" id = "family-input-container" required>
</div>
</div>
</div>
</form>
The element shows up as it should, and is submitted with the form when the user hits the submit button, but the regex pattern and required attributes are not enforced.
in addHouseMembers(that) the value of that is a string, not a number, and you have to check if is value can be 'translated' in an integer value.
use the "onchange" event on the input field household-size is not a good idea because this event is triggered each time a digit of the number entered, which has the effect of erasing and completely rewrite the family-input-container part
I Imagine you are looking for something like that ?
const myForm = document.getElementById('my-form')
, familyElm = document.getElementById('family-input-container')
, parserDOM = new DOMParser()
;
function newHouseMember(ref)
{
let div=
` <div>
Family Member ${ref}<br>Name: <br>
<input type="text" name="member${ref}_name" pattern="/^[a-zA-Z ]*$/" required >
</div>`
return parserDOM.parseFromString( div, 'text/html').body.firstChild
}
myForm.btPeoples.onclick=_=>
{
let nbPeoples = parseInt(myForm['household-size'].value)
if (!isNaN(nbPeoples) && nbPeoples > 0 )
{
familyElm.innerHTML = ''
for (let i=1; i<=nbPeoples; i++)
{
familyElm.appendChild( newHouseMember(i) )
}
}
}
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" rel="stylesheet" >
<form id="my-form">
<div class="form-group">
<label class="col-lg-3 control-label">What is the total amount of people living in your household?</label>
<div class="col-lg-3 inputGroupContainer">
<div class = "input-group">
<input class="form-control" name="household-size" required value="" placeholder="number of peoples" pattern="\d*" />
<button name="btPeoples" class="btn btn-info" type="button" >check it!</button>
</div>
</div>
</div>
<div class="form-group", id="family-info">
<label class="col-lg-12">Information for other Family Members</label>
<div class="col-lg-3 inputGroupContainer">
<div class="input-group" id="family-input-container">
</div>
</div>
</div>
</form>

Trying to implement closure on event handler? Error: undefined

I have trying to get the values out of a form when the register button is clicked.
setupFormUI() and the relevant form fields are saved in variables
$($rego_form).on("submit", getRegistrationFormValue); is called - a handler should be able to have access to setupFormUI() variables (closure) but it seems to not do anything
ISSUE: getRegistrationFormValue doesn't log anything. I can make it work if I pass arguments to the function... but I want to use
closure
setupFormUI();
function setupFormUI() {
var $name = $("#name");
var $age = $("#age");
var $department = $("#department");
var $position = $("#position");
var $rego_form = $("#rego-form");
$($rego_form).on("submit", getRegistrationFormValue);
}
function getRegistrationFormValue() {
// alert("asdasd");
var name = $name.val();
var age = $age.val();
var department = $department.val();
var position = $position.val();
console.log("----->", name, age, position, department);
}
html
<form id="rego-form">
<div class="row">
<div class="col-md-5">
<div class="form-group">
<label>Company (disabled)</label>
<input type="text" class="form-control" disabled placeholder="Company" value="Creative Code Inc.">
</div>
</div>
<div class="col-md-3">
<div class="form-group">
<label>name</label>
<input type="text" id="name" class="form-control" placeholder="name" value="michael">
</div>
</div>
<div class="col-md-4">
<div class="form-group">
<label for="exampleInputEmail1">Age</label>
<input id="age" class="form-control" placeholder="age">
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label>Department Name</label>
<input type="text" id="department" class="form-control" placeholder="department" value="Marketing">
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label>Position</label>
<input type="text" id="position" class="form-control" placeholder="position" value="social media manager">
</div>
</div>
</div>
<button type="submit" id="rego-user-btn" class="btn btn-info btn-fill pull-right">Register</button>
<div class="clearfix"></div>
</form>
You need the variables to be in scope, you can use an anonymous closure as a callback to achieve this.
setupFormUI();
function setupFormUI() {
var $name = $("#name");
var $age = $("#age");
var $department = $("#department");
var $position = $("#position");
var $rego_form = $("#rego-form");
$rego_form.on("submit", function(){
var name = $name.val();
var age = $age.val();
var department = $department.val();
var position = $position.val();
console.log("----->", name, age, position, department);
});
}
An alternative to the accepted answer — give the "handler" a meaningful context of this with Function.prototype.bind(), or maybe just use the ES6 class.
setupFormUI();
function setupFormUI() {
var args = {
$name: $("#name"),
$age: $("#age"),
$department: $("#department"),
$position: $("#position"),
$rego_form: $("#rego-form")
}
args.$rego_form.submit(getRegistrationFormValue.bind(args));
}
function getRegistrationFormValue(e) {
var name = this.$name.val();
var age = this.$age.val();
var department = this.$department.val();
var position = this.$position.val();
console.log("----->", name, age, position, department);
e.preventDefault();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form id="rego-form" action="#">
<input id="name" value="John Doe" />
<input id="age" value="37" />
<input id="department" value="Some dept" />
<input id="position" value="Debt collector" />
<button type="submit">Submit</button>
</form>
This is no closure, if the variable in setupFormUI is referenced, it is a closure.
getRegistrationFormValue is just a variable whose function is passed directly to the event trigger (and is asynchronous), note that it is not executed in setupFormUI, nor is it defined in setupFormUI, When it is executed, it has nothing to do with setupFormUI.
Mike Zinn's answer defines an anonymous function in setupFormUI, which in turn refers to the variable in setupFormUI, which is a closure.

PHP Not Recognizing Array in HTML Form "name" Attribute

I have a list of and fields where users enter the name of an item and the quantity. The PHP function
generateMaterialsTable();
is responsible for generating one text field and one number field if there are no existing records in the database. If there are multiples, the function shows all items and their corresponding quantities. Here is the PHP code:
function generateMaterialsTable($month_id, $table, $item, $addOrEdit){
global $mysqli;
$item_singular = substr($item, 0, strlen($item)-1);
$item_singular_title = $item_singular.'_title';
if($addOrEdit == 'Edit'){
$materials_query = "SELECT * FROM archivestats.".$table."_".$item." WHERE month_id = '$month_id'";
$materials_result = $mysqli->query($materials_query);
if($materials_result->num_rows > 0){
$counter = 1;
while($materials_match = $materials_result->fetch_assoc()){
$output .= '
<div class="form-group '.$item_singular.'-row row">
<div class="col-sm-8">
<input type="text" name="'.$item_singular.'[]" class="form-control item-field" value="'.htmlentities($materials_match[$item_singular_title]).'">
</div>
<div class="col-sm-4">
<input type="number" name="'.$item_singular.'qty[]" class="form-control align-right '.$item_singular.'qty" value="'.$materials_match['quantity'].'">
</div>
</div>
';
$counter++;
}
} else {
$output .= '
<div class="form-group '.$item_singular.'-row row">
<div class="col-sm-8">
<input type="text" name="'.$item_singular.'[]" class="form-control item-field" value="">
</div>
<div class="col-sm-4">
<input type="number" name="'.$item_singular.'qty[]" class="form-control align-right '.$item_singular.'qty" value="">
</div>
</div>
';
}
}
return $output;
}
The user also has the option to add a new text and quantity field. This is done via the following JQuery:
//WHEN USER CLICKS '+Add Another Field'
$('.new-field').click(function(){
var newFieldId = $(this).attr('id'); //find id of the '+Add Another Field' paragraph
var newField = newFieldId.substr(0, newFieldId.lastIndexOf('-')); //find the name of the field before the last - (eg. 'book' from 'book-new')
var fields = $(this).parents().siblings().closest('.'+newField+'-row').find('input[type="text"]');
var count = 0;
$(fields).each(function(){
//we only need to get information for the last text box in the bunch
if(count == fields.length-1){
var last_field = $(this).attr('name'); //the name attribute of the last text box
var field_name = last_field.substr(0, last_field.indexOf('[')); //find the name of the field before a _ (eg. 'book' from 'book_1')
var regEx = /\d+/; //find the number of the field contained in the name (eg. '1' from 'book_1')
var field_number = parseInt(last_field.match(regEx));
$(this).parent().parent().after('<div class="form-group '+ field_name +'-row row"> <div class="col-sm-8"><input type="text" name="'+ field_name +'[]" class="form-control item-field"></div><div class="col-sm-4 add-field"><input type="number" name="'+ field_name +'qty[]" class="form-control align-right ' + field_name + 'qty"></div></div>');
}
count++; //iterate our counter
});
}); //end .new-feild.click()
For whatever reason, when I go to submit the form, the array as defined in
name="'.$item_singular.'[]"
only works properly with one group of text fields - that is, it properly records all array items. For example, let's say I have the following:
<div class="form-group book-row row">
<div class="col-sm-8">
<input type="text" name="book[]" class="form-control item-field">
</div>
<div class="col-sm-4">
<input type="number" name="bookqty[]" class="form-control align-right bookqty">
</div>
</div>
</div>
<div class="form-group book-row row">
<div class="col-sm-8">
<input type="text" name="book[]" class="form-control item-field">
</div>
<div class="col-sm-4">
<input type="number" name="bookqty[]" class="form-control align-right bookqty">
</div>
</div>
For this, I will input values of EXAMPLE 1 / 4 and EXAMPLE 2 / 15. When I submit and do:
print_r($_POST['book'])
I get the proper value of
Array([0] => "Example 1", [1] => "Example 2")
But then in another section of that EXACT SAME FORM I do this:
<div class="form-group book-row row">
<div class="col-sm-8">
<input type="text" name="digbook[]" class="form-control item-field">
</div>
<div class="col-sm-4">
<input type="number" name="digbookqty[]" class="form-control align-right digbookqty">
</div>
</div>
</div>
<div class="form-group book-row row">
<div class="col-sm-8">
<input type="text" name="digbook[]" class="form-control item-field">
</div>
<div class="col-sm-4">
<input type="number" name="digbookqty[]" class="form-control align-right digbookqty">
</div>
</div>
</div>
For this, I will input values of EXAMPLE 3 / 1 and EXAMPLE 4 / 20. Now I'll get ONLY the first item in the array:
Array([0] => "Example 3")
This makes absolutely no sense and it is driving me crazy. It is the exact same function spitting out the exact same code with two completely different results. Unreal...

Categories