How to make a bunch of inputs disappear when clicking a button - javascript

I was trying to make a post sumbit page like reddit's but then i got a problem when trying to make the buttons work as expected for example: if i click the "post" button it will show a text area then when I click the "image & video" button it will delete the text area element and replaces it with an input (with attribute of type="file" ) It was working all fine until i added a third button that adds another input and works the same way, it didn't work as expected and it couldn't delete the previous inputs when clicked (the first two buttons are still working well but also they can't delete the third button's input)
so here is the code
//Normal text post part
document.getElementById('textarea-btn').addEventListener('click', function(event){
event.target.disabled = true;
document.getElementById('media').disabled = false;
document.getElementById('link-btn').disabled = false;
let textarea = document.createElement('textarea');
textarea.setAttribute('class', 'post-data');
textarea.setAttribute('id', 'textarea');
textarea.setAttribute('placeholder', 'Text (optional)');
document.querySelector('.post-content').appendChild(textarea);
//removing other inputs
let file = document.getElementById('file');
let link = document.getElementById('link')
document.querySelector('.post-content').removeChild(file);
document.querySelector('.post-content').removeChild(link);
});
//media post section
document.getElementById('media').addEventListener('click', function(event){
event.target.disabled = true;
document.getElementById('textarea-btn').disabled = false;
document.getElementById('link-btn').disabled = false;
let file = document.createElement('input');
file.setAttribute('class', 'post-data');
file.setAttribute('id', 'file');
file.setAttribute('type', 'file');
document.querySelector('.post-content').appendChild(file);
//removing other inputs
let textarea = document.getElementById('textarea');
let link = document.getElementById('link');
document.querySelector('.post-content').removeChild(textarea);
document.querySelector('.post-content').removeChild(link);
});
//Link section
document.getElementById('link-btn').addEventListener('click', function(event){
event.target.disabled = true;
document.getElementById('textarea-btn').disabled = false;
document.getElementById('media').disabled = false;
let link = document.createElement('input');
link.setAttribute('class', 'title-text');
link.setAttribute('id', 'link');
link.setAttribute('type', 'text');
link.setAttribute('placeholder', 'Link');
document.querySelector('.post-content').appendChild(link);
//removing other inputs
let file = document.getElementById('file');
let textarea = document.getElementById('textarea');
document.querySelector('.post-content').removeChild(file);
document.querySelector('.post-content').removeChild(textarea);
})
<div id="post-creator" class="creator-container">
<div class="post-type">
<button class="text-post" id="textarea-btn">Post</button>
<button class="media-post" id="media">Image & video</button>
<button class="link-post" id="link-btn">Link</button>
</div>
<div class="post-title">
<input type="text" class="title-text" name="post-title" placeholder="Title">
</div>
<div class="post-content">
</div>
<div class="post-footer">
<div class="spoiler">Spoiler</div>
<div class="nsfw">NSFW</div>
<button class="post">post</button>
</div>
</div>

The code shows errors on removeChild because it can not find the node under the element you are trying to remove. I would say try to check if the element exists before removing it.
Try running the following code if it works
<script>
el = document.getElementById('textarea-btn');
if(el)
{
//Normal text post part
el.addEventListener('click', function(event){
event.target.disabled = true;
document.getElementById('media').disabled = false;
document.getElementById('link-btn').disabled = false;
let textarea = document.createElement('textarea');
textarea.setAttribute('class', 'post-data');
textarea.setAttribute('id', 'textarea');
textarea.setAttribute('placeholder', 'Text (optional)');
document.querySelector('.post-content').appendChild(textarea);
//removing other inputs
let _file = document.getElementById('file');
let _link = document.getElementById('link')
let _div = document.querySelector('.post-content');
if(_div.contains(_file)){
_div.removeChild(_file);
}
if(_div.contains(_link)){
_div.removeChild(_link);
}
});
}
el = document.getElementById('media');
if(el)
{
//media post section
el.addEventListener('click', function(event){
event.target.disabled = true;
document.getElementById('textarea-btn').disabled = false;
document.getElementById('link-btn').disabled = false;
let file = document.createElement('input');
file.setAttribute('class', 'post-data');
file.setAttribute('id', 'file');
file.setAttribute('type', 'file');
document.querySelector('.post-content').appendChild(file);
//removing other inputs
let _textarea = document.getElementById('textarea');
let _link = document.getElementById('link');
let _div = document.querySelector('.post-content');
if(_div.contains(_textarea)){
_div.removeChild(_textarea);
}
if(_div.contains(_link)){
_div.removeChild(_link);
}
});
}
el = document.getElementById('link-btn');
if(el)
{
//Link section
el.addEventListener('click', function(event){
event.target.disabled = true;
document.getElementById('textarea-btn').disabled = false;
document.getElementById('media').disabled = false;
let link = document.createElement('input');
link.setAttribute('class', 'title-text');
link.setAttribute('id', 'link');
link.setAttribute('type', 'text');
link.setAttribute('placeholder', 'Link');
document.querySelector('.post-content').appendChild(link);
//removing other inputs
let _file = document.getElementById('file');
let _textarea = document.getElementById('textarea');
let _div = document.querySelector('.post-content');
if(_div.contains(_file)){
_div.removeChild(_file);
}
if(_div.contains(_textarea)){
_div.removeChild(_textarea);
}
});
}
</script>

