Javascript: Avoid refreshing page after submit [duplicate] - javascript

This question already has answers here:
How do I make an HTML button not reload the page
(10 answers)
Closed 1 year ago.
my knowledge in Javascript is basic.
I'm trying to run a function when clicking the button submit, but when I do the page shows for a fraction of a second the result in the webpage but then it refreshes automatically showing the page in blank again. Any idea on how to fix this? Thanks in advance.
HTML
<section class="container-form">
<div>
<p>
Por favor ingresar los datos de tu préstamo para hacer el cálculo.
</p>
</div>
<form action="" id="form">
<input type="number" name="capital" id="capital" placeholder="Capital Inicial $">
<input type="number" name="rate" id="rate" placeholder="Tasa de Interés Anual %">
<input type="number" name="periods" id="periods" placeholder="Cantidad de cuotas">
<div>
<label for="frequency">Frecuencia de las cuotas</label>
<select name="frequency" id="frequency">
<option value="monthly">Mensual</option>
</select>
</div>
<div class="container-btn">
<input type="submit" id="btnSubmit" class="submit" onclick="calculateAnnuity()">
</div>
</form>
</section>
<section class="container-table">
<table id="table-results" class="table">
<thead>
<tr>
<th>Nº</th>
<th>Cuota</th>
<th>Interés</th>
<th>Capital</th>
<th>Saldo</th>
</tr>
</thead>
<tbody></tbody>
</table>
</section>
JS
// Declarar variables
let capital;
let rate;
let frequency;
let periods;
let btnSubmit;
let tableResults;
// Asignar valores a variables desde el form
capital = document.getElementById('capital');
rate = document.getElementById('rate');
frequency = document.getElementById('frequency');
periods = document.getElementById('periods');
btnSubmit = document.getElementById('btnSubmit');
tableResults = document.querySelector('#table-results tbody')
// Disparador de funcións
/* btnSubmit.addEventListener('click',() => {
calculateAnnuity(capital.value, rate.value, frequency.value, periods.value)
}) */
function calculateAnnuity (capital, rate, frequency, periods) {
// Declarar variables
let annuity = 0;
let actualCapital = capital;
let interestFee = 0;
let capitalFee = 0;
// Calculo de cuota
annuity = capital * (rate/100/12)
/
(1-Math.pow(1+rate/100/12,-periods));
console.log(typeof(capital)+" "+typeof(rate)+" "+typeof(periods)+" "+typeof(annuity))
for(let i = 0; i <= periods; i++) {
const row = document.createElement('tr');
row.innerHTML = `
<td>${i}</td>
<td>${parseFloat(annuity).toFixed(2)}</td>
<td>${parseFloat(interestFee).toFixed(2)}</td>
<td>${parseFloat(capitalFee).toFixed(2)}</td>
<td>${parseFloat(actualCapital).toFixed(2)}</td>
`
switch (frequency) {
case 'monthly':
interestFee = actualCapital * rate/100/12;
default:
continue;
}
capitalFee = annuity - interestFee;
actualCapital = actualCapital - capitalFee;
console.log(actualCapital);
tableResults.appendChild(row)
}
}

Form events comes with event or just e for intimates.
at your form action in javascript, you can use e.preventDefault(); function, to prevents browser to refresh when form is submited.

Related

JavaScript not found [object HTMLSpanElement], how i can fix that

