So I have this code in ejs to load all the item in the menu table in MongoDB to the front-end
<form action="/order" method="post">
<div class="food-container">
<% for(i = 0; i < menu.length; i++){ %>
<label for="name"><%= menu[i].name %></label>
<input
type="text"
value="<%= menu[i].name %>"
name="menu[<%= [i] %>][name]"
class="name"
id="name"
hidden
/>
<input
type="number"
name="menu[<%= [i] %>][quantity]"
id="name"
min="0"
value="0"
class="input"
/>
<% } %>
<textarea name="notes" id="notes" cols="30" rows="10"></textarea>
</div>
<button type="submit">Order</button>
</form>
now I want to add a text below the form everytime a value for one of the number input is changed to mark a new order item. so I use this in the script tag
const input = document.querySelectorAll(".input");
const name = document.querySelectorAll(".name");
const container = document.querySelector(".food-container");
for (i = 0; i < input.length; i++) {
const name1 = name[i].value.replaceAll(" ", "-");
input[i].addEventListener("change", function (evt) {
const className = document.querySelectorAll(`.${name1}`);
if (parseInt(this.value) == 1 && className.length === 0) {
const className = document.querySelector(`.${name1}`);
const div = document.createElement("div");
const h1 = `<h5 class="${name1}">${name1} X1</h5>`;
div.innerHTML = h1;
container.appendChild(div);
} else if (parseInt(this.value) >= 1){
const className = document.querySelector(`.${name1}`);
className.innerHTML = `<h5 class="${name1}">${name1} X${this.value}</h5>`;
} else {
const className = document.querySelector(`.${name1}`);
className.remove();
}
});
the code above loop through all the text input length and add an event listener to each of the element so if there isn't a h5 element with the item name class it will make a new h5 element and if the number input goes back to 0 it will remove the h5 element with the corresponding class name. I'm wondering if there's a more shorter and elegant way to do this because I know this code is very very confusing and spaghetti-like
Related
I'm working on a TO DO List.
here's the HTML body-
<div class="cardDiv">
<input type="text" class="titleText" placeholder="Today's Battle Plans🤠">
<div class="taskList">
<div class="indiv-task task1">
<input type="checkbox" class="checkBox">
<input type="text" class="textBox" placeholder="task1">
</div>
</div>
<button class="addTask-btn" onclick="addTask()">Add More Tasks</button>
</div>
<script src="index.js"></script>
Basically, the button at the end adds a code block for a new task each time the button gets pressed as per this JS code-
let taskList = document.querySelector(".taskList");
let taskCode = '<div class="indiv-task"> <input type="checkbox" class="checkBox"> <input type="text" class="textBox" placeholder="task1"> </div>';
function addTask() {
taskList.innerHTML += taskCode;
let taskListLength = document.querySelectorAll(".indiv-task").length;
for(i=0; i<taskListLength; i++) {
document.querySelectorAll(".textBox")[i].placeholder = "task"+(i+1);
document.querySelectorAll(".indiv-task")[i].classList.add("task"+(i+1));
}
}
But the problem is that whenever the button is pressed all the input text in textBox(es) gets erased. Is there a way I can avoid that, or is it possible only with databases?
PS- I'm still on my learning path...
Like what epascarello said we need to create an element and add it to the taskList element and not use innerHTML to add elements.
let taskList = document.querySelector(".taskList");
let taskHTML = '<input type="checkbox" class="checkBox"> <input type="text" class="textBox" placeholder="task1">';
function addTask() {
let taskCode = document.createElement("DIV");
taskCode.innerHTML = taskHTML;
taskCode.classList.add("indiv-task")
taskList.appendChild(taskCode)
let taskListLength = document.querySelectorAll(".indiv-task").length;
for(i=0; i<taskListLength; i++) {
document.querySelectorAll(".textBox")[i].placeholder = "task"+(i+1);
document.querySelectorAll(".indiv-task")[i].classList.add("task"+(i+1));
}
}
This means that the innerHTML for the taskList element is not reset to have empty text boxes, rather, it just adds another element.
This is because the innerHTML will replace the current html of the element. You can try with:
function addTask() {
const taskList = document.querySelector(".taskList");
const taskCode = '<div class="indiv-task"> <input type="checkbox" class="checkBox"> <input type="text" class="textBox" placeholder="task1"> </div>';
const taskCodeDocument = new DOMParser().parseFromString(taskCode, "text/html");
const taskCodeChild = taskCodeDocument.body.firstChild;
taskList.appendChild(taskCodeChild);
let taskListLength = document.querySelectorAll(".indiv-task").length;
for (i = 0; i < taskListLength; i++) {
document.querySelectorAll(".textBox")[i].placeholder = "task" + (i + 1);
document.querySelectorAll(".indiv-task")[i].classList.add("task" + (i + 1));
}
}
ref: https://developer.mozilla.org/en-US/docs/Web/API/DOMParser/parseFromString
& https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML
My goal is that only 15 quantities of input elements can be accepted, once the user enters 16 it should say that only 15 input elements is allowed. However I don't know how will I do this. I tried putting condition inside for but it is not not working. I am a little bit confused on this
Here is my HTML code
<div class="form-group">
<label> Quantity: </label>
<input class="form-control" name="quantity" type="number" id="get_Elem"
required>
<br>
<input type="button" id="sb_add_ctrl" name="is_Sub" class="btn btn-
primary" value="Add Control Number">
</div>
<div class="form-group" name="parent" id="parent"></div>
Here is my JS code
$(document).on('click', '#sb_add_ctrl', function() {
var element = $('#get_Elem').val();
var input;
var parent = $(document.getElementById("parent"));
var value = $('#sel_control_num').val();
functionPopulate(parent);
if (isNaN(element)) {
return;
}
for (var i = 0; i < element; i++) {
if(should I do it here??){
}
value = value.replace(/(\d+)$/, function(match, element) {
const nextValue = ++match;
return ('0' + nextValue).slice(1);
});
document.getElementById("parent").style.padding = "5px 0px 0px 0px";
document.getElementById("parent").innerHTML += '<br><input type="text"
value="' + value +
'" class="form-control" name="get_Input_show[]" required>'
}
});
You can check if the element value is < 16 if yes then only add html else show error message.
Demo Code :
$(document).on('click', '#sb_add_ctrl', function() {
var element = $('#get_Elem').val();
var input;
//var value = $('#sel_control_num').val();
var value = 12;
//functionPopulate(parent);
if (isNaN(element)) {
return;
}
//check if elemnt value if < 16
if (element < 16) {
$("#parent").empty() //empty div
for (var i = 0; i < element; i++) {
/* value = value.replace(/(\d+)$/, function(match, element) {
const nextValue = ++match;
return ('0' + nextValue).slice(1);
});*/
document.getElementById("parent").style.padding = "5px 0px 0px 0px";
document.getElementById("parent").innerHTML += '<br><input type="text" value = "' + value + '" class="form-control" name="get_Input_show[]" required>';
}
} else {
alert("only 15") //show error
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="form-group">
<label> Quantity: </label>
<input class="form-control" name="quantity" type="number" id="get_Elem" required>
<br>
<input type="button" id="sb_add_ctrl" name="is_Sub" class="btn btn-
primary" value="Add Control Number">
</div>
<div class="form-group" name="parent" id="parent"></div>
There are two ways in which you can restrict it
You can use maxLength property of an input tag, which will restrict the user to input the 16th character.
You can keep checking the value in the input field and show error if the length is more than 15 character. To do this you can use onkeypress event on input, like
HTML
<input type="text" id="test" onkeypress="test()" />
JS:
<script>
function test() {
alert('Hi')
}
</script>
I have 1 input. And it has to print out 2 outputs 1 with -1 to the output and the other with -2. But the output doesn't show anything. can someone tell me what I'm doing wrong here.
Code:
// Meters en Centimeters value
function updateTotal() {
const list = document.getElementsByClassName("AutosubmitCalculator");
const values = [];
for (let i = 0; i < list.length; ++i) {
values.push(parseFloat(list[i].value));
}
let total = values.reduce(function(previousValue, currentValue) {
return previousValue + currentValue;
});
document.getElementById("schermentotaal").value = total - 2;
document.getElementById("schermentotaal2").value = total - 1;
}
HTML Input:
<div class="InputField InputMeters">
<input type="tel" name="iFenceMeters" id="FenceMeters" class="AutosubmitCalculator" data-minimum-length="1" tabindex="1" placeholder="00" maxlength="3" value="">
<div class="FormExclamation Tipped Hidden" id="FormCalculatorExclamationFence">0</div>
</div>
HTML Output:
<div class="SummaryRow">
<strong>Schermen</strong>
<input name="schermentotaal" type="text" id="schermentotaal" value=""></input>
</div>
<div class="SummaryRow">
<strong>Palen en onderplaten</strong>
<input name="schermentotaal2" type="text" id="schermentotaal2" value=""></input>
</div>
Thanks in advance :D
You're not calling your updateTotal anywhere. I suggest you run this function on the oninput event on your input field. This will make it so that whenever you enter a number it will run the function updateTotal.
You also have some additional errors, such as you are trying to get the element with the id total but don't have an element with this id in your HTML.
document.getElementById("total").value
I've changed this to be schermentotaal2 which is a valid id in your HTML:
document.getElementById("schermentotaal2").value
See working example below:
function updateTotal() {
const list = document.getElementsByClassName("AutosubmitCalculator");
const values = [];
for (let i = 0; i < list.length; i++) {
values.push(parseFloat(list[i].value));
}
let total = values.reduce(function(previousValue, currentValue) {
return previousValue + currentValue;
});
document.getElementById("schermentotaal").value = (total - 2) || '';
document.getElementById("schermentotaal2").value = (total - 1) || '';
}
<div class="InputField InputMeters">
<input type="tel" name="iFenceMeters" id="FenceMeters" class="AutosubmitCalculator" data-minimum-length="1" tabindex="1" placeholder="00" maxlength="3" value="" oninput="updateTotal()" />
<div class="FormExclamation Tipped Hidden" id="FormCalculatorExclamationFence">0</div>
</div>
<div class="SummaryRow">
<strong>Schermen</strong>
<input name="schermentotaal" type="text" id="schermentotaal" value="" />
</div>
<div class="SummaryRow">
<strong>Palen en onderplaten</strong>
<input name="schermentotaal2" type="text" id="schermentotaal2" value="" />
</div>
Also, if you only have one input you may want to reconsider using a class to get the input value for this as you don't require a loop to get the value from one input field.
I need help extending this JavaScript (borrowed from https://www.quirksmode.org/dom/domform.html):
var appCounter = 0;
function anotherApp() {
appCounter = appCounter + 1;
var newAppField = document.getElementById("keyApp").cloneNode(true);
newAppField.id = '';
newAppField.style.display = 'block';
var newApp = newAppField.childNodes;
for (var i = 0; i < newApp.length; i++) {
var theName = newApp[i].name
if (theName) {
newApp[i].name = theName + appCounter;
}
}
var insertApp = document.getElementById('keyApp');
insertApp.parentNode.insertBefore(newAppField, insertApp);
document.getElementById('appCount').value = appCounter
}
This works fine when element in my form is:
<div id="keyApp" style="display:none">
<input type="text" name="application" id="application">
<input type="text" name="usage" id="usage">
<\div>
But when I add div's around the inputs (bootstrap styling reasons) I loose the ability to update the input names:
<div id="keyApp" style="display:none">
<div class="col-md-2">
<input type="text" name="application" id="application">
</div>
<div class="col-md-2">
<input type="text" name="usage" id="usage">
</div>
<\div>
How do I extend the script to modify the input names in these new div's?
Since there is now another layer, you need to get newApp[i].childNodes[0] now in order to get the actual input elements.
newApp now holds a list of the div elements with col-md-2 styling, and you need to get the children inside of these div elements.
I apologize for the wordy title but I haven't found a solution to my problem yet. I am a newbie with jQuery and web development so any guidance would be appreciated.
I have a <input> that allows user to enter a value (number) of how many rows of a set of input fields they want populated. Here's my example:
<div id="form">
<input id="num" name="num" type="text" />
</div>
<p> </p>
<div id="form2">
<form action="" method="post" class="form_main">
<div class="data">
<div class="item">
<input id="name" name="name[]" type="text" placeholder="name" /><br/>
<input id="age" name="age[]" type="text" placeholder="age" /><br/>
<input id="city" name="city[]" type="text" placeholder="city" /><br/>
<hr />
</div>
</div>
<button type="submit" name="submit">Submit</button>
</form>
My jQuery:
<script>
var itemNum = 1;
$("#num").on("change", function() {
var count = this.value;
var item = $(".item").parent().html();
//item.attr('id', 'item' + itemNum);
for(var i = 2; i <= count; i++) {
itemNum++;
$(".data").append(item);
}
})
</script>
I'm having problems adding an ID item+itemNum increment to <div class="item">... item.attr() didn't work. It doesn't append once I added that line of code.
Also, how can I get it so that once a user enters a number that populates rows of input fields, that if they change that number it will populate that exact number instead of adding to the already populated rows? Sorry if this doesn't make any sense. Please help!
Here is a DEMO
var itemNum = 1;
$("#num").on("change", function() {
$('.data div').slice(1).remove(); //code for removing previously populated elements.
var count = this.value;
console.log(count);
var item;
//item.attr('id', 'item' + itemNum);
var i;
for(i = 1; i <= count; i++) {
console.log(i);
item = $("#item0").clone().attr('id','item'+itemNum);
//prevent duplicated ID's
item.children('input[name="name[]"]').attr('id','name'+itemNum);
item.children('input[name="age[]"]').attr('id','age'+itemNum);
item.children('input[name="city[]"]').attr('id','city'+itemNum);
itemNum++;
$(".data").append(item);
}
})
Use clone() instead of html()
Try
var itemNum = 1,
item = $(".data .item").parent().html();;
$("#num").on("change", function () {
var count = +this.value;
if (itemNum < count) {
while (itemNum < count) {
itemNum++;
$(item).attr('id', 'item' + itemNum).appendTo('.data')
}
} else {
itemNum = count < 1 ? 1 : count;
$('.data .item').slice(itemNum).remove();
}
})
Demo: Fiddle