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" />
Related
I have already found a way to get what I want, but I'm trying to understand why the next code doesn't work.
If to be more precise why does the function showHideTaskDetails() doesn't seem to do what it should do (BTW leave aside its name, it's not an indication of its purpose)
I expect the following to happen:
When clicking on the button with the class "fa-solid fa-circle-chevron-down", the value of the variable hideContent change to the opposite of the current value (if it's true to become false and vice versa).
After that if the hideContent is true the variable color will be "background-color: red" so the style of all dives will change to have background with the color red.
But instead, nothing happens!
HTML
<body>
<div class="container">
<form action="">
<label for="task-headline">Task Headline</label>
<input type="text" id="task-headline">
<label for="deadline">Task Deadline</label>
<input type="date" id="deadline">
<label for="task-details">Task Details</label>
<textarea name="" id="task-details" cols="80" rows="10"></textarea>
<button id="add-task">Add Task</button>
</form>
<div class="tasks-area"></div>
</div>
</body>
JS
const headLineEl = document.getElementById("task-headline")
const deadlineEl = document.getElementById("deadline")
const taskDetailsEl = document.getElementById("task-details")
const TasksAreaEl = document.querySelector(".tasks-area")
addTaskBtn = document.getElementById("add-task")
let hideContent = true
let color = ""
showTasks()
addTaskBtn.addEventListener("click", (e) => {
e.preventDefault()
const newTask = collectTaskInfo()
saveToLs(newTask)
showTasks()
})
//get from the local storage the current tasks
function getLsData() {
let currentLsContent = JSON.parse(localStorage.getItem("tasks"))
if (currentLsContent === null) {
currentLsContent = []
}
return currentLsContent
}
//show the tasks on the dom
function showTasks() {
const array = getLsData()
let tasksContainer = []
array.map(task => {
const readyTask =
`
<div class="task-container" style=${color}>
<div class="main-basic-info">
<p> <span>Task:</span> ${task.headline} </p>
<div class="left-part">
<p> <span>Deadline:</span> ${task.deadline} </p>
<i class="fa-solid fa-circle-chevron-down" onClick="showHideTaskDetails()"></i>
</div>
</div>
<p class="details"> <span>Details:</span> ${task.details} </p>
</div>
<br>
`
tasksContainer.push(readyTask)
})
TasksAreaEl.innerHTML = tasksContainer
}
//hide unhide details
function showHideTaskDetails() {
hideContent = !hideContent
console.log(hideContent);
if (hideContent) color = "background-color: red"
// const test = document.getElementsByTagName('div')
// test.style = "background-color: red"
}
//collect task information to object
function collectTaskInfo() {
const obj = {
headline: headLineEl.value,
deadline: deadline.value,
details: taskDetailsEl.value
}
return obj
}
//update the current array in local storage with the new task
function addNewTaskToLsArray(newTask) {
const currentTaskArrayInLs = getLsData()
currentTaskArrayInLs.push(newTask)
const updatedTaskArray = currentTaskArrayInLs
return updatedTaskArray
}
//save data to local storage
function saveToLs(task) {
const arrayWithTheNewTask = addNewTaskToLsArray(task)
localStorage.setItem("tasks", JSON.stringify(arrayWithTheNewTask))
}
You showHideTasksDetails function is not re-rendering the page by itself.
You can modify it so that the showTasks function is called again when the showHideTaskDetails is called.
function showHideTaskDetails() {
hideContent = !hideContent;
console.log(hideContent);
if (hideContent) {
color = "'background-color: red'";
} else {
color = "";
}
// const test = document.getElementsByTagName('div')
// test.style = "background-color: red"
showTasks();
}
first it's onclick not onClick
Second initial value of hideContent is set to true and you're changing it to false when you're calling the showHideTaskDetails fn before if statement
how to pass from a function to another function? (script>script) <= element
how do I pass the value of the field validator into the second function?
<script>
$('#card_number').validateCreditCard(function(result) {
if (result.valid) {
const infosuccess = result.card_type == null ? '-' : result.card_type.name
const valid = result.valid
const validlunn = result.luhn_valid
const validlenght = result.length_valid
console.log(infosuccess);
} else {
// $(this)
// const inforeject = result.valid
// console.log(result);
}
});
</script>
<script>
$('#nextaction').click(function(e) {
e.preventDefault();
// my code...
})
</script>
You cannot pass arguments directly in to event handlers. However, there are other approaches you can use.
In this case you can set the 'Next' button to be disabled when the page loads. You can then enable/disable it depending on the result of the credit card validation.
To retrieve the entered card number you can simply read the value from the input when the button is clicked, like this:
const $cardInput = $('#card_number');
const $validateBtn = $('#validate_card');
const $nextBtn = $('#next-action');
$cardInput.validateCreditCard(function(result) {
$nextBtn.prop('disabled', !result.valid); // enable/disable 'next' button
if (result.valid) {
// update the UI to show card details if necessary here...
} else {
console.log('enter a valid credit card number...');
}
});
$nextBtn.on('click', function(e) {
e.preventDefault();
const cardNumber = $cardInput.val();
console.log(cardNumber);
console.log('move to next action here...');
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-creditcardvalidator/1.0.0/jquery.creditCardValidator.min.js" integrity="sha512-7omJBgl5QF4QuC3Ge745IO3rDZVMrZWIGK8lSs5lQIFxbWt4d2c7YQg3ZcnonFyRuQslrJ1Ai33Zj/rnXC15+Q==" crossorigin="anonymous"
referrerpolicy="no-referrer"></script>
<p>
Test Card number: 5404000000000084
</p>
<label>
Credit card number:
<input type="text" id="card_number" />
<button type="button" id="validate_card">Validate</button>
</label>
<button type="button" id="next-action" disabled>Next...</button>
I was working on a basic commment script. This basically means whatever you type into the textboxes (one for title, and another for message) and then press submit, your comment should be added to the page, similarly how youtube does it. I was planning on having a prebuilt HTML div, and just clone it for every new comment that is made (and of course changing the text to match). The problem is that I can not get my script to work. When you press submit, no element is cloned into the container. This is my issue. What is the problem?
EDIT: I updated the code and the new error is (Cannot read property 'appendChild' of null)
window.onload = () => {
const template = document.comment;
const form = document.forms.comment;
const container = document.querySelector('.container')
form.submit2.addEventListener('click', () => {
const name = form.name;
const text = form.text;
const newNode = template.cloneNode(true);
newNode.classList.remove('hidden')
container.appendChild(newNode)
})
}
.hidden {
display: none;
}
.comment-form input {
display: block;
padding: 2px;
}
<!DOCTYPE html>
<html>
<head>
<link rel = "stylesheet" href = 'style.css'>
</head>
<body>
<form name = "comment" class = "comm">
<input type = "text" maxlength = 20 name = 'name' placeholder = 'name'>
<textarea name = "text" placeholder = 'comment'></textarea>
<input type = "button" value = "submit" name = "submit2">
</form>
<div name = "comment" class = 'hidden'>
<h1>Demo</h1>
<p>Paragraph</p>
</div>
<div class = "container"></div>
<script src = "script.js"></script>
</body>
</html>
window.addEventListener('load', e => {
const template = document.querySelector('.comment-template');
const form = document.querySelector('.comment-form');
const container = document.querySelector('.container');
form.querySelector('.submit-button').addEventListener('click', e => {
const newNode = template.cloneNode(true);
newNode.querySelector('.name').innerText =
form.querySelector('.name').value;
newNode.querySelector('.comment').innerText =
form.querySelector('.comment').value;
newNode.classList.remove('hidden');
container.appendChild(newNode);
});
});
.hidden {
display: none;
}
.comment-form input {
display: block;
padding: 2px;
}
<form class="comment-form">
<input type="text" maxlength="20" placeholder="name" class="name">
<textarea name="text" placeholder="comment" class="comment"></textarea>
<input type="button" value="submit" class="submit-button">
</form>
<div class="comment-template hidden">
<h1 class="name"></h1>
<p class="comment"></p>
</div>
<div class="container"></div>
I changed the logic to use querySelector instead of the name access. Also fixed that the container was originally coming back as an array like object, instead of just one element, which is why the append child didn't work. Also added the logic to actually stick the name and comment text into the cloned node.
window.onload = () => {
let template = document.comment;
// You have two elements with a name of comment. It is being set as the
// form, and not the div that presumably you are trying to clone later.
console.log("My template", template);
// so to fix that, you can select the element by its class instead
template = document.getElementsByClassName('hidden')[0];
console.log("My fixed template", template);
const form = document.forms.comment;
console.log("My form", form);
// getElementsByClassName returns an array like object, even if there
// is only one element matched. Using [0] lets us get just a single one
const container = document.getElementsByClassName('container')[0];
console.log("My container", container);
// using the name change you said you made to have the button named
// submit2 instead of submit, we can bind the click event to it
console.log("My submit button", form.submit2);
form.submit2.addEventListener('click', () => {
let name = form.submit2.name;
console.log("My name", name);
// The "name" element is not a child of the submit button. It is a
// sibling element with it's own name
// We need to reference it instead, and grab the value
name = form.name.value;
console.log("My fixed name", name);
let text = form.submit2.text;
console.log("My text", text);
// Same issue with the text
text = form.text.value;
console.log("My fixed text", text);
const newNode = template.cloneNode(true);
console.log("My new node", newNode.outerHTML);
// As you can see, you cloned the node, but you haven't put the name
// or text on it. Need to do that before appending it to the DOM.
newNode.getElementsByTagName('h1')[0].innerText = name;
newNode.getElementsByTagName('p')[0].innerText = text;
console.log("My fixed new node", newNode.outerHTML);
newNode.classList.remove('hidden');
container.appendChild(newNode);
})
}
.hidden {
display: none;
}
.comm input{
display: block;
padding:2px;
}
<!DOCTYPE html>
<html>
<head>
<link rel = "stylesheet" href = 'style.css'>
</head>
<body>
<form name = "comment" class = "comm">
<input type = "text" maxlength = 20 name = 'name' placeholder = 'name'>
<textarea name = "text" placeholder = 'comment'></textarea>
<input type = "button" value = "submit" name = "submit2">
</form>
<div name = "comment" class = 'hidden'>
<h1>Demo</h1>
<p>Paragraph</p>
</div>
<div class = "container"></div>
<script src = "script.js"></script>
</body>
</html>
Providing an alternative answer that steps through the original logic, attempting to show the issues, and show how to fix them. Trying to stay as close to the original logic as possible.
The problem was that in my HTML elements I added whitespace. Never add spaces around the = sign. Nothing was wrong with the script itself.
With this code we can insert one by one 4 different text values into the search field ('Decoration', 'Health', 'Fun', 'Yesterday 4').
But I need to simultaneously insert an image for each of those text values (appearing logically outside the search field). Note that the next image should appear in place of the first and delete this one.
See in: http://jsfiddle.net/7bpaL5hy/
const myValues = ['Decoration', 'Health', 'Fun', 'Yesterday 4'];
let myInd = 0;
function setValue() {
document.getElementById('bbb').value = myValues[myInd];
myInd = myInd >= (myValues.length - 1) ? 0 : myInd+1;
}
<form id="form1" name="form1" method="post">
<p>
<input type="button" name="set_Value" id="set_Value" value="submit" onclick="setValue()" />
</p>
<p>
<label>
<input type="text" name="bbb" id="bbb" />
</label>
</p>
</form>
You need to include the image tag and a list of images as an arrangement, please take a look at the following example
let init = 0;
const input = document.querySelector("input");
const img = document.querySelector("img");
const myValues = [
{
value: "Item 1",
image: "item-1.png",
},
{
value: "Item 2",
image: "item-2.png",
},
{
value: "Item 3",
image: "item-3.png",
},
{
value: "Item 4",
image: "item-4.png",
},
];
document.querySelector("form").addEventListener("submit", submitHandler);
function submitHandler(event) {
event.preventDefault();
const { value, image } = getCurrentValue();
input.value = value;
img.src = image;
img.alt = value;
updateInit();
}
function getCurrentValue() {
return myValues[init];
}
function updateInit() {
if (init < myValues.length - 1) {
init += 1;
} else {
init = 0;
}
}
<img src="" alt="" />
<form>
<input />
<button type="submit">Click</button>
</form>
A convenient way to relate values to their respective image is for both values to be properties of an object, so I changed myValues to an array of objects.
You will notice that only the value of the alt attribute is shown since there is no link with a real image. It still helps to demonstrate how it works.
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.