This is my form view:
and this is my dynamic input form code:
...
let subJudulInput = []; // this variable will render
for (var i = 0; i < this.props.subtitleInput.index; i++) {
let index = i + 1;
subJudulInput.push(
<div key={'formgroup' + index} class="form-group">
{(i === 0) ? <label for="subJudulInput">Sub Judul</label>:false}
<input key={'input' + index} type="text" class="form-control" placeholder={`Masukan Sub Judul ${index}`}/>
</div>
);
}
...
If I click the plus button, the new input form will show:
This is my form handler:
onAddingTitle(event) { // if the submit button get pressed
let formData = {subJudul:[]};
event.preventDefault();
console.log(event.target.elements);
}
How I can grab all of that dynamic input value? (Best ways) to formData object; like this:
let formData = {subJudul:[
'sub judul 1 value here',
'sub judul 2 value here',
'sub judul 3 value here',
'next new input'
]};
Add name attribute to the text field: name={"textbox-"+index}
Try the below code to get your expected values
onAddingTitle(event) {
event.preventDefault();
let formElements = event.target.elements;
let formData = {
subJudul: []
};
Object.keys(formElements).forEach((key) => {
if (formElements[key].type == 'text') {
formData.subJudul.push(formElements[key].value)
}
});
console.log('formData', formData);
}
Explanation:
Get the form elements (which is a object)
loop through the object elemets using keys
Check the type of the field, if its a textbox(add as per your need) push the value of the field to array.
Related
I have a page, where I need to filter through all kinds of data (served as JSON variable) using just pure javascript. Everything works nicely until I try to implement a datalist where the contents of that list are updated in realtime, based on user input.
var data = [{name:"Paul"},{name:"Alex"},{name:"Laura"}] // This is just example object
function updateSearch() {
let search = document.getElementById('search').value;
let options = document.getElementById('searchList');
options.innerHTML = "";
if (search.length >= 2) {
search = search.toLowerCase();
for (let d of data) {
if (d.name.toLowerCase().search(search) === 0) {
options.innerHTML += `
<option>${d.name}</option>
`;
}
}
}
}
<datalist id='searchList'></datalist>
<input type="search" id="search" list='searchList' onchange="updateSearch()">
The goal is to not show the full list of names until at least 2 characters are entered, but it just won't update until the user clicks out focuses back to search input.
One solution to achieve what you require would be to replace the event type that updateSearch() is bound to from onchange to onkeyup:
const data = [
{ name : "Foo" },
{ name : "Bar" },
{ name : "Bing" },
{ name : "Bong" },
{ name : "Boo!" }];
function updateSearch() {
let search = document.getElementById('search').value;
let options = document.getElementById('searchList');
options.innerHTML = "";
if (search.length >= 2) {
search = search.toLowerCase();
for (let d of data) {
if (d.name.toLowerCase().search(search) === 0) {
options.innerHTML += `
<option>${d.name}</option>
`;
}
}
}
}
<datalist id='searchList'></datalist>
<!-- Update to onkeyup -->
<input type="search" id="search" list='searchList' onkeyup="updateSearch()">
Doing this will cause the datalist to interactivly update as the user types. Hope that helps!
I am currently trying to add a button, that when I click it - a list of questions appear (with textareas/inputs), every textarea/input has his own ID and I'm trying to get all of the answers printed into one form.
<h5>QUESTION BULK 1/h5>
<div id="question1">
<h4">#1</h4>
<p>Relative name?: <input id="a_relative">
<p>Age: <input id="a_age">
<p>What makes him your relative?: <input id="a_what">
</div>
I'm trying to get a button to make it add that bulk of questions, so the user can add the relevant amount.
e.g:
<button onClick="clickMe()">Add</button>
All of the data from the inputs should be later taken and put into a certain "answer sheet" form.
e.g:
function clickMe() {
var relative = document.getElementById("a_relative").value;
var age = document.getElementById("a_age").value;
var what = document.getElementById("a_what").value;
var generatedForm = " Name: "+relative+"\n\
Relative age: "+age+"\n\
Reason he/she is your relative: "+what+".";
document.getElementById("X").value = clickMe // put everything in a textarea of example,
}
Try using JQuery it makes id that you do not have to use
document.getElementById("a_relative").value;
Here's a quick solution using modern JS methods.
// Use an array to contain the questions
const questions = [
// Each question has an id, question text, and an
// object containing the input information
{ id: 1, text: 'Name', input: { el: 'input', type: 'text' } },
{ id: 2, text: 'Age', input: { el: 'input', type: 'number' } },
{ id: 3, text: 'How', input: { el: 'textarea' } },
];
// Grab and cache the elements from the page
const main = document.querySelector('.main');
const form = document.querySelector('form');
const output = document.querySelector('#output');
const add = document.querySelector('.add');
const show = document.querySelector('.show');
// Add event listeners for the buttons
add.addEventListener('click', handleAdd, false);
show.addEventListener('click', handleShow, false);
// When add button is clicked...
function handleAdd() {
// ...produce html for each question in the array...
const html = questions.map(question => {
return createQuestionHTML(question);
}).join('');
// ...and add it to the form.
form.insertAdjacentHTML('beforeend', html);
}
function createQuestionHTML(question) {
// Grab the properties/values from the question object
const { id, text, input: { el, type } } = question;
// Based on the input type choose whether an input
// or a textarea should be displayed.
// Ensure they have an answer class, and a data attribute
// with question text
let input = type === 'input'
? `<${el} type=${type} class="answer" data-to="${text}" />`
: `<${el} class="answer" data-to="${text}"></${el}`;
// Return a section containing a heading of the question text,
// and the appropriate input element
return (
`<section class="question">
<h5>${id} - ${text}</h5>
${input}
</section>`
);
}
// When the show button is clicked...
function handleShow() {
// ...select all the elements with the answer class within the form
const answers = form.querySelectorAll('.answer');
// Hide the form
main.classList.add('hidden');
// Log the value and data-to attribute text to console
[...answers].forEach(({ value, dataset }) => {
output.insertAdjacentHTML('beforeend', `<div>${dataset.to} => ${value}`);
});
}
form, .buttons { margin-bottom: 1em; }
h5 { margin-bottom: 0.2em; }
.hidden { display: none }
<section class="main">
<form></form>
<section class="buttons">
<button class="add">Add questions</button>
<button class="show">Show answers</button>
</section>
</section>
<div id="output" />
I have a Contact Form that utilizes Google Scripts. It successfully sends the email and formats it decently to my inbox, but there are 2 problems:
-I need it so that IF var key is equal to 'Action', then do not display it in the email it sends. Because right now, "Action send_message" is getting included in the email and I don't like that.
For this, I have unsuccessfully tried things like:
for (var idx in order) {
var key = order[idx];
//Skip this entry into the email output if it is the Action
if( key === 'Action') {
continue
}
It seems to not react to this code at all.
-I also need it so that if a city is selected, e.g. Alachua, that the email says 'Alachua' instead of 'Florida_Alachua'. But I can't add a NAME to an option since apparently options don't have that property. I also can't do the quick fix of changing the VALUE of the <option> to resolve this step, because of other code I have that conflicts with this route.
Google Scripts Code:
/******************************************************************************
* This tutorial is based on the work of Martin Hawksey twitter.com/mhawksey *
* But has been simplified and cleaned up to make it more beginner friendly *
* All credit still goes to Martin and any issues/complaints/questions to me. *
******************************************************************************/
// if you want to store your email server-side (hidden), uncomment the next line
var TO_ADDRESS = "myemail#email.com";
// spit out all the keys/values from the form in HTML for email
// uses an array of keys if provided or the object to determine field order
function formatMailBody(obj, order) {
var result = "";
if (!order) {
order = Object.keys(obj);
}
// loop over all keys in the ordered form data
for (var idx in order) {
var key = order[idx];
result += "<h4 style='text-transform: capitalize; margin-bottom: 0'>" + key + "</h4><div>" + sanitizeInput(obj[key]) + "</div>";
// for every key, concatenate an `<h4 />`/`<div />` pairing of the key name and its value,
// and append it to the `result` string created at the start.
}
return result; // once the looping is done, `result` will be one long string to put in the email body
}
// sanitize content from the user - trust no one
// ref: https://developers.google.com/apps-script/reference/html/html-output#appendUntrusted(String)
function sanitizeInput(rawInput) {
var placeholder = HtmlService.createHtmlOutput(" ");
placeholder.appendUntrusted(rawInput);
return placeholder.getContent();
}
function doPost(e) {
try {
Logger.log(e); // the Google Script version of console.log see: Class Logger
record_data(e);
// shorter name for form data
var mailData = e.parameters;
// names and order of form elements (if set)
var orderParameter = e.parameters.formDataNameOrder;
var dataOrder;
if (orderParameter) {
dataOrder = JSON.parse(orderParameter);
}
// determine recepient of the email
// if you have your email uncommented above, it uses that `TO_ADDRESS`
// otherwise, it defaults to the email provided by the form's data attribute
var sendEmailTo = (typeof TO_ADDRESS !== "undefined") ? TO_ADDRESS : mailData.formGoogleSendEmail;
// send email if to address is set
if (sendEmailTo) {
MailApp.sendEmail({
to: String(sendEmailTo),
subject: "Contact form submitted",
// replyTo: String(mailData.email), // This is optional and reliant on your form actually collecting a field named `email`
htmlBody: formatMailBody(mailData, dataOrder)
});
}
return ContentService // return json success results
.createTextOutput(
JSON.stringify({"result":"success",
"data": JSON.stringify(e.parameters) }))
.setMimeType(ContentService.MimeType.JSON);
} catch(error) { // if error return this
Logger.log(error);
return ContentService
.createTextOutput(JSON.stringify({"result":"error", "error": error}))
.setMimeType(ContentService.MimeType.JSON);
}
}
/**
* record_data inserts the data received from the html form submission
* e is the data received from the POST
*/
function record_data(e) {
var lock = LockService.getDocumentLock();
lock.waitLock(30000); // hold off up to 30 sec to avoid concurrent writing
try {
Logger.log(JSON.stringify(e)); // log the POST data in case we need to debug it
// select the 'responses' sheet by default
var doc = SpreadsheetApp.getActiveSpreadsheet();
var sheetName = e.parameters.formGoogleSheetName || "responses";
var sheet = doc.getSheetByName(sheetName);
var oldHeader = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues()[0];
var newHeader = oldHeader.slice();
var fieldsFromForm = getDataColumns(e.parameters);
var row = [new Date()]; // first element in the row should always be a timestamp
// loop through the header columns
for (var i = 1; i < oldHeader.length; i++) { // start at 1 to avoid Timestamp column
var field = oldHeader[i];
var output = getFieldFromData(field, e.parameters);
row.push(output);
// mark as stored by removing from form fields
var formIndex = fieldsFromForm.indexOf(field);
if (formIndex > -1) {
fieldsFromForm.splice(formIndex, 1);
}
}
// set any new fields in our form
for (var i = 0; i < fieldsFromForm.length; i++) {
var field = fieldsFromForm[i];
var output = getFieldFromData(field, e.parameters);
row.push(output);
newHeader.push(field);
}
// more efficient to set values as [][] array than individually
var nextRow = sheet.getLastRow() + 1; // get next row
sheet.getRange(nextRow, 1, 1, row.length).setValues([row]);
// update header row with any new data
if (newHeader.length > oldHeader.length) {
sheet.getRange(1, 1, 1, newHeader.length).setValues([newHeader]);
}
}
catch(error) {
Logger.log(error);
}
finally {
lock.releaseLock();
return;
}
}
function getDataColumns(data) {
return Object.keys(data).filter(function(column) {
return !(column === 'formDataNameOrder' || column === 'formGoogleSheetName' || column === 'formGoogleSendEmail' || column === 'honeypot');
});
}
function getFieldFromData(field, data) {
var values = data[field] || '';
var output = values.join ? values.join(', ') : values;
return output;
}
Contact Form HTML
<section id="contact-form">
<form id="gform"
class="contact-form" method="post"
action="(Google Scripts URL)"
enctype="text/plain">
<p>
<label for="name">Your Name <font face="Arial" color="red">*</font></label>
<input type="text" style="height:35px;" class="heighttext required" name="name" id="name" class="required" title="* Please provide your name">
</p>
<p>
<label>Your Location <font face="Arial" color="red">*</font></label>
<select name="Location" id="column_select" style="height:35px;" class="required" title=" * Please provide your location">
<option selected value="col00">-- State --</option>
<option value="Alabama">Alabama</option>
<option value="California">California</option>
<option value="Florida">Florida</option>
</select>
<select name="City" id="layout_select" style="height:35px;">
<option disabled selected value="Florida">-- City --</option>
<option name="Alachua" value="Florida_Alachua">Alachua</option>
<option name="Alford" value="Florida_Alford">Alford</option>
</select>
</p>
<p>
<input type="submit" value="Send Message" id="submit" class="pp-btn special">
<img src="images/ajax-loader.gif" id="contact-loader" alt="Loading...">
<input type="hidden" name="action" value="send_message">
</p>
</form>
</section><!-- #contact-form -->
Form Handler Javascript
(function() {
function validEmail(email) { // see:
var re = /^([\w-]+(?:\.[\w-]+)*)#((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$/i;
return re.test(email);
}
function validateHuman(honeypot) {
if (honeypot) { //if hidden form filled up
console.log("Robot Detected!");
return true;
} else {
console.log("Welcome Human!");
}
}
// get all data in form and return object
function getFormData() {
var form = document.getElementById("gform");
var elements = form.elements;
var fields = Object.keys(elements).filter(function(k) {
return (elements[k].name !== "honeypot");
}).map(function(k) {
if(elements[k].name !== undefined) {
return elements[k].name;
// special case for Edge's html collection
}else if(elements[k].length > 0){
return elements[k].item(0).name;
}
}).filter(function(item, pos, self) {
return self.indexOf(item) == pos && item;
});
var formData = {};
fields.forEach(function(name){
var element = elements[name];
// singular form elements just have one value
formData[name] = element.value;
// when our element has multiple items, get their values
if (element.length) {
var data = [];
for (var i = 0; i < element.length; i++) {
var item = element.item(i);
if (item.checked || item.selected) {
data.push(item.value);
}
}
formData[name] = data.join(', ');
}
});
// add form-specific values into the data
formData.formDataNameOrder = JSON.stringify(fields);
formData.formGoogleSheetName = form.dataset.sheet || "responses"; // default sheet name
formData.formGoogleSendEmail = form.dataset.email || ""; // no email by default
console.log(formData);
return formData;
}
function handleFormSubmit(event) { // handles form submit without any jquery
event.preventDefault(); // we are submitting via xhr below
var data = getFormData(); // get the values submitted in the form
/* OPTION: Remove this comment to enable SPAM prevention, see README.md
if (validateHuman(data.honeypot)) { //if form is filled, form will not be submitted
return false;
}
*/
if( data.email && !validEmail(data.email) ) { // if email is not valid show error
var invalidEmail = document.getElementById("email-invalid");
if (invalidEmail) {
invalidEmail.style.display = "block";
return false;
}
} else {
disableAllButtons(event.target);
var url = event.target.action; //
var xhr = new XMLHttpRequest();
xhr.open('POST', url);
// xhr.withCredentials = true;
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.onreadystatechange = function() {
console.log( xhr.status, xhr.statusText )
console.log(xhr.responseText);
//document.getElementById("gform").style.display = "none"; // hide form
/*
var thankYouMessage = document.getElementById("thankyou_message");
if (thankYouMessage) {
thankYouMessage.style.display = "block";
}
*/
return;
};
// url encode form data for sending as post data
var encoded = Object.keys(data).map(function(k) {
return encodeURIComponent(k) + "=" + encodeURIComponent(data[k])
}).join('&')
xhr.send(encoded);
}
}
function loaded() {
console.log("Contact form submission handler loaded successfully.");
// bind to the submit event of our form
var form = document.getElementById("gform");
form.addEventListener("submit", handleFormSubmit, false);
};
document.addEventListener("DOMContentLoaded", loaded, false);
function disableAllButtons(form) {
var buttons = form.querySelectorAll("button");
for (var i = 0; i < buttons.length; i++) {
buttons[i].disabled = true;
}
}
})();
finally, this is the extra code that would break if I simply tried changing the value of option to, e.g., 'Alachua' instead of 'Flordia_Alachua'. https://jsfiddle.net/hmatt843/504dgmqy/19/
Thanks for any and all help.
Try console.log(key) before if( key === 'Action'). I think you'll find that key never equals 'Action', exactly. Looks like you'll need if( key === 'action'), instead.
If you wish to remove part of string value, try the replace method: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace
It also looks like you're trying to work with elements[k].name when you mean to be working with elements[k].value.
I believe your code should look something like...
function(k) {
if(elements[k].value !== undefined) {
return elements[k].value.replace('Florida_', '');
// special case for Edge's html collection
} else if(elements[k].length > 0){
return elements[k].item(0).value.replace('Florida_', '');
}
}
... or something to that effect.
In the future, you may want to make it easier for folks trying to help you by posting only the portions of code your having trouble with, and breaking your questions into different posts. A lot to sift through up there.
Hope this helped.
The split() method splits a String object into an array of strings by separating the string into substrings, using a specified separator string to determine where to make each split.
Var splitValue = elements[k].item(0).value.split("");
splitValue[1] will give you a string of characters after the delimeter () in this case.
I have a dynamic input which will have checkbox to hide the inputs when you tick the checkbox, at the moment I'm trying to add click="getChk() to the checkbox however it was only giving me the last index inputName.
Say I have input Ids (code, sku, id).
My dynamic inputs and checks code line is
for (var x = 0; x < searchParams.length; x++) {
var container = $('#checkBox');
var inputs = container.find('input');
var id = inputs.length + 1;
var inputName = searchParams[x].name;
$('<textarea />', { id: inputName, name: inputName, placeholder: inputName, rows: "2", class: "search-area-txt col-sm-12" }).appendTo(searchbox);
$('<input />', { type: 'checkbox', id: 'x' + id, name: inputName }).appendTo(checkBox);
$('<label />', { 'for': 'x' + id, text: inputName, id: inputName, name: inputName }).appendTo(checkBox);
}
But this will need to be saved in the localStorage so when refresh it will persist the input to be hidden when its exists in the localStorage.
Edit: the code below should save the name in the localStorage in array form.
var inputNames = [];
getChk(id){
var indexOfItem = inputNames.indexOf(name)
if (indexOfItem >= 0) {
inputNames.splice(indexOfItem, 1);
} else {
inputNames.push(name);
}
localStorage.setItem('chked', JSON.stringify(inputNames))
}
My attempt is by adding .click(function(){})
$('<input />', { type: 'checkbox', id: 'x' + id, name: inputName }).appendTo(checkBox).click(function(){
getChk(id); // only gives me the id name
});
HTML inputs and checkbox html
The issue is because when the click event handler runs the for loop has completed, therefore the id variable holds the last value.
To fix this, amend your click handler to read the id attribute directly from the element which raised the event:
$('<input />', { type: 'checkbox', id: 'x' + id, name: inputName }).appendTo(checkBox).click(function() {
getChk(this.id);
});
Also, as spotted by #guest271314, the correct method when setting localStorage data is setItem(), not set():
localStorage.setItem('checked', id);
you can try below code
getChk(e){
localStorage.set('checked', this.id);
console.log('input id>> ', this.id);
}
.click(getChk);
I found a file called copyShipping.js that allows me to copy form elements from one form to another by the click of a checkbox. However, it copies by name of each field rather than ID. Below is the code. How do I get it to copy by ID? I know there's a getElementByID on Javascript but I don't know how to implement it. Ideally I would just like the code changed for me. Thanks.
function eCart_copyBillingToShipping(cb){
if(cb.checked){ // Only copy when the checkbox is checked.
var theForm = cb.form;
// The number of elements must match in billingFields and shippingFields. The type of input element must also match between the arrays.
var billingFields = new Array('firstname', 'lastname', 'email', 'phone', 'fax', 'street1', 'street2', 'city', 'state_province', 'StateOther', 'other_state_province', 'postcode', 'other_postcode', 'country');
var shippingFields = new Array('shipping_firstname', 'shipping_lastname', 'shipping_email', 'shipping_phone', 'shipping_fax', 'shipping_street1', 'shipping_street2', 'shipping_city', 'shipping_state_province', 'ShippingStateOther', 'other_shipping_state_province', 'shipping_postcode', 'other_shipping_postcode', 'shipping_country');
for(var i=0;i<billingFields.length;i++){
var billingObj = theForm.elements[billingFields[i]];
var shippingObj = theForm.elements[shippingFields[i]];
if(billingObj && shippingObj){
if(billingObj.tagName){ // non-radio groups
var tagName = billingObj.tagName.toLowerCase();
if(tagName == 'select'){
shippingObj.selectedIndex = billingObj.selectedIndex;
}
else if((billingObj.type && shippingObj.type ) && (billingObj.type == 'checkbox' || billingObj.type == 'radio')){
shippingObj.checked = billingObj.checked;
}
else{ // textareas and other inputs
shippingObj.value = billingObj.value;
}
}
else if(billingObj.length){ // radio group
for(var r=0;r<billingObj.length;r++){
shippingObj[r].checked = billingObj[r].checked;
}
}
}
}
}
}
It is always recommended to access the elements using Id. Also it is recommended to have id and name same.
Try this.
function eCart_copyBillingToShipping(cb){
if(cb.checked){ // Only copy when the checkbox is checked.
var theForm = cb.form;
// The number of elements must match in billingFields and shippingFields. The type of input element must also match between the arrays.
var billingFields = new Array('firstname', 'lastname', 'email', 'phone', 'fax', 'street1', 'street2', 'city', 'state_province', 'StateOther', 'other_state_province', 'postcode', 'other_postcode', 'country');
var shippingFields = new Array('shipping_firstname', 'shipping_lastname', 'shipping_email', 'shipping_phone', 'shipping_fax', 'shipping_street1', 'shipping_street2', 'shipping_city', 'shipping_state_province', 'ShippingStateOther', 'other_shipping_state_province', 'shipping_postcode', 'other_shipping_postcode', 'shipping_country');
for(var i=0;i<billingFields.length;i++){
//assuming that now array contains id (not name)
var billingObj = theForm.getElementById(billingFields[i]);
var shippingObj = theForm.getElementById(shippingFields[i]);
if(billingObj && shippingObj){
if(billingObj.tagName){ // non-radio groups
var tagName = billingObj.tagName.toLowerCase();
if(tagName == 'select'){
shippingObj.selectedIndex = billingObj.selectedIndex;
}
else if((billingObj.type && shippingObj.type ) && (billingObj.type == 'checkbox' || billingObj.type == 'radio')){
shippingObj.checked = billingObj.checked;
}
else{ // textareas and other inputs
shippingObj.value = billingObj.value;
}
}
else if(billingObj.length){ // radio group
for(var r=0;r<billingObj.length;r++){
shippingObj[r].checked = billingObj[r].checked;
}
}
}
}
}
}