Prevent HTML element reload when concatenating HTML using innerHTML - javascript

I have a form having two input fields:
<form id="import-products-form">
<div class="form-row">
<select></select>
<input>
</div>
</form>
And a button:
<button id="add-input-button"><strong>+</strong></button>
Everytime the button is clicked, two input fields will be added to the form:
document.getElementById("add-input-button").onclick = () => {
const input = `
<div class="form-row">
<select></select>
<input>
</div>
`;
document.getElementById("import-products-form").innerHTML += input;
};
The problem here is whenever the button is clicked, the values of the existed fields will be reset to default. In DevTools, I saw that the entire form was reloaded when the button clicked.
Is there anyway to keep the values of the existed fields when new fields added to the form?

Don't assign to innerHTML. That causes all the elements inside the form to be recreated from scratch, and any dynamic state is lost.
Use insertAdjacentHTML instead. This parses the new HTML and appends the DOM elements, without disturbing the original elements.
document.getElementById("import-products-form").insertAdjacentHTML('beforeend', input);

x.innerHTML += input effectively runs
x.innerHTML = (x.innerHTML + input) and you lose the state
You should create new element and append it.
document.getElementById("add-input-button").onclick = (e) => {
const input = `
<select></select>
<input>
`;
let div = document.createElement('div')
div.classList.add('form-row')
div.innerHTML=input
document.getElementById("import-products-form").appendChild(div)
};
<form id="import-products-form">
<div class="form-row">
<select></select>
<input>
</div>
</form>
<button id="add-input-button"><strong>+</strong></button>
For this specific use case, no need to create element from text every time.
{
const input = `
<select></select>
<input>
`;
let div = document.createElement('div')
div.classList.add('form-row')
div.innerHTML=input
document.getElementById("add-input-button").onclick = (e) => {
document.getElementById("import-products-form").appendChild(div.cloneNode(true))
};
}
<form id="import-products-form">
<div class="form-row">
<select></select>
<input>
</div>
</form>
<button id="add-input-button"><strong>+</strong></button>

Try using appendChild instead of innerHTML.
document.getElementById("add-input-button").onclick = () => {
var div = document.createElement('div');
var select = document.createElement('select');
var input = document.createElement('input');
div.classList.add('form-row');
div.appendChild(select);
div.appendChild(input);
document.getElementById("import-products-form").appendChild(div);
};
<form id="import-products-form">
<div class="form-row">
<select></select>
<input>
</div>
</form>
<button id="add-input-button"><strong>+</strong></button>

Related

How to get the innerHTML of an input in Java script

I am making a TODO list. I have difficulties with setting the input text on my card. Everything I write in the input, I want to select and to put on the card.
I tried to select the innerHTML of an input when I type something in. I don't know how to select the typed input text. I would then create a new element with the text inside, and would append it to the card.
let btn = document.querySelector('.add');
let textspace = document.querySelector('.todotext');
const input = document.querySelector('input');
// eventlistner by button clicked
btn.addEventListener('click', function() {
var txt = document.getElementsByClassName('input').innerHTML;
});
<div class="card">
<div class="todoheader">TODO List</div>
<div class="todotext"></div>
<ul class="list"></ul>
<div class="addtodo">
<buton class="add" type="button"> + </buton>
<input type="text" class="input" placeholder="add todo" />
</div>
</div>
To get the value of the input use the value property, not innerHTML. Also note that you already have a reference to the input Element in the input variable, so you don't need to use getElementsByClassName() to retrieve it - not least of all because the syntax there is flawed.
Once you have the text you can use createElement() to add a new p element to the .todotext container:
const btn = document.querySelector('.add');
const textspace = document.querySelector('.todotext');
const input = document.querySelector('input');
btn.addEventListener('click', function() {
const txt = input.value;
if (!txt)
return;
const p = document.createElement('p');
p.textContent = txt;
textspace.appendChild(p);
input.value = '';
});
<div class="card">
<div class="todoheader">TODO List</div>
<div class="todotext"></div>
<ul class="list"></ul>
<div class="addtodo">
<button class="add" type="button"> + </button>
<input type="text" class="input" placeholder="add todo" />
</div>
</div>
As others already answered your question. I just wanted to point out that there is a misspelling in your code (buton instead of button). Fix that and the button element would be rendered correctly.
First, getElementsByClassName will return HTMLCollection which is array-like, you need to use querySelector instead, also the innerHTML, textContent, innerText properties all are empty string for the input because the input is a self-closing tag without content inside, you need to use value property.
let btn = document.querySelector('.add');
let textspace = document.querySelector('.todotext');
const input = document.querySelector('input');
// eventlistner by button clicked
btn.addEventListener('click', function() {
var txt = input.value;
console.log(txt)
});
<div class="card">
<div class="todoheader">TODO List</div>
<div class="todotext"></div>
<ul class="list"></ul>
<div class="addtodo">
<buton class="add" type="button"> + </buton>
<input type="text" class="input" placeholder="add todo" />
</div>
</div>
btn.addEventListener('click', function() {
var txt = document.getElementByClassName('input').value;
});
You were using getElementByClassName which will be HTMLCollection.To loop over each element you need to convert it into an array loop over them.
var txt = document.getElementsByClassName('input').value;
You should get the value of an input , not the innerHTML
Also assign a unique id to you input fields and select them with it, it's much better :)