Related

(Javascript) Checking if all input fields have been filled and activating a button afterwards

I have a group of dynamically generated input fields. I want to loop through all of them and check if the user has indeed written something on them. If all fields have been filled, activate the button, otherwise, desactivate it. Code is really long, so here is the most important part :
//Here is the loop that creates the number of inputs to create based on what the user enters:
(CourseObject.course_array).forEach((evaluation,value) => {
const percentage_value = CourseObject.each_evaluation_value[value];
//Some lists
const li_inputs = document.createElement('li');
li_inputs.id = ((`${evaluation}-of-${CourseName}-input-li`.replace(/°/g, "")).replace(/ /g, "")).toLocaleLowerCase();
li_inputs.className = "list-group-item";
(document.getElementById(`${CourseName}-input-ul`).appendChild(li_inputs));
//Here starts the important stuff, creation of the inputs and attributes
const text_input = document.createElement('input');
text_input.type = 'text';
text_input.placeholder = `Nota de ${evaluation} (${percentage_value}%)`;
text_input.id = ((`${evaluation}-of-${CourseName}-input-text`.replace(/°/g, "")).replace(/ /g, "")).toLocaleLowerCase();
text_input.className = 'form-control grade-input';
(document.getElementById(((`${evaluation}-of-${CourseName}-input-li`.replace(/°/g, "")).replace(/ /g, "")).toLocaleLowerCase())).appendChild(text_input);
}
);
//Creating the button
const SendAndShow = document.createElement('button');
SendAndShow.textContent = 'Calcular';
SendAndShow.id = 'send-and-show-button';
SendAndShow.disabled = true; //Desactivated from the beggining
SendAndShow.className = 'btn btn-dark';
document.getElementById('second-column').appendChild(SendAndShow);
//Here I want to loop through the inputs. If they are all filled, SendAndShow.disabled = false
//A random event set to be activated once the button is clicked
document.getElementById('send-and-show-button').onclick = function() {
.
. //Something to do
.
}
I have tried querySelectorAll and getting the element by class but I can't seem to be able to hack it, any suggestions?
Note : I would like a pure JS answer, no JQuery.
You can use the onchange method in every input element, then check the values of inputs with FormData
const form = document.querySelector('#form')
function getFormData() {
formData = new FormData(form)
console.log(formData.entries())
}
text_input.onchange = function(){
getFormData()
}
<form id='form'></form>
for dynamic element add listener to the parent or body then check your input elements
createInput.addEventListener('click', function() {
let input = document.createElement('input')
myform.prepend(input)
submit.setAttribute('disabled', '')
})
// the parent
myform.addEventListener('input', function(el) {
if (el.target.tagName != 'INPUT') return;
// chack all input
let allFilled = true
document.querySelectorAll('#myform input').forEach(function(input) {
if (!input.value)
allFilled = false;
})
// set the button state
if (allFilled)
submit.removeAttribute('disabled')
else
submit.setAttribute('disabled', '')
})
input{display:block;margin:10px;}
<button id="createInput">Create input</button><br><br>
<form id="myform">
<button id="submit" disabled>Submit</button>
</form>