"use strict";
let btn = document.getElementById("buttonCarrito");
btn.addEventListener("click",agregar);
//this function is agregar (add in English), the idea is that this function put the elements Manzana (Apple) in the shop cart but when i try do this i get [object HTMLSpanElement]50 (50 is the Apple value, but i don't can show only the number 50)
function agregar(){
let Productos= {
"Manzana": "50",
"Banana": "40",
"Naranja": "30",
"Mandarina": "20"
}
console.table(Productos)
let frutaComprada= document.getElementById("inputProducto").value;
let costoTotal= document.getElementById("valor");
let productoSeleccionado=Productos[frutaComprada];
costoTotal=costoTotal+productoSeleccionado;
valor.innerHTML=costoTotal;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div class="container">
<h1>Bienvenido a la tienda</h1>
<input id="inputProducto" type="text" placeholder="Ingrese su producto">
<br>
<br>
<input id="inputCompra" type="text" placeholder="Ingrese el valor de su compra">
<br>
<br>
<button id="buttonCarrito">Agregar al carrito</button>
<p>El valor total de su compra es: <span id="valor"> 0 </span></p>
</div>
</body>
<script src="js.js"></script>
</html>
Values from form inputs will always be strings, so to add numbers together you need to coerce the string to a number. A couple of methods: 1) Number(str) or 2) +str.
Your object of products/prices: there's no need to have those prices as strings.
The main problem you were having is that let costoTotal= document.getElementById("valor"); is only picking up the element and not the text content. We can use let costoTotal= document.getElementById("valor").textContent; for that, but then we need to coerce that to a number similarly to input values.
(Sidenote: at the moment your code doesn't use the value from inputCompra which is why I asked about it in the comments. So the total will increase by 40 for bananas, for example, regardless of what is entered in that input.)
let btn = document.getElementById("buttonCarrito");
btn.addEventListener("click", agregar);
function agregar() {
let Productos = {
Manzana: 50,
Banana: 40,
Naranja: 30,
Mandarina: 20
}
let frutaComprada = document.getElementById("inputProducto").value;
let costoTotal = Number(document.getElementById("valor").textContent);
let productoSeleccionado = Productos[frutaComprada];
costoTotal = costoTotal + productoSeleccionado;
valor.textContent = costoTotal;
}
<div class="container">
<h1>Bienvenido a la tienda</h1>
<input id="inputProducto" type="text" placeholder="Ingrese su producto">
<br>
<br>
<input id="inputCompra" type="text" placeholder="Ingrese el número de artículos">
<br>
<br>
<button id="buttonCarrito">Agregar al carrito</button>
<p>El valor total de su compra es: <span id="valor"> 0 </span></p>
</div>
Here's a version that uses quantity in case you were curious.
let Productos = {
Manzana: 50,
Banana: 40,
Naranja: 30,
Mandarina: 20
}
const product = document.getElementById('inputProducto');
const quantity = document.getElementById('inputCompra')
const valor = document.getElementById('valor');
const btn = document.getElementById('buttonCarrito');
btn.addEventListener('click', agregar);
function agregar() {
const frutaComprada = product.value;
const itemQuantity = Number(quantity.value);
const productoSeleccionado = Productos[frutaComprada];
const subTotal = productoSeleccionado * itemQuantity;
let costoTotal = Number(valor.textContent);
costoTotal = costoTotal + subTotal;
valor.textContent = costoTotal;
}
<div class="container">
<h1>Bienvenido a la tienda</h1>
<input id="inputProducto" type="text" placeholder="Ingrese su producto">
<br>
<br>
<input id="inputCompra" type="text" placeholder="Ingrese el valor de su compra">
<br>
<br>
<button id="buttonCarrito">Agregar al carrito</button>
<p>El valor total de su compra es: <span id="valor"> 0 </span></p>
</div>

how to add one on name attribute with javascript?

I have a dynamic form section which I need the name attribute to be dynamic as well.
the number should always get +1 each time the user create a new section !
name="training**1**[institut]"
This is crucial to have a proper SQL insert ... otherwise the array won't have a classical database logics !
JSFIDDLE here
Any idea ? thanks a lot from France !
<form method="post" action="">
<!-- INFO SECTION -->
<div id="infos">
<h2>Infos personnelles</h2>
<input placeholder="Prénom">
<input placeholder="Nom">
</div>
<!-- TRAINING SECTION -->
<div id="training">
<h2>Formation</h2>
<!-- Template -->
<div id="new-training" style="display:none">
<div>
</br>
<p></p>
<input id="mytext" type="text" name="training[1][institut]" placeholder="Diplôme" value="">
<input name="training[1][institut]" placeholder="Institut">
</div>
</div>
</div>
<p id="addnew">
+ Ajouter une formation
</p>
<p>
<br>
<input type="submit" value="Sauvergarder" name="submit">
</p>
</form>
<script> // 1st : Enregistrer / supprimer une formation
var ct = 1;
function addTraining()
{
ct++;
var div1 = document.createElement('div');
div1.id = ct;
// link to delete extended form elements
var delLink = 'Supprimer cette formation';
div1.innerHTML = document.getElementById('new-training').innerHTML + delLink;
document.getElementById('training').appendChild(div1);
}
function removeTraining(eleId)
{
d = document;
var ele = d.getElementById(eleId);
var parentEle = d.getElementById('training');
parentEle.removeChild(ele);
}
The best solution (my opinion) is to use a simple templating engine
https://jsfiddle.net/nget5dq2/1/
Addition to your HTML:
<template id="new_el_template" hidden>
<div id="row-{cid}">
<input id="mytext-{cid}" type="text" name="training[{cid}][institut]" placeholder="Diplôme" value="">
<input name="training[{cid}][institut]" placeholder="Institut">
</div>
Supprimer cette formation
</template>
JS
var ct = 1;
function addTraining() {
ct++;
let div = document.createElement('div');
div.innerHTML = document.getElementById('new_el_template').innerHTML.replace(/\{cid\}/gi, ct);
document.getElementById('training').appendChild(div);
}
function removeTraining(eleId) {
document.getElementById('row-' + eleId).parentNode.remove();
}
And yes, you can go ahead and generate the initial element directly from the template.
write the name attribute this way you should get all the data from the form when u post it.
<input id="mytext" type="text" name="training[diploma][]" placeholder="Diplôme" value="">
<input name="training[institut][]" placeholder="Institut">
Here is a working example with comments added throughout..
<!DOCTYPE html>
<html>
<head>
<title>Test</title>
</head>
<body>
<form method="post" action="">
<!-- INFO SECTION -->
<div id="infos">
<h2>Infos personnelles</h2>
<input placeholder="Prénom">
<input placeholder="Nom">
</div>
<!-- TRAINING SECTION -->
<div id="training">
<h2>Formation</h2>
<!-- Template -->
<div id="new-training" >
<div>
</br>
<p></p>
<input id="mytext" type="text" name="training[1][institut]" placeholder="Diplôme" value="">
<input name="training[1][institut]" placeholder="Institut">
</div>
</div>
</div>
<p id="addnew">
<a style="color: blue" onclick="addTraining()">+ Ajouter une formation</a>
</p>
<p>
<br>
<input type="submit" value="Sauvergarder" name="submit">
</p>
</form>
</body>
<script>
const addTraining = () => {
//Get parent container to place new input into
const parent = document.getElementById('training');
//Create DIV to wrap around input elements
let div = document.createElement('div')
//Create new input with a unique name attribute
let newInput1 = document.createElement('input');
let newInput2 = document.createElement('input');
//You can get an array of all existing elements and add 1 to create a unique name for each
let num = parent.querySelectorAll('div').length + 1,
newName = 'training['+ num +'][institut]';
//Set name attribute
newInput1.setAttribute('name', newName);
newInput2.setAttribute('name', newName);
//Set other attributes you alreadt had
newInput1.setAttribute('placeholder', 'Diplôme');
newInput2.setAttribute('placeholder', 'Institut');
newInput1.setAttribute('id', 'myText');
newInput1.setAttribute('type', 'text');
//Append elements
parent.appendChild(div);
div.appendChild(newInput1);
div.appendChild(newInput2)
}
</script>
</html>

Clone div not being removed, just the original one

I have a div being cloned and I would like the button remove to remove the selected div. It's only removing the html div that is used to clone the field.
See my code below:
JS
// Clones Schedule Field
function cloneField(){
const newFieldContainer = document.querySelector(".schedule-item").cloneNode(true)
console.log(newFieldContainer)
let fields = newFieldContainer.querySelectorAll('input')
fields.forEach(function(field){
field.value = ""
})
document.querySelector("#schedule-items").appendChild(newFieldContainer)
}
// Adds new field
function addButton(){
let button = document.querySelector("#add-time")
const selected = document.getElementById('select').selected
let scheduleItems = document.querySelector('#schedule-items')
let inputs = scheduleItems.querySelectorAll('input')
if(selected == true || [...inputs].some(input=>input.value === "")){
alert('Tem o dia ou a hora faltando nos Horários Disponíveis.')
button.removeEventListener('click',cloneField)
}else{
button.addEventListener('click',cloneField)
}
}
// Removed field added if needed
let buttonRemove = document.querySelector('.remove-schedule-item')
buttonRemove.addEventListener('click',removeField)
function removeField(){
let scheduleItem = document.querySelector('.schedule-item')
scheduleItem.parentNode.removeChild(scheduleItem);
console.log('hey')
}
HTML
<fieldset id="schedule-items">
<legend>Horários disponíveis
<button type="button" id="add-time" onclick="addButton()">+Novo horário</button>
</legend>
<div class="schedule-item">
<div class="select-block">
<label for="weekday">Dia da semana</label>
<select name="weekday[]" required="true">
<option id="select" value="select" selected>Selecione uma opção</option>
{%for weekday in weekdays %}
<option value="{{loop.index0}}">{{weekday}}</option>
{%endfor%}
</select>
</div>
<div class="input-block">
<label for="time_from">Das</label>
<input type="time" name="time_from[]" required>
</div>
<div class="input-block">
<label for="time_to">Ate</label>
<input type="time" name="time_to[]" required>
</div>
<div class="remove-schedule-item">
<button>remove</button>
</div>
</div>
</fieldset>
</form>
Thanks in advance
when you try to remove the item
function removeField(){
let scheduleItem = document.querySelector('.schedule-item')
scheduleItem.parentNode.removeChild(scheduleItem);
console.log('hey')
}
you are always selecting the first .schedule-item and then delete the first item
edit:
when you clone you element you need to add event listener to the new element
function cloneField(){
const newFieldContainer = document.querySelector(".schedule-item").cloneNode(true);
let fields = newFieldContainer.querySelectorAll('input')
fields.forEach(function(field){
field.value = ""
});
document.querySelector("#schedule-items").appendChild(newFieldContainer);
const removeBtn = newFieldContainer.querySelector('.remove-schedule-item');
if(removeBtn){
removeBtn.addEventListener('click',function(){
newFieldContainer.remove();
});
}
}

Input search through an array

well I'm pretty new in Javascript and I would like to improve the following code
that I made to order the buttons based on the search,I don't know that else should I add to make it work so this is what I've done until now, every comment or suggestion will be welcome
Thanks a lot!
//Variables
let valorBusqueda = document.querySelector('#valor');
let opcBusqueda = document.querySelector('.opc-busqueda');
//Event Listener
valorBusqueda.addEventListener('keyup', keyUpCampo);
//Funciones
function keyUpCampo() {
//Muestra el menu de sugerencias
opcBusqueda.style = "display: flex; flex-direction:column; width:165px";
sendToPage();
}
var sendToPage = function () {
//Get the input value by finding the element by its ID
let busqueda = document.getElementById('valor').value;
//Check if the value is in the array
var sugerencias = ['marvel','maravilloso', 'futbol','goku ssj','falafel','robocop', 'rick','ricardo', 'morty', 'x-men', 'starwars', 'goku', 'bulma', 'vegeta', 'simpsons', 'homer', 'cartoon'];
var coincidencias =[]
for (indice in sugerencias) {
let lSug = sugerencias[indice].charAt();
if (lSug.includes(busqueda.charAt())) {
coincidencias.push(sugerencias[indice]);
opcBusqueda.innerHTML = `<input type="button" value=${coincidencias[0]} >
<input type="button" value=${coincidencias[1]} >
<input type="button" value=${coincidencias[2]} >
`
}
}
}
<body>
<div class="busqueda">
<div class="inputs">
<input id="valor" type="text" placeholder=" Busca hashgtags, temas, busca lo que quieras..">
</div>
</div>
<div class="opc-busqueda" style="display: none;">
</div>
</body>

Javascript getting a single element on Firefox, and an array on other browsers

So i have a form in html, with each of the options being like this: (A plethora of full pages like this can be found here)
<input id="Q1opc1" name="Q1" type="radio" value="Q1opc1" />
<label for="Q1opc1 ">Froyo </label>
<label id="Q1extr" style="display: none">&nbsp&nbsp Recuerda que los nombres se asignan en orden alfabético.
</label> </br>
The submit button:
<input
onclick="comprobarRespuesta(Q1opc2,Q1,Q1extr,Q1FraseCorrecto,Q1FraseIncorrecto,Q1GrCorrecto,Q1GrIncorrecto);"
type="button" value="Comprobar" />
First i pass the right answer, then the name of the radio buttons, then the id of the hints, then the id of the right and wrong phrases and images to be shown/hidden as apropiate.
The JavaScript function looks like this:
function comprobarRespuesta(correcta, radio, extra, sicorrecto, sinocorrecto,
iconoTick, iconoWrong) {
var tmpChoice = radio;
var c = radio.length;
var correct = 0;
for (i = 0; i < c; i++) {
if (tmpChoice[i].checked == true) {
extra[i].style.display = "inline";
if (tmpChoice[i].value == correcta.value) {
sicorrecto.style.display = "inline";
sinocorrecto.style.display = "none";
iconoWrong.style.visibility = "hidden";
iconoTick.style.visibility = "visible";
} else {
sinocorrecto.style.display = "inline";
sicorrecto.style.display = "none";
iconoWrong.style.visibility = "visible";
iconoTick.style.visibility = "hidden";
}
} else {
extra[i].style.display = "none";
}
}
};
The problem i have is that in most browsers i have been able to test, the variable called "extra" in my function is an array of elements, so accesing extra[i] has no problems, but in firefox, extra is only the first label with that id, and not all of them, so JavaScript outputs "TypeError: extra[i] is undefined" to the console, exits, and my form behaves as it was not working at all
So with the pointers from CBroe, I rewrote part of the code so that it uses the proper document.getElementById()/document.getElementsByName(), and doesent repeat ids. Now it needs much fewer paramenters to be passed, and works fine on all browsers i have tried and should work properly on all others as I am using the proper functions. Here is my working code, now in less pieces (HTML):
<form name="Q4Form">
<h5>
Cada ítem de menú tiene una serie de atributos. ¿Cuál de los siguientes NO es un atributo de menú?
<img id="Q4GrCorrecto" height="16" alt="Correcto" style="visibility: hidden" width="16"
src="http://www.dcomg.upv.es/~jtomas/bien.jpg" />
<img id="Q4GrIncorrecto" height="16" alt="Incorrecto" style="visibility: hidden" width="16"
src="http://www.dcomg.upv.es/~jtomas/mal.png"/>
</h5><h6>
<input id="Q4opc1" name="Q4" type="radio" value="Q4opc1" />
<label for="Q4opc1 ">icono
</label>
<label id="Q4extr1" name="Q4extr" style="display: none">&nbsp&nbsp</label> </br>
<input id="Q4opc2" name="Q4" type="radio" value="Q4opc2" />
<label for="Q4opc2 ">método que se ejecutará al seleccionar una opción
</label>
<label id="Q4extr2" name="Q4extr" style="display: none">&nbsp&nbsp</label> </br>
<input id="Q4opc3" name="Q4" type="radio" value="Q4opc3" />
<label for="Q4opc3 ">título que se mostrará
</label>
<label id="Q4extr3" name="Q4extr" style="display: none">&nbsp&nbsp</label> </br>
<input id="Q4opc4" name="Q4" type="radio" value="Q4opc4" />
<label for="Q4opc4 ">identificador (id)</label>
<label id="Q4extr4" name="Q4extr" style="display: none">&nbsp&nbsp</label> </br>
</h6>
<label id="Q4FraseCorrecto" style="display: none">
Respuesta correcta
</label>
<label id="Q4FraseIncorrecto" style="display: none">
Respuesta incorrecta
</label> </br>
<input
onclick="comprobarRespuesta(2,4);"
type="button" value="Comprobar" />
</form>
onClick variables are the correct answer and the number of the question
JavaScript:
function comprobarRespuesta(numCorrecta, numPregunta) {
var radio = document.getElementsByName("Q"+numPregunta);
var sicorrecto = document.getElementById("Q"+numPregunta+"FraseCorrecto");
var sinocorrecto = document.getElementById("Q"+numPregunta+"FraseIncorrecto");
var iconoTick = document.getElementById("Q"+numPregunta+"GrCorrecto");
var iconoWrong = document.getElementById("Q"+numPregunta+"GrIncorrecto");
var extra = document.getElementsByName("Q"+numPregunta+"extr");
var c = radio.length;
for (i = 0; i < c; i++) {
if (radio[i].checked == true) {
extra[i].style.display = "inline";
if (i == numCorrecta-1) {
sicorrecto.style.display = "inline";
sinocorrecto.style.display = "none";
iconoWrong.style.visibility = "hidden";
iconoTick.style.visibility = "visible";
} else {
sinocorrecto.style.display = "inline";
sicorrecto.style.display = "none";
iconoWrong.style.visibility = "visible";
iconoTick.style.visibility = "hidden";
}
} else {
extra[i].style.display = "none";
}
}
};
Now I am geting the variables inside the function, and i ned so much fewer inputs because the names or ids of the elements are hightly predictable.

Categories