Cannot read properties of 'null' (reading appendChild)

Can anyone tell me what is wrong with my code? This works for all the other elements on the page but not this one, which is the parent to all of them.
let addButton = document.querySelector('.add-note');
addButton.addEventListener('click', (event) => {
//prevent refresh
event.preventDefault();
//note input value
let noteInput = document.querySelector(".note-input");
//create note container
let noteList = document.querySelector(".notes");
//create note
let note = document.createElement("li");
note.classList.add("note");
noteList.appendChild(note);
});
<div class="title">
<h1>To Do List</h1>
</div>
<br>
<form>
<div class="add-note">
<input class="note-input" type="text" placeholder="Enter to-do item here"></input>
<button class="add" type="submit">+</button>
</div>
</form>
<br>
<ul className="notes" id="notes"></ul>
Is this a React project? className is only available when using React.
<ul className="notes" id="notes"></ul>
change to
<ul class="notes" id="notes"></ul>
Your question i a tad unclear, but i think part of it is that you added the event listener to the div instead of the submit button. Change the class in your query selector to ".add" instead of ".add-note".

Laravel Blade : how do i make textarea show on clicking add more

I have this school application, I want to add 100 questions to the database, the normal thing done is add, one after the other., that is I will click submit 100 times....exhausting right.... Now, I want to create an application that I will have to query the database once, that is the submit button will have an add more button beside, but if I click to add more, it should make another text area show below......but if I click save, it should save to the database
<form method="post" action={{route('save.question', $subject->slug)}} >
#csrf
<textarea name="questions"></textarea>
<button type='submit'>Submit</button>
<button type=''>Add more question</button>
</form>
There's some approaches, but I prefer:
If click on Add more question button, add a textarea input to DOM
If click on Submit, add all textarea values to a javascript array
Stringify the array
Send it into an input that hidden
Decode that input value in PHP with json_decode()
So:
let questionsContainer = document.querySelector("#questions-container");
let addQuestionTextarea = document.querySelector("#add-question-textarea");
addQuestionTextarea.onclick = () => {
let textarea = document.createElement("textarea");
questionsContainer.appendChild(textarea);
}
let submit = document.querySelector("#submit");
submit.onclick = () => {
collectValues();
}
function collectValues(){
let allTextareas = questionsContainer.getElementsByTagName('textarea');
allTextareas = [...allTextareas]
let allValues = [];
allTextareas.forEach((textarea)=>{ allValues.push(textarea.value) });
document.getElementById('questions-array').value = JSON.stringify(allValues);
document.getElementById("form").submit();
}
textarea{
display:block;
margin: 8px;
}
<div id="questions-container">
<textarea></textarea>
</div>
<button id="add-question-textarea">Add more question</button>
<form method="post" action={{route('save.question', $subject->slug)}} id="form">
#csrf
<input type="text" id="questions-array" hidden name="questions">
</form>
<button id="submit">Submit</button>

if i add more than one element then why previous is deleted (only Answer in Plan Javascript) [duplicate]

I have a form having two input fields:
<form id="import-products-form">
<div class="form-row">
<select></select>
<input>
</div>
</form>
And a button:
<button id="add-input-button"><strong>+</strong></button>
Everytime the button is clicked, two input fields will be added to the form:
document.getElementById("add-input-button").onclick = () => {
const input = `
<div class="form-row">
<select></select>
<input>
</div>
`;
document.getElementById("import-products-form").innerHTML += input;
};
The problem here is whenever the button is clicked, the values of the existed fields will be reset to default. In DevTools, I saw that the entire form was reloaded when the button clicked.
Is there anyway to keep the values of the existed fields when new fields added to the form?
Don't assign to innerHTML. That causes all the elements inside the form to be recreated from scratch, and any dynamic state is lost.
Use insertAdjacentHTML instead. This parses the new HTML and appends the DOM elements, without disturbing the original elements.
document.getElementById("import-products-form").insertAdjacentHTML('beforeend', input);
x.innerHTML += input effectively runs
x.innerHTML = (x.innerHTML + input) and you lose the state
You should create new element and append it.
document.getElementById("add-input-button").onclick = (e) => {
const input = `
<select></select>
<input>
`;
let div = document.createElement('div')
div.classList.add('form-row')
div.innerHTML=input
document.getElementById("import-products-form").appendChild(div)
};
<form id="import-products-form">
<div class="form-row">
<select></select>
<input>
</div>
</form>
<button id="add-input-button"><strong>+</strong></button>
For this specific use case, no need to create element from text every time.
{
const input = `
<select></select>
<input>
`;
let div = document.createElement('div')
div.classList.add('form-row')
div.innerHTML=input
document.getElementById("add-input-button").onclick = (e) => {
document.getElementById("import-products-form").appendChild(div.cloneNode(true))
};
}
<form id="import-products-form">
<div class="form-row">
<select></select>
<input>
</div>
</form>
<button id="add-input-button"><strong>+</strong></button>
Try using appendChild instead of innerHTML.
document.getElementById("add-input-button").onclick = () => {
var div = document.createElement('div');
var select = document.createElement('select');
var input = document.createElement('input');
div.classList.add('form-row');
div.appendChild(select);
div.appendChild(input);
document.getElementById("import-products-form").appendChild(div);
};
<form id="import-products-form">
<div class="form-row">
<select></select>
<input>
</div>
</form>
<button id="add-input-button"><strong>+</strong></button>