How to loop over dynamically generated input fields?

I am generating some input fields dynamically on my page, and I want to grab inputs from them to store in localStorage if this way works if not? suggest a way around, how can this be done? also how can i add a event listener to submit button ? followings are code have a look at it and give some suggestions/improvisations.
..
HTML
<div id="warnMessage"></div>
<div class="add"></div>
<div class="inputs">
<input
type="text"
maxlength="1"
id="inputValue"
/>
<button class="btn" type="button">+</button>
</div>
javascript
const div = document.querySelector(".add");
const add = document
.querySelector(".btn")
.addEventListener("click", addingInps);
function addingInps() {
const inputValue = parseInt(document.getElementById("inputValue").value);
if (isNaN(inputValue)) {
document.getElementById("warnMessage").innerText = "Enter Again";
document.getElementById("inputValue").value = "";
} else {
const form = document.createElement("form");
form.method = "post";
form.action = "#";
for (let i = 0; i < inputValue; i++) {
const inp = document.createElement("input");
inp.type = "text";
inp.maxLength = "12";
inp.required = true;
inp.className = "inp";
const br = document.createElement("br");
form.appendChild(br.cloneNode());
form.appendChild(inp);
form.appendChild(br.cloneNode());
div.appendChild(form);
document.querySelector("#inputValue").style.display = "none";
}
const sub = document.createElement("button");
sub.className = "subButton";
sub.type = "button";
sub.value = "button";
sub.textContent = "Submit"
form.appendChild(sub);
}
}
You are loop through an input ...not an array or nodelist.
It cant work
I think it would be easier if you appended an ID with every new input field you made
for(let i=0;i < inputValue;i++){
// create your element ipt
ipt.setAttribute("id","autogenerated_" + i);
}
and grab value based on id
document.getElementById("autogenerated_x").value();
about setting an event listener, I can't think any other way of the classic
btn.addEventListener("click", function(e){
// your functionality
});

Using JS to generate a list of HTML elements. addEventListener only applying to last element [duplicate]

