Find and compare input value with JSON data - javascript

I'm trying to compare user input value with JSON data.
I found some questions similar to this one, but it didn't solve my problem.
This is my code, do you know why it doesn't work.
Javascript
fetch('js/countries.json')
.then(res => res.json())
.then(data => {
function checkCountry() {
let input = document.getElementById("countryInput").value;
let country = data.find(check => check.country === "Norway");
let text;
if (input === data[country]) {
text = "Yes";
} else {
text = "No";
}
document.getElementById("alert").innerHTML = text;
}
document.getElementById("check").addEventListener("click", checkCountry);
console.log(data);
})
JSON
[{"country":"USA","active":true},
{"country":"Spain","active":true},
{"country":"Norway","active":true}]
HTML
<form action="">
<div class="input-container">
<input id="countryInput" type="text" placeholder="Country">
<i class="fas fa-search"></i>
</div>
<button id="check" type="button">CHECK</button>
</form>

This line is not good: if (input === data[country]) {
you have to check with the same mechanism as you have checked for country above...
let inputCountry = data.find(check => check.country === input);
Like this:
const data = [{"country":"USA","active":true},
{"country":"Spain","active":true},
{"country":"Norway","active":true}];
document.getElementById("check").addEventListener("click", checkCountry);
function checkCountry() {
let input = document.getElementById("countryInput").value;
let country = data.find(check => check.country === "Norway");
let inputCountry = data.find(check => check.country === input);
let text;
// You have to check with the country
if (inputCountry && input === inputCountry.country) {
text = "Yes";
} else {
text = "No";
}
console.log(text);
}
<form action="">
<div class="input-container">
<input id="countryInput" type="text" placeholder="Country">
<i class="fas fa-search"></i>
</div>
<button id="check" type="button">CHECK</button>
</form>

You can't use data[country] because data isn't key value pair collection.
It consists of objects.
Try to change resulting json from {'country': 'Spain', 'active': true}, ... to
'Spain': {active: true}, ...
Or call data element via:
if (input === data.find(el => el.country == country)) {
text = "Yes";
} else {
text = "No";
}

Related

ToDo List. Delete task button

I am trying to build todo list and I like to put on button(.cancel-task) action which remove exactly item which connected with that button, but when I try to put addEventListener I meet error like "its not a function". Please explain me how to make it with using attribute id which I add before for tasks and also how to remove this item from local storage. Thank you, for your attention.
const taskList = document.querySelector(".todo_tasks-wrapper");
const formTodo = document.querySelector(".control");
const inputTask = document.querySelector(".todo_input");
const btnDeleteTask = document.querySelectorAll(".cancel-task");
const taskKeeper = [];
let taskIdCounter = 0;
const data = JSON.parse(localStorage.getItem("tasks"));
const updateHtml = (taskObj) => {
const newLi = document.createElement("li");
newLi.innerHTML = `<li id="${taskObj.id}" class="item-task">
<span>${taskObj.task}</span>
<button class="cancel-task">
<img src="assets/todo-cancel.png" alt="Cancel">
</button>
</li>`;
taskList.append(newLi);
}
const newTask = (info) => {
taskIdCounter += 1;
const taskObj = {
task: info,
id: taskIdCounter,
};
taskKeeper.push(taskObj);
localStorage.setItem("tasks", JSON.stringify(taskKeeper));
updateHtml(taskObj);
};
formTodo.addEventListener("submit", event => {
event.preventDefault();
const info = inputTask.value.trim();
if(info.length !== 0) {
newTask(info);
inputTask.value = "";
inputTask.focus();
}
});
if(data !== null) {
for(let item of data) {
updateHtml(item);
}
}
<div class="todo_wrapper">
<ul class="todo_tasks-wrapper">
</ul>
<form class="control" action="">
<label class="todo_label-form" for="task">
<input class="todo_input" id="task" type="text" placeholder="Enter new task" maxlength="30">
<input class="todo_submit" type="submit" value="+">
</label>
</form>
</div>
You can use a onclick listener on the todo_tasks-wrapper element and check every element inside the event path to match the criterias.
Example:
todoTaskWrapper.addEventListener("click", (event) => {
for (let el of event.composedPath()) {
// window and document have no matches function, but they are included in the path
if (el.matches && el.matches("button.cancel-task")) {
console.log(el, "is the button clicked")
console.log(el.parentNode, "is the li element");
// remove it
el.parentNode.remove();
}
}
});
MDN: Event.composedPath()
MDN: Element.matches()

Multi-step form won't go to next section JS/HTML

So I wrote this multi-step form and it worked with the current code I have listed below until I changed it to send/receive data from php. The only thing that works is updating the progress bar but other then that it doesn't work. I have an idea why its not working cause of the actual button event isn't targeting the correct $(this).parent(); when I changed it from nextSection() to onSubmit(). I would possibly like to write it where it just selects the div class from an object then remove the current section but I wanna keep it the way I have for now.
$(".btn").on("click", nextSection);
function nextSection() {
if (typeof sections[current] !== "undefined") {
if(valid) {
current_section = $(this).parent();
next_section = $(this).parent().next();
console.log(current_section)
next_section.fadeIn();
current_section.remove();
current++;
updateProgressbar();
if (current === 1) {
let username = $(".username").val();
updatePenguinObj("username", username);
} else if (current === 2) {
let password = $(".password").val();
let email = $(".email").val();
updatePenguinObj("password", password);
updatePenguinObj("email", email);
} else if (current === 3) {
let name = $(".done");
name.text(name.text().replace(/%.+?%/, userData.username));
}
}
}
}
Then I changed it to the onSubmit() function w/ the validation responses.
$(".btn").on("click", onSubmit);
function onSubmit(event) {
event.preventDefault()
let request = new XMLHttpRequest()
request.onreadystatechange = () => handleResponse(request)
let formData = new FormData()
formData.append('username', userData.username);
formData.append('color', userData.colorId);
formData.append('password', userData.password);
formData.append('email', userData.email);
request.open('POST', 'scripts/php/create.php')
request.send(formData)
}
function handleResponse(request) {
if (request.readyState !== XMLHttpRequest.DONE || request.status !== 200) {
return
}
let response = JSON.parse(request.responseText);
if (!response) {
return
}
sectionValidation(response);
}
function sectionValidation(response) {
valid = true;
let section = $(sections[current]);
let input = section.find("input");
input.each(function() {
let inputs = $(this).attr('type') === "checkbox" ? !$(this).is(':checked') : input;
if(inputs) {
if (!response.valid) {
showError(response.message);
return valid = response.valid;
}
}
});
if(valid) {
nextSection(); //This is where nextSection is excuted to go to next page but doesnt.
}
}
I pastebin the entire code for each file type that way im not spamming this thread with just code. Overall i'm just trying to figure out how to fix it where I can go to the next section.
HTML - https://pastebin.com/eF8eXBfN
JS - https://pastebin.com/LuvYtYFc
PHP -
Basically just returns a JSON Object {message: "Test", valid: false} for the message responses and validation for it to go to next section.
if this isn't helpful I apologise in advance ....
because nextSection(); uses $(this) it won't have refrance to the button as it would have done when you used $(".btn").on("click", nextSection);
so you could add a reference of $(this) though to that function from the onSubmit
I create an example using your code, I dummy the response from the php but the rest is the same: https://jsfiddle.net/PatrickHume/8x6rodpn/
I don't know if this is better but it's another approach, I hope its helpful
let valid = true;
let sections = {
0: ".rules-section",
1: ".color-section",
2: ".info-section",
3: ".done-section"
};
let userData;
let current = 0,
current_section, next_section;
let currPalleteId = 0;
let penguinColors = {
"Blue": "003366",
"Green": "009900",
"Pink": "FF3399",
"Black": "333333",
"Red": "CC0000",
"Orange": "FF6600",
"Yellow": "FFCC00",
"Purple": "660099",
"Brown": "996600",
"Peach": "FF6666",
"Dark Green": "006600",
"Light Blue": "0099CC",
"Lime Green": "8AE302",
"Sensei Gray": "93A0A4",
"Aqua": "02A797",
"Arctic White": "F0F0D8",
};
window.onload = function() {
initalizeCreate();
};
function initalizeCreate() {
loadPalletes();
createPenguinObj();
$(".btn").on("click", onSubmit);
$(".show-password").on("click", togglePassword);
$("#startAgain").on("click", resetForm);
$(".random-username").on("click", randomUsername);
$(".username").keyup(function() {
let username = this.value;
updateDollName(username);
});
}
async function randomUsername() {
let url = "https://randomuser.me/api/";
let obj = await (await fetch(url)).json();
obj = obj.results[0];
let randuser = obj.login.username
$(".username").val(randuser);
updateDollName(randuser);
}
function updateDollName(username) {
username === "" ? $(".penguinName").text("Penguin Name") : $(".penguinName").text(username);
}
function togglePassword() {
$(this).toggleClass("fa-eye fa-eye-slash");
let input = $(this).prev('.info-section input');
input.attr('type', input.attr('type') === 'password' ? 'text' : 'password');
}
function resetForm() {
location.reload()
}
function nextSection($this) {
if (typeof sections[current] !== "undefined") {
if (valid) {
current_section = $($this).parent();
next_section = $($this).parent().next();
// console.log(current_section)
next_section.fadeIn();
current_section.remove();
current++;
updateProgressbar();
if (current === 1) {
let username = $(".username").val();
updatePenguinObj("username", username);
} else if (current === 2) {
let password = $(".password").val();
let email = $(".email").val();
updatePenguinObj("password", password);
updatePenguinObj("email", email);
} else if (current === 3) {
let name = $(".done");
name.text(name.text().replace(/%.+?%/, userData.username));
}
}
}
}
function onSubmit(event) {
event.preventDefault()
let request = new XMLHttpRequest()
request.onreadystatechange = () => handleResponse(request, $(this))
let formData = new FormData()
formData.append('username', userData.username);
formData.append('color', userData.colorId);
formData.append('password', userData.password);
formData.append('email', userData.email);
request.open('POST', 'https://reqbin.com/sample/post/json')
request.send(formData)
}
function handleResponse(request, $this) {
if (request.readyState !== XMLHttpRequest.DONE || request.status !== 200) {
return
}
var resp = `{
"message": "Test",
"valid": true
}`
let response = JSON.parse(resp);
if (!response) {
return
}
sectionValidation(response, $this);
}
function sectionValidation(response, $this) {
valid = true;
let section = $(sections[current]);
let input = section.find("input");
input.each(function() {
let inputs = $(this).attr('type') === "checkbox" ? !$(this).is(':checked') : input;
if (inputs) {
if (!response.valid) {
showError(response.message);
return valid = response.valid;
}
}
});
if (valid) {
nextSection($this);
}
}
function showError(text) {
$("#c_container").append(`<div class="error-block-container"><div class="error-container"><div id="error-content"><div id="error-msg-txt"> %text% </div><div id="error-btn"><div id="error-txt">Ok</div></div></div></div></div>`);
$("#error-btn").on("click", () => {
closeError();
});
let message = $("#error-msg-txt").html(text);
message.text(message.text().replace(/%.+?%/, message));
$(".error-block-container").fadeIn();
}
function closeError() {
$(".error-block-container").remove();
}
function updateProgressbar() {
let progressSteps = document.querySelectorAll(".progress-step");
progressSteps.forEach((progressStep, id) => {
if (id < current + 1) {
progressStep.classList.add("progress-step-active");
progressStep.classList.add("step");
} else {
progressStep.classList.remove("progress-step-active");
progressStep.classList.remove("step");
}
});
progressSteps.forEach((progressStep, id) => {
if (id < current) {
progressStep.classList.add("progress-step-check");
progressStep.classList.remove("progress-step-active");
} else {
progressStep.classList.remove("progress-step-check");
}
});
let progressActive = document.querySelectorAll(".step");
$(".progress").css("width", ((progressActive.length - 1) / (progressSteps.length - 1)) * 100 + "%");
}
function loadPalletes() {
let colorIndexNum = 0;
for (let palletes in penguinColors) {
let colorHex = penguinColors[palletes],
colorIndex = palletes,
colorIndexCurrNum = ++colorIndexNum;
$("#palletes").append(`<div data-id="${colorIndexCurrNum}" class="tinyPallete" style="background: #${colorHex}"></div> `);
}
$("#palletes").on("click", function(e) {
currPalleteId = $(e.target).attr("data-id");
e.currentTarget.querySelector(".active").classList.remove("active");
if (e.target.classList.contains("tinyPallete")) {
e.target.classList.add("active");
}
$(".doll").css("background-color", "#" + penguinColorByIndex(currPalleteId, false));
});
}
function penguinColorByIndex(index, keys) {
if (keys) {
return Object.keys(penguinColors)[--index];
}
return Object.values(penguinColors)[--index];
}
function updatePenguinObj(key, value) {
userData[key] = value;
return userData;
}
function createPenguinObj() {
userData = new Object();
userData.username = "";
userData.colorId = Number(currPalleteId);
userData.password = "";
userData.email = "";
return userData;
}
<html>
<head>
<title>Create Account</title>
<link type="text/css" rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.css" />
<link type="text/css" rel="stylesheet" href="styles/fonts.css" />
<link type="text/css" rel="stylesheet" href="styles/create.css" />
<script type="text/javascript" src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.16.0/jquery.validate.min.js"></script>
</head>
<body>
<div id="c_header">
<h2>Create a Free Account</h2>
<div id="startAgain">Start Again</div>
<div class="c_progressBar">
<div class="progress" id="progress"></div>
<div class="progress-step progress-step-active"></div>
<div class="progress-step"></div>
<div class="progress-step"></div>
<div class="progress-step"></div>
</div>
</div>
<div id="c_container">
<div id="c_content">
<img id="logo" src="images/logo.png" /><img id="safety" src="images/safety.png" />
<form method="POST">
<div class="rules-section">
<div class="grid-rules">
<div class="item">
<div>
<div id="rule-title">Respect other penguins</div>
Club Penguin does not tolerate any swearing, bullying or mean behavior toward other penguins. Disciplinary action will be taken should any one of these occur while playing.
</div>
<img id="rule-image" src="images/respect.png" />
</div>
<div class="item">
<div>
<div id="rule-title">No inappropriate talk</div>
References to drugs and alcohol related activities, and sexual, racial or otherwise inappropriate talk are not permitted.
</div>
<img id="rule-image" src="images/inapp.png" />
</div>
<div class="item">
<div>
<div id="rule-title">Never reveal personal information</div>
The best way to stay safe online is to NEVER share your real name, phone number, address, email or passwords.
</div>
<img id="rule-image" src="images/personal.png" />
</div>
<div class="item">
<div>
<div id="rule-title">No cheating</div>
Use of third party programs to cheat is prohibited. Players who use any third party programs while playing risk being permanently banned.
</div>
<img id="rule-image" src="images/cheating.png" />
</div>
</div>
<hr />
<div id="agree"> <span class="toggle">
<input type="checkbox" id="agree" name="agree" /><label>I agree to the Club Penguin Rules.</label>
</span>
</div>
<div id="terms"> <span class="toggle">
<input type="checkbox" id="terms" name="terms" /><label>I agree to the <a id="hyper" href="#">Terms of Use</a></label>
</span>
</div>
<button class="btn" name="submit">Continue</button>
</div>
<div class="color-section">
<div id="color-form">
<p id="epname">Enter Your Penguin Name:</p>
<!--<span class="bubble">
<div id="bubble-msg"></div>
</span>-->
<input type="text" name="username" class="username" id="inputaligncenter" maxlength="16" /> <span toggle="#random_username" class="fa fa-fw fa-refresh random-username" title="Random Username"></span>
<div id="cpsmall">Minimum 4 characters: use only numbers, letters and spaces.</div>
<p id="cpname">Click on a Color:</p>
<div id="palletes"></div>
<img id="paintbucket" src="images/paintbucket.png" />
</div>
<div class="doll-container"> <img class="doll" src="images/doll.png" /> <span class="penguinName">Penguin Name</span> </div>
<button class="btn" name="submit">Continue</button>
</div>
<div class="info-section">
<div id="info-form">
<div id="ppname-wrapper">
Penguin Password:
<div id="ppsmall">This is the password you will use to login to Club Penguin. </div>
<input type="password" name="password" class="password" placeholder="Password"><span toggle="#password" class="fa fa-fw fa-eye field_icon show-password"></span>
<input type="password" name="cpassword" class="cpassword" placeholder="Confirm Password"><span toggle="#c_password" class="fa fa-fw fa-eye field_icon show-password"></span>
<p id="activatedTxt">your penguin must be activated before you will be able to play at club penguin</p>
Parent's Email Address:
<div id="ppsmall">Please enter your parent's valid email address. Club Penguin will send your parent an e-mail with an activation code.</div>
<div class="env"> <img src="images/envelope.png">
<input type="text" class="email" name="email">
</div>
</div>
<div class="doll-container fixed"> <img class="doll" src="images/doll.png" /> <span class="penguinName">Penguin Name</span> </div>
</div>
<button type="submit" class="btn" name="submit">Continue</button>
</div>
<div class="done-section">
<h2 class="done">%username%, your Account Has Been Successfully Created!</h2>
</div>
</form>
</div>
</div>
</body>
</html>
Solved my problem lol. I just wrote another function that just selects the classes from a div, removes the current, then adds 1 to the current section to show the next. If anyone has a better method feel free to correct me.
function gotoNextSection() {
current_section = $(sections[current]);
current_section.remove();
current++;
next_section = $(sections[current]);
next_section.fadeIn();
updateProgressbar();
}

How can I select the item from the search dropdown and have it populate the search input field

If you type a word into the search input field a suggestion list appears below.
I would like to be able to select the word from the list e.g Maine (ME) and have it then populate the search input field. How would I manipulate my code to be able to do this please?
HTML
<form action="*">
<div class="form-group">
<input type="text" class="rounded form-control" id="search" autocomplete="off"
placeholder="Current Location">
</div>
<div id="match-list" onclick="myFunction()"></div>
</form>
javascript
const search = document.getElementById('search');
const matchList = document.getElementById('match-list');
// Search states.json and filter it
const searchPlaces = async searchText => {
const res = await fetch('../data/states.json');
const states = await res.json();
// Get matches to current text input
let matches = states.filter(state => {
const regex = new RegExp(`^${searchText}`, 'gi');
return state.name.match(regex) || state.abbr.match(regex);
});
if (searchText.length === 0) {
matches = [];
matchList.innerHTML = '';
}
outputHtml(matches);
};
// Show results in HTML
const outputHtml = matches => {
if (matches.length > 0) {
const html = matches.map(match => `
<div class="card card-body mb-1">
<h6>${match.name} (${match.abbr})</h6>
</div>
`).join('');
matchList.innerHTML = html;
}
};
search.addEventListener('keyup', () => searchPlaces(search.value));
function myFunction() {
document.getElementById("search").innerHTML = "text";
}
json
[
{
"abbr": "AL",
"name": "Alabama",
},
{
"abbr": "ME",
"name": "Maine",
}
]
Found I needed to put value="" into the html file
<input type="search" class="rounded form-control" id="search" autocomplete="off" placeholder="Current Location" value="">
and to update the following function in the javascript file.
function myFunction() {
let texts = document.querySelector("h6").innerText;
document.getElementById("search").value = texts;
matchList.innerHTML = '';
}

How to delete an item on click from dynamically generated content javascript

I am working on a very basic task application with vanilla javascript. I have an array and from that, I am rendering the todos dynamically. I want to delete a todo when the checkbox is clicked.
I tried to create a form with the id of the todo in the hidden input and on change event submit the form and delete the todo but I'm generating all of them dynamically. Don't you think it will be a lot of code?
Is there a better way to do this?
Thank you
const todos = ['Complete the todo app', 'Write a script', 'Record a video', 'Publish the video']
const renderTodos = function (todos) {
document.querySelector('#todos').innerHTML = ''
todos.forEach(function (todo, index) {
const divElem = document.createElement('div')
divElem.classList.add(`item`, `item-${index}`)
document.querySelector('#todos').appendChild(divElem)
const checkboxElem = document.createElement('input')
checkboxElem.type = 'checkbox'
checkboxElem.name = 'deleteTodo'
document.querySelector(`.item-${index}`).appendChild(checkboxElem)
const titleElem = document.createElement('p')
titleElem.textContent = todo
document.querySelector(`.item-${index}`).appendChild(titleElem)
})
}
renderTodos(todos)
document.querySelector('#add-todo').addEventListener('submit', function (e) {
e.preventDefault()
if (e.target.elements.newItem.value === '') {
return
}
todos.push(e.target.elements.newItem.value)
e.target.elements.newItem.value = ''
renderTodos(todos)
})
<div id="todos"></div>
<form class="item" id="add-todo" action="">
<input
type="text"
name="newItem"
placeholder="New Item"
autocomplete="off"
/>
<button type="submit" name="list">+</button>
</form>
use remove method :
const DomParser = new DOMParser()
, todoAll = document.getElementById('todos')
, todoForm = document.getElementById('add-todo')
, todos = ['Complete the todo app', 'Write a script', 'Record a video', 'Publish the video']
;
function todoAdding(todo, index)
{
let elmZ = `<div class="item item-${index}"><input type="checkbox" name="deleteTodo"><p>${todo}</p></div>`;
let inZ = DomParser.parseFromString( elmZ, 'text/html');
todoAll.appendChild( inZ.body.firstChild )
}
function renderTodos(todos)
{
document.querySelector('#todos').innerHTML = ''
todos.forEach( todoAdding )
}
todoForm.onclick = e =>
{
e.preventDefault()
if (todoForm.newItem.value === '') return
todos.push(todoForm.newItem.value)
todoForm.newItem.value = ''
renderTodos(todos)
}
todoAll.onclick = e =>
{
if (!e.target.matches('input[type=checkbox]')) return
let suppIndex = todos.findIndex(todo=>todo===e.target.parentNode.querySelector('p').textContent)
todos.splice(suppIndex,1)
e.target.parentNode.remove()
}
renderTodos(todos) // initial case
<div id="todos"></div>
<form class="item" id="add-todo" action="">
<input
type="text"
name="newItem"
placeholder="New Item"
autocomplete="off"
/>
<button type="submit" name="list">+</button>
</form>

How can I get form data with JavaScript/jQuery?

Is there a simple, one-line way to get the data of a form as it would be if it was to be submitted in the classic HTML-only way?
For example:
<form>
<input type="radio" name="foo" value="1" checked="checked" />
<input type="radio" name="foo" value="0" />
<input name="bar" value="xxx" />
<select name="this">
<option value="hi" selected="selected">Hi</option>
<option value="ho">Ho</option>
</form>
Output:
{
"foo": "1",
"bar": "xxx",
"this": "hi"
}
Something like this is too simple, since it does not (correctly) include textareas, selects, radio buttons and checkboxes:
$("#form input").each(function () {
data[theFieldName] = theFieldValue;
});
Use $('form').serializeArray(), which returns an array:
[
{"name":"foo","value":"1"},
{"name":"bar","value":"xxx"},
{"name":"this","value":"hi"}
]
Other option is $('form').serialize(), which returns a string:
"foo=1&bar=xxx&this=hi"
Take a look at this jsfiddle demo
$('form').serialize() //this produces: "foo=1&bar=xxx&this=hi"
demo
Updated answer for 2014: HTML5 FormData does this
var formData = new FormData(document.querySelector('form'))
You can then post formData exactly as it is - it contains all names and values used in the form.
Based on jQuery.serializeArray, returns key-value pairs.
var data = $('#form').serializeArray().reduce(function(obj, item) {
obj[item.name] = item.value;
return obj;
}, {});
document.querySelector('form').addEventListener('submit', (e) => {
const formData = new FormData(e.target);
// Now you can use formData.get('foo'), for example.
// Don't forget e.preventDefault() if you want to stop normal form .submission
});
This is a nitpicky answer, but let me explain why this is a better solution:
We're properly handling a form submit rather than a button press. Some people like to push enter on fields. Some people use alternative input devices such as speech input or other accessibility devices. Handle the form submit and you correctly solve it for everyone.
We're digging into the form data for the actual form that was submitted. If you change your form selector later, you don't have to change the selectors for all the fields. Furthermore, you might have several forms with the same input names. No need to disambiguate with excessive IDs and what not, just track the inputs based on the form that was submitted. This also enables you to use a single event handler for multiple forms if that is appropriate for your situation.
The FormData interface is fairly new, but is well supported by browsers. It's a great way to build that data collection to get the real values of what's in the form. Without it, you're going to have to loop through all the elements (such as with form.elements) and figure out what's checked, what isn't, what the values are, etc. Totally possible if you need old browser support, but the FormData interface is simpler.
I'm using ES6 here... not a requirement by any means, so change it back to be ES5 compatible if you need old browser support.
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());
or if you want a plain Object instead
const form = document.querySelector('form');
const data = Object.fromEntries(new FormData(form).entries());
although note that this won't work with duplicate keys like you get from multi-select and duplicate checkboxes with the same name.
Simplest way, 2022.
document.querySelector('form').addEventListener('submit', (e) => {
const data = Object.fromEntries(new FormData(e.target).entries());
console.log(data)
});
Output
{ name: 'Stackoverflow' }
use .serializeArray() to get the data in array format and then convert it into an object:
function getFormObj(formId) {
var formObj = {};
var inputs = $('#'+formId).serializeArray();
$.each(inputs, function (i, input) {
formObj[input.name] = input.value;
});
return formObj;
}
Here's a really simple and short soluton that even doesn't require Jquery.
var formElements=document.getElementById("myForm").elements;
var postData={};
for (var i=0; i<formElements.length; i++)
if (formElements[i].type!="submit")//we dont want to include the submit-buttom
postData[formElements[i].name]=formElements[i].value;
I use this:
jQuery Plugin
(function($){
$.fn.getFormData = function(){
var data = {};
var dataArray = $(this).serializeArray();
for(var i=0;i<dataArray.length;i++){
data[dataArray[i].name] = dataArray[i].value;
}
return data;
}
})(jQuery);
HTML Form
<form id='myform'>
<input name='myVar1' />
<input name='myVar2' />
</form>
Get the Data
var myData = $("#myForm").getFormData();
$("#form input, #form select, #form textarea").each(function() {
data[theFieldName] = theFieldValue;
});
other than that, you might want to look at serialize();
Here is a working JavaScript only implementation which correctly handles checkboxes, radio buttons, and sliders (probably other input types as well, but I've only tested these).
function setOrPush(target, val) {
var result = val;
if (target) {
result = [target];
result.push(val);
}
return result;
}
function getFormResults(formElement) {
var formElements = formElement.elements;
var formParams = {};
var i = 0;
var elem = null;
for (i = 0; i < formElements.length; i += 1) {
elem = formElements[i];
switch (elem.type) {
case 'submit':
break;
case 'radio':
if (elem.checked) {
formParams[elem.name] = elem.value;
}
break;
case 'checkbox':
if (elem.checked) {
formParams[elem.name] = setOrPush(formParams[elem.name], elem.value);
}
break;
default:
formParams[elem.name] = setOrPush(formParams[elem.name], elem.value);
}
}
return formParams;
}
Working example:
function setOrPush(target, val) {
var result = val;
if (target) {
result = [target];
result.push(val);
}
return result;
}
function getFormResults(formElement) {
var formElements = formElement.elements;
var formParams = {};
var i = 0;
var elem = null;
for (i = 0; i < formElements.length; i += 1) {
elem = formElements[i];
switch (elem.type) {
case 'submit':
break;
case 'radio':
if (elem.checked) {
formParams[elem.name] = elem.value;
}
break;
case 'checkbox':
if (elem.checked) {
formParams[elem.name] = setOrPush(formParams[elem.name], elem.value);
}
break;
default:
formParams[elem.name] = setOrPush(formParams[elem.name], elem.value);
}
}
return formParams;
}
//
// Boilerplate for running the snippet/form
//
function ok() {
var params = getFormResults(document.getElementById('main_form'));
document.getElementById('results_wrapper').innerHTML = JSON.stringify(params, null, ' ');
}
(function() {
var main_form = document.getElementById('main_form');
main_form.addEventListener('submit', function(event) {
event.preventDefault();
ok();
}, false);
})();
<form id="main_form">
<div id="questions_wrapper">
<p>what is a?</p>
<div>
<input type="radio" required="" name="q_0" value="a" id="a_0">
<label for="a_0">a</label>
<input type="radio" required="" name="q_0" value="b" id="a_1">
<label for="a_1">b</label>
<input type="radio" required="" name="q_0" value="c" id="a_2">
<label for="a_2">c</label>
<input type="radio" required="" name="q_0" value="d" id="a_3">
<label for="a_3">d</label>
</div>
<div class="question range">
<label for="a_13">A?</label>
<input type="range" required="" name="q_3" id="a_13" min="0" max="10" step="1" list="q_3_dl">
<datalist id="q_3_dl">
<option value="0"></option>
<option value="1"></option>
<option value="2"></option>
<option value="3"></option>
<option value="4"></option>
<option value="5"></option>
<option value="6"></option>
<option value="7"></option>
<option value="8"></option>
<option value="9"></option>
<option value="10"></option>
</datalist>
</div>
<p>A and/or B?</p>
<div>
<input type="checkbox" name="q_4" value="A" id="a_14">
<label for="a_14">A</label>
<input type="checkbox" name="q_4" value="B" id="a_15">
<label for="a_15">B</label>
</div>
</div>
<button id="btn" type="submit">OK</button>
</form>
<div id="results_wrapper"></div>
edit:
If you're looking for a more complete implementation, then take a look at this section of the project I made this for. I'll update this question eventually with the complete solution I came up with, but maybe this will be helpful to someone.
I have included the answer to also give back the object required.
function getFormData(form) {
var rawJson = form.serializeArray();
var model = {};
$.map(rawJson, function (n, i) {
model[n['name']] = n['value'];
});
return model;
}
Based on neuront's response I created a simple JQuery method that gets the form data in key-value pairs but it works for multi-selects and for array inputs with name='example[]'.
This is how it is used:
var form_data = $("#form").getFormObject();
You can find an example below of its definition and how it works.
// Function start
$.fn.getFormObject = function() {
var object = $(this).serializeArray().reduce(function(obj, item) {
var name = item.name.replace("[]", "");
if ( typeof obj[name] !== "undefined" ) {
if ( !Array.isArray(obj[name]) ) {
obj[name] = [ obj[name], item.value ];
} else {
obj[name].push(item.value);
}
} else {
obj[name] = item.value;
}
return obj;
}, {});
return object;
}
// Function ends
// This is how it's used
$("#getObject").click( function() {
var form_data = $("#form").getFormObject();
console.log(form_data);
});
/* Only to make view better ;) */
#getObject {
padding: 10px;
cursor:pointer;
background:#0098EE;
color:white;
display:inline-block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<form id="form">
<input type="text" name="text" value="Hola amigo" />
<input type="text" name="text_array[]" value="Array 1" />
<input type="text" name="text_array[]" value="Array 2" />
<input type="text" name="text_array[]" value="Array 3" />
<select name="multiselect" multiple>
<option name="option1" selected> option 1 </option>
<option name="option2" selected> option 2 </option>
</select>
<input type="checkbox" name="checkbox" value="checkbox1" checked/>
<input type="checkbox" name="checkbox" value="checkbox2" checked/>
<input type="radio" name="radio" value="radio1" checked/>
<input type="radio" name="radio" value="radio2"/>
</form>
<div id="getObject"> Get object (check the console!) </div>
If you are using jQuery, here is a little function that will do what you are looking for.
First, add an ID to your form (unless it is the only form on the page, then you can just use 'form' as the dom query)
<form id="some-form">
<input type="radio" name="foo" value="1" checked="checked" />
<input type="radio" name="foo" value="0" />
<input name="bar" value="xxx" />
<select name="this">
<option value="hi" selected="selected">Hi</option>
<option value="ho">Ho</option>
</form>
<script>
//read in a form's data and convert it to a key:value object
function getFormData(dom_query){
var out = {};
var s_data = $(dom_query).serializeArray();
//transform into simple data/value object
for(var i = 0; i<s_data.length; i++){
var record = s_data[i];
out[record.name] = record.value;
}
return out;
}
console.log(getFormData('#some-form'));
</script>
The output would look like:
{
"foo": "1",
"bar": "xxx",
"this": "hi"
}
You can also use the FormData Objects; The FormData object lets you compile a set of key/value pairs to send using XMLHttpRequest. Its primarily intended for use in sending form data, but can be used independently from forms in order to transmit keyed data.
var formElement = document.getElementById("myform_id");
var formData = new FormData(formElement);
console.log(formData);
This will append all form fields to the JavaScript object "res":
var res = {};
$("#form input, #form select, #form textarea").each(function(i, obj) {
res[obj.name] = $(obj).val();
})
var formData = new FormData($('#form-id'));
params = $('#form-id').serializeArray();
$.each(params, function(i, val) {
formData.append(val.name, val.value);
});
For those of you who would prefer an Object as opposed to a serialized string (like the one returned by $(form).serialize(), and a slight improvement on $(form).serializeArray()), feel free to use the code below:
var Form = {
_form: null,
_validate: function(){
if(!this._form || this._form.tagName.toLowerCase() !== "form") return false;
if(!this._form.elements.length) return false;
return true;
}, _loopFields: function(callback){
var elements = this._form.elements;
for(var i = 0; i < elements.length; i++){
var element = form.elements[i];
if(name !== ""){
callback(this._valueOfField(element));
}
}
}, _valueOfField: function(element){
var type = element.type;
var name = element.name.trim();
var nodeName = element.nodeName.toLowerCase();
switch(nodeName){
case "input":
if(type === "radio" || type === "checkbox"){
if(element.checked){
return element.value;
}
}
return element.value;
break;
case "select":
if(type === "select-multiple"){
for(var i = 0; i < element.options.length; i++){
if(options[i].selected){
return element.value;
}
}
}
return element.value;
break;
case "button":
switch(type){
case "reset":
case "submit":
case "button":
return element.value;
break;
}
break;
}
}, serialize: function(form){
var data = {};
this._form = form;
if(this._validate()){
this._loopFields(function(value){
if(value !== null) data[name] = value;
});
}
return data;
}
};
To execute it, just use Form.serialize(form) and the function will return an Object similar to this:
<!-- { username: "username", password: "password" } !-->
<input type="text" value="username">
<input type="password" value="password">
As a bonus, it means you don't have to install the entire bundle of jQuery just for one serialize function.
I'm kind of supprised because no one mentioned below solution.
Get form data via document.forms.namedItem function
var form = document.forms.namedItem("fileinfo");
form.addEventListener('submit', function(ev) {
var oData = new FormData(form);
}
The HT
<form name="fileinfo">
<label>Your email address:</label>
<input type="email" autocomplete="on" autofocus name="userid" placeholder="email" required size="32" maxlength="64" /><br />
<label>Custom file label:</label>
<input type="text" name="filelabel" size="12" maxlength="32" /><br />
<label>File to stash:</label>
<input type="file" name="file" required />
<input type="submit" value="Stash the file!" />
</form>
<div></div>
I wrote a library to solve this very problem: JSONForms. It takes a form, goes through each input and builds a JSON object you can easily read.
Say you have the following form:
<form enctype='application/json'>
<input name='places[0][city]' value='New York City'>
<input type='number' name='places[0][population]' value='8175133'>
<input name='places[1][city]' value='Los Angeles'>
<input type='number' name='places[1][population]' value='3792621'>
<input name='places[2][city]' value='Chicago'>
<input type='number' name='places[2][population]' value='2695598'>
</form>
Passing the form to JSONForms' encode method returns you the following object:
{
"places": [
{
"city": "New York City",
"population": 8175133
},
{
"city": "Los Angeles",
"population": 3792621
},
{
"city": "Chicago",
"population": 2695598
}
]
}
Here's demo with your form.
function getFormData($form){
var unindexed_array = $form.serializeArray();
var indexed_array = {};
$.map(unindexed_array, function(n, i){
if(indexed_array[n['name']] == undefined){
indexed_array[n['name']] = [n['value']];
}else{
indexed_array[n['name']].push(n['value']);
}
});
return indexed_array;
}
you can use this function for have an object or a JSON from form.
for use it:
var object = formService.getObjectFormFields("#idform");
function getObjectFormFields(formSelector)
{
/// <summary>Função que retorna objeto com base nas propriedades name dos elementos do formulário.</summary>
/// <param name="formSelector" type="String">Seletor do formulário</param>
var form = $(formSelector);
var result = {};
var arrayAuxiliar = [];
form.find(":input:text").each(function (index, element)
{
var name = $(element).attr('name');
var value = $(element).val();
result[name] = value;
});
form.find(":input[type=hidden]").each(function (index, element)
{
var name = $(element).attr('name');
var value = $(element).val();
result[name] = value;
});
form.find(":input:checked").each(function (index, element)
{
var name;
var value;
if ($(this).attr("type") == "radio")
{
name = $(element).attr('name');
value = $(element).val();
result[name] = value;
}
else if ($(this).attr("type") == "checkbox")
{
name = $(element).attr('name');
value = $(element).val();
if (result[name])
{
if (Array.isArray(result[name]))
{
result[name].push(value);
} else
{
var aux = result[name];
result[name] = [];
result[name].push(aux);
result[name].push(value);
}
} else
{
result[name] = [];
result[name].push(value);
}
}
});
form.find("select option:selected").each(function (index, element)
{
var name = $(element).parent().attr('name');
var value = $(element).val();
result[name] = value;
});
arrayAuxiliar = [];
form.find("checkbox:checked").each(function (index, element)
{
var name = $(element).attr('name');
var value = $(element).val();
result[name] = arrayAuxiliar.push(value);
});
form.find("textarea").each(function (index, element)
{
var name = $(element).attr('name');
var value = $(element).val();
result[name] = value;
});
return result;
}
$( "form" ).bind( "submit", function(e) {
e.preventDefault();
console.log( $(this).serializeObject() );
//console.log( $(this).serialize() );
//console.log( $(this).serializeArray() );
});
$.fn.serializeObject = function() {
var o = {};
var a = this.serializeArray();
$.each( a, function() {
if ( o[this.name] !== undefined)
{
if ( ! o[this.name].push )
{
o[this.name] = [o[this.name]];
}
o[this.name].push(this.value || '');
}
else
{
o[this.name] = this.value || '';
}
});
return o;
};
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<form>
<input type="radio" name="foo" value="1" checked="checked" />
<input type="radio" name="foo" value="0" />
<input name="bar" value="xxx" />
<select name="this">
<option value="hi" selected="selected">Hi</option>
<option value="ho">Ho</option>
</select>
<input type="submit" value="Submit" />
</form>
Codepen
I wrote a function that takes care of multiple checkboxes and multiple selects. In those cases it returns an array.
function getFormData(formId) {
return $('#' + formId).serializeArray().reduce(function (obj, item) {
var name = item.name,
value = item.value;
if (obj.hasOwnProperty(name)) {
if (typeof obj[name] == "string") {
obj[name] = [obj[name]];
obj[name].push(value);
} else {
obj[name].push(value);
}
} else {
obj[name] = value;
}
return obj;
}, {});
}
Here is a nice vanilla JS function I wrote to extract form data as an object. It also has options for inserting additions into the object, and for clearing the form input fields.
const extractFormData = ({ form, clear, add }) => {
return [].slice.call(form.children).filter(node => node.nodeName === 'INPUT')
.reduce((formData, input) => {
const value = input.value
if (clear) { input.value = '' }
return {
...formData,
[input.name]: value
}
}, add)
}
Here is an example of its use with a post request:
submitGrudge(e) {
e.preventDefault()
const form = e.target
const add = { id: Date.now(), forgiven: false }
const grudge = extractFormData({ form, add, clear: true })
// grudge = {
// "name": "Example name",
// "offense": "Example string",
// "date": "2017-02-16",
// "id": 1487877281983,
// "forgiven": false
// }
fetch('http://localhost:3001/api/grudge', {
method: 'post',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(grudge)
})
.then(response => response.json())
.then(grudges => this.setState({ grudges }))
.catch(err => console.log('error: ', err))
}
showing form input element fields and input file to submit your form without page refresh and grab all values with file include in it here it is
<form id="imageUploadForm" action="" method="post" enctype="multipart/form-data">
<input type="text" class="form-control" id="fname" name='fname' placeholder="First Name" >
<input type="text" class="form-control" name='lname' id="lname" placeholder="Last Name">
<input type="number" name='phoneno' class="form-control" id="phoneno" placeholder="Phone Number">
<textarea class="form-control" name='address' id="address" rows="5" cols="5" placeholder="Your Address"></textarea>
<input type="file" name="file" id="file" >
<input type="submit" id="sub" value="Registration">
</form>
on Submit button page will send ajax request to your php file.
$('#imageUploadForm').on('submit',(function(e)
{
fname = $('#fname').val();
lname = $('#lname').val();
address = $('#address').val();
phoneno = $('#phoneno').val();
file = $('#file').val();
e.preventDefault();
var formData = new FormData(this);
formData.append('file', $('#file')[0]);
formData.append('fname',$('#fname').val());
formData.append('lname',$('#lname').val());
formData.append('phoneno',$('#phoneno').val());
formData.append('address',$('#address').val());
$.ajax({
type:'POST',
url: "test.php",
//url: '<?php echo base_url().'edit_profile/edit_profile2';?>',
data:formData,
cache:false,
contentType: false,
processData: false,
success:function(data)
{
alert('Data with file are submitted !');
}
});
}))
$(form).serializeArray().reduce(function (obj, item) {
if (obj[item.name]) {
if ($.isArray(obj[item.name])) {
obj[item.name].push(item.value);
} else {
var previousValue = obj[item.name];
obj[item.name] = [previousValue, item.value];
}
} else {
obj[item.name] = item.value;
}
return obj;
}, {});
It will fix issue:couldn't work with multiselects.
Here's my version in vanilla JS (tested on Chrome)
works with:
name="input"
name="form[name]" (creates an object)
name="checkbox[]" (creates an object with an array)
name="form[checkbox][]" (creates an array)
name="form[select][name]" (creates an object with an object containing only the selected value)
/**
* Get the values from a form
* #param formId ( ID without the # )
* #returns {object}
*/
function getFormValues( formId )
{
let postData = {};
let form = document.forms[formId];
let formData = new FormData( form );
for ( const value of formData.entries() )
{
let container = postData;
let key = value[0];
let arrayKeys = key.match( /\[[\w\-]*\]/g ); // Check for any arrays
if ( arrayKeys !== null )
{
arrayKeys.unshift( key.substr( 0, key.search( /\[/ ) ) ); // prepend the first key to the list
for ( let i = 0, count = arrayKeys.length, lastRun = count - 1; i < count; i++ )
{
let _key = arrayKeys[i];
_key = _key.replace( "[", '' ).replace( "]", '' ); // Remove the brackets []
if ( _key === '' )
{
if ( ! Array.isArray( container ) )
{
container = [];
}
_key = container.length;
}
if ( ! (_key in container) ) // Create an object for the key if it doesn't exist
{
if ( i !== lastRun && arrayKeys[i + 1] === '[]' )
{
container[_key] = [];
}
else
{
container[_key] = {};
}
}
if ( i !== lastRun ) // Until we're the last item, swap container with it's child
{
container = container[_key];
}
key = _key;
}
}
container[key] = value[1]; // finally assign the value
}
return postData;
}
You are all not fully correct. You cannot write:
formObj[input.name] = input.value;
Because this way if you have multiselect list - its values will be overwritten with the last one, since it's transmitted as: "param1" : "value1", "param1" : "value2".
So, correct approach is:
if (formData[input.name] === undefined) {
formData[input.name] = input.value;
}
else {
var inputFieldArray = $.merge([], $.isArray(formData[input.name]) ? formData[input.name] : [formData[input.name]]);
$.merge(inputFieldArray, [input.value]);
formData[input.name] = $.merge([], inputFieldArray);
}

Categories