Simple Javascript front-end message board design

I am working on a personal blog website project, and I wanted to implement a simple message board on my index page. Due to the projected site traffic (relatively low) I decided on only using a front-end implementation without linking to a database with the following js and html code:
<section class="message-board">
<div class="title">
<h2>
Leave a message
</h2>
</div>
<textarea class="message" type="text"></textarea><br/>
<input value="submit" type="button" class="submit-btn">
<div class="display-area">
Existing comment:
</div>
</section>
and then the js,
<script>
window.onload=function() {
var displayArea = document.getElementsByClassName("display-area");
var btn = document.getElementsByClassName("submit-btn");
btn.onclick = function() {
var comment = document.getElementsByClassName("message").value;
displayArea.appendChild(comment);
};
}
</script>
My intention was to make my display-area contain whatever was put in textarea via .appendChild when submit is clicked. Sadly, it isn't working as intended-nothing actually happens. I am thinking about potential errors in my js code, but just couldn't figure out anything that would resolve the problem.
Any assistance will be greatly appreciated!!!
getElementsByClassName() returns a collection of elements (note the s in Elements). If you have only one element that matches the class name, you have this element in the first index of the array-like collection.
var displayArea = document.getElementsByClassName("display-area")[0];
var btn = document.getElementsByClassName("submit-btn")[0];
You can also use querySelector(), that uses CSS selectors (like jQuery) and returns a single element:
var displayArea = document.querySelector(".display-area");
In order to append a text node (your variable comment stores a string), use append() instead of appendChild():
displayArea.append(comment);
Two ways this can be done are by calling the JavaScript function on click, or by calling it on form submission.
1) call function onclick:
Wrap your form within a form tag, and call your JavaScript function based on the element Ids.
Note the showInput function is being called onclick when the button is clicked.
function showInput() {
console.log('showInput called...')
var userInput = document.getElementById("userInput").value;
var display = document.getElementById("display");
display.innerHTML = userInput;
}
<section class="message-board">
<div class="title">
<h2>
Leave a message
</h2>
</div>
<form>
<textarea class="message" type="text" id="userInput"></textarea><br/>
</form>
<input type="submit" onclick="showInput();">
<div class="display-area">
Existing comment:
</div>
<p><span id="display"></span></p>
</section>
Here's a jsfiddle, with the same code as above: http://jsfiddle.net/ethanryan/94kvj0sc/
Note the JavaScript in the jsfiddle is being called at the bottom of the Head section of the HTML.
2) call function on form submit:
You can also do this by calling the JavaScript function on the submission of the form, instead of on the click of the button. However, since this form uses a textarea, hitting return will add a line break to the text, and not submit the form, so the button still needs to be clicked for the function to be called.
function showInput() {
console.log('showInput called...')
event.preventDefault()
var userInput = document.getElementById("userInput").value;
var display = document.getElementById("display");
display.innerHTML = userInput;
}
<section class="message-board">
<div class="title">
<h2>
Leave a message
</h2>
</div>
<form onsubmit="showInput()">
<textarea class="message" type="text" id="userInput"></textarea><br/>
<input type="submit" value="Submit">
</form>
<div class="display-area">
Existing comment:
</div>
<p><span id="display"></span></p>
</section>
Note the event.preventDefault() in the form, since the default behavior of forms is to submit data to a backend database.
jsfiddle: http://jsfiddle.net/ethanryan/qpufd469/
3. appending instead of replacing text
Finally, my examples above used innerHTML to replace the userInput text. If you want to append instead of replace the text, you can use insertAdjacentHTML to add the text to the end, and then append a linebreak to it. Finally, you can reset the form.
function showInput() {
console.log('showInput called...')
event.preventDefault()
var userInput = document.getElementById("userInput").value;
var display = document.getElementById("display");
var theForm = document.getElementById("theForm");
var linebreak = document.createElement("br");
display.insertAdjacentHTML('beforeend', userInput);
display.appendChild(linebreak);
theForm.reset();
}
<section class="message-board">
<div class="title">
<h2>
Leave a message
</h2>
</div>
<form onsubmit="showInput()" id="theForm">
<textarea class="message" type="text" id="userInput"></textarea><br/>
<input type="submit" value="Submit">
</form>
<div class="display-area">
Existing comment:
</div>
<p><span id="display"></span></p>
</section>
jsfiddle: http://jsfiddle.net/ethanryan/x4hq0Lzp/

Categories