This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 3 years ago.
I have the following HTML written. The idea is that I can add items to the list at the top, and then generate a field which includes a name, checkbox, and text field. The text field is to be enabled/disabled depending on the checkbox. In my javascript, the toggle function is assigned to the onclick attribute of the checkbox field, but it only works on the last item on the list. Can anyone tell why this functionality isn't being assigned to all the checkboxes? If you open the resulting html code in a browser, it shows no onclick events for any checkboxes except the last one, so it appears it isn't being added. Does it somehow get removed from the previous one when I assign it to the next? How would I fix it? Thank you.
<!DOCTYPE html>
<html>
<body onload="loadAllSettings()" }>
<script>
var genOptFields = ["genField1", "genField2"];
function loadAllSettings() {
loadSettingsList("genSet", genOptFields);
}
</script>
<h2>Options</h2>
<form>
<fieldset id="genSet">
<legend>General</legend>
</fieldset>
</form>
<script>
function loadSettingsList(parentId, optionalFields) {
var fieldset = document.getElementById(parentId);
for (fieldId of optionalFields) {
var p = document.createElement('p');
p.append(fieldId + ":");
var input = document.createElement('input');
input.type = "text";
input.disabled = true;
input.id = fieldId;
var cb = document.createElement('input');
cb.type = "checkbox";
cb.id = "cb_" + fieldId;
cb.addEventListener("click", function () {
toggleCheck(fieldId);
});
p.appendChild(cb);
p.appendChild(input);
fieldset.appendChild(p);
}
}
function toggleCheck(fieldId) {
document.getElementById(fieldId).disabled = !document.getElementById("cb_" +
fieldId).checked;
}
</script>
</body>
</html>
As explained below, your fieldId reference isnt static. As a result when calling toggle check it was always passing the last value that fieldId contained no matter what (double check this by console.logging your fieldId passed to toggle check)
function loadAllSettings() {
const genOptFields = ["genField1", "genField2"];
loadSettingsList("genSet", genOptFields);
}
function loadSettingsList(parentId, optionalFields) {
const fieldset = document.getElementById(parentId);
optionalFields.forEach(function (fieldId) {
createParagraph(fieldId, fieldset);
});
}
function createParagraph(fieldId, fieldset) {
const p = document.createElement('p');
p.append(fieldId + ":");
createCheckbox(p, fieldId);
createInputField(p, fieldId);
fieldset.appendChild(p);
}
function createInputField(p, fieldId) {
const input = document.createElement('input');
input.type = "text";
input.disabled = true;
input.id = fieldId;
p.appendChild(input);
}
function createCheckbox(p, fieldId) {
const cb = document.createElement('input');
cb.type = "checkbox";
cb.id = "cb_" + fieldId;
//set this attribute to capture value
cb.setAttribute('data-fieldId', fieldId);
cb.addEventListener("click", function () {
//use static data attribute value instead of fieldId var which isnt static
toggleCheck(this.getAttribute('data-fieldId'));
});
p.appendChild(cb);
}
function toggleCheck(fieldId) {
document.getElementById(fieldId).disabled = !document.getElementById("cb_" + fieldId).checked;
}
<!DOCTYPE html>
<html>
<body onload="loadAllSettings()" }>
<h2>Options</h2>
<form>
<fieldset id="genSet">
<legend>General</legend>
</fieldset>
</form>
</body>
</html>
Since you are generating the element using body on-load event, click event become static. That is why element is always pointing to the last child. You can simply achieve your requirement by passing element scope(this) into the click event.
Here is the working solution:
<body onload="loadAllSettings()" }>
<script>
var genOptFields = ["genField1", "genField2"];
function loadAllSettings() {
loadSettingsList("genSet", genOptFields);
}
</script>
<h2>Options</h2>
<form>
<fieldset id="genSet">
<legend>General</legend>
</fieldset>
</form>
<script>
function loadSettingsList(parentId, optionalFields) {
var fieldset = document.getElementById(parentId);
for (fieldId of optionalFields) {
var p = document.createElement('p');
p.append(fieldId + ":");
var input = document.createElement('input');
input.type = "text";
input.disabled = true;
input.id = fieldId;
var cb = document.createElement('input');
cb.type = "checkbox";
cb.id = "cb_" + fieldId;
cb.addEventListener("click", function () {
toggleCheck(this);
});
p.appendChild(cb);
p.appendChild(input);
fieldset.appendChild(p);
}
}
function toggleCheck(ele) {
ele.nextElementSibling.disabled = !ele.checked;
}
</script>
</body>

Add onClick to an input being built by JavaScript

I have a file type input button that I am needing to clear completely if the user chooses to and the only safe solution I have found is to completely destroy the input and rebuild it. What I have right now works but it is a "Harp Gun" solution in that it only works once.
Basically, the user has a file input like so:
<input type="file" name="filesToUpload" id="filesToUpload" onChange="makeFileList();" />
<ul id="fileList"><li>No Files Selected</li></ul>
And when they select a file, they may need to clear that completely.
So I have this being built up via appending it on to the filelist:
function makeFileList() {
var input = document.getElementById("filesToUpload");
var ul = document.getElementById("fileList");
while (ul.hasChildNodes()) {
ul.removeChild(ul.firstChild);
}
for (var i = 0; i < input.files.length; i++) {
var li = document.createElement("li");
var fileSize = input.files[i].size;
li.innerHTML = input.files[i].name +" "+ "<span id=\"lblSize\"></span><input onclick=\"clearFileInput()\" type=\"button\" value=\"Clear\" \/>";
ul.appendChild(li);
}
if(!ul.hasChildNodes()) {
var li = document.createElement("li");
li.innerHTML = 'No Files Selected';
ul.appendChild(li);
}
};
And to completely destroy the file, the function rebuilds the input like so:
function clearFileInput(){
var oldInput = document.getElementById("filesToUpload");
var newInput = document.createElement("input");
newInput.type = "file";
newInput.id = oldInput.id;
newInput.name = oldInput.name;
newInput.className = oldInput.className;
newInput.style.cssText = oldInput.style.cssText;
// copy any other relevant attributes
oldInput.parentNode.replaceChild(newInput, oldInput);
};
So I can create the element, add the file type, and use the old input ID, class and name. But I need it to have the same onChange="makeFileList(); behavior as well.
Here is a FIDDLE. Any help is appreciated.
Simply add the attribute.
function clearFileInput(){
var oldInput = document.getElementById("filesToUpload");
var newInput = document.createElement("input");
newInput.type = "file";
newInput.id = oldInput.id;
newInput.name = oldInput.name;
newInput.className = oldInput.className;
newInput.style.cssText = oldInput.style.cssText;
newInput.setAttribute("onclick", "makeFileList()");
// copy any other relevant attributes
oldInput.parentNode.replaceChild(newInput, oldInput);
};
How about this:
function clearFileInput(){
var oldInput = document.getElementById("filesToUpload"),
newInput = document.createElement("input"),
eventHandler = oldInput.onchange;
newInput.type = "file";
newInput.id = oldInput.id;
newInput.name = oldInput.name;
newInput.className = oldInput.className;
newInput.style.cssText = oldInput.style.cssText;
// copy any other relevant attributes
oldInput.parentNode.replaceChild(newInput, oldInput);
newInput.onclick = eventHandler ;
};
Since you've tagged it jquery, you can use event-delegation.
$(document).on('change', '[name="filesToUpload"]', makeFileList);

HTML and JS : Capture Key Value pairs in HTML form

I have a Spring MVC application where I am required to capture a variable number of key value pairs based on user input. The HTML & JS part of the code to render the controls is as follows :
<tr>
<td><label>Attributes (Names & Value(s))</label></td>
<td><input id="Button1" type="button" value="Add" onclick="Button1_onclick()"/></td>
</tr>
<script language="javascript" type="text/javascript">
var NumOfRow = 1;
var attribs = {};
function Button1_onclick() {
NumOfRow++;
// get the reference of the main Div
var mainDiv = document.getElementById('MainDiv');
// create new div that will work as a container
var newDiv = document.createElement('div');
newDiv.setAttribute('id', 'innerDiv' + NumOfRow);
//create span to contain the text
var newSpan = document.createElement('span');
newSpan.innerHTML = "Attribute Type";
// create new textbox for type entry
var newTextBox = document.createElement('input');
newTextBox.type = 'text';
newTextBox.setAttribute('id', 'DimensionType' + NumOfRow);
//create span to contain the text
var newSpan2 = document.createElement('span');
newSpan2.innerHTML = "Attribute Value(s)";
// create new textbox for value entry
var newTextBox2 = document.createElement('input');
newTextBox2.type = 'text';
newTextBox2.setAttribute('id', 'DimensionValue' + NumOfRow);
// create remove button for each attribute
var newButton = document.createElement('input');
newButton.type = 'button';
newButton.value = 'Remove';
newButton.id = 'btn' + NumOfRow;
// attach event for remove button click
newButton.onclick = function RemoveEntry() {
var mainDiv = document.getElementById('MainDiv');
mainDiv.removeChild(this.parentNode);
NumOfRow--;
}
// append the span, textbox and the button
newDiv.appendChild(newSpan);
newDiv.appendChild(newTextBox);
newDiv.appendChild(newSpan2);
newDiv.appendChild(newTextBox2);
newDiv.appendChild(newButton);
// finally append the new div to the main div
mainDiv.appendChild(newDiv);
}
}
</script>
I am not sure how to send this captured data back to my controller when the form is submitted. Please advise. Also if there is a better way to capture such data, those suggestions are most welcome as well.
What about making Capture key event in a text field you can do this :
<html>
<head>
<script language="JavaScript" type = "text/javascript">
<!--
document.onkeypress = DisplayMsg;
function DisplayMsg(key_event)
{
if (document.all) //Checks for IE 4.0 or later
{
document.form1.text2.value = String.fromCharCode(event.keyCode);
}
else if (document.getElementById) //checks for Netscape 6 or later
{
document.form1.text2.value = String.fromCharCode(key_event.which);
}
else if (document.layers) //Checks for Netscape 4
{
document.form1.text2.value = String.fromCharCode(key_event.which);
}
}
//-->
</script>
<title>Capture Key Pressed</title>
</head>
<body>
<form name="form1">
<b>Type value in field: See what you typed:</b><br>
<input type = "text" name = "text1" onKeyPress="DisplayMsg(event)" size="20">
<input type = "text" name = "text2" onKeyPress="DisplayMsg(event)" size="20">
</form>
</body>
</html>

Categories

Resources