Estoy tratando de hacer una pequeña calculadora con elementos de entrada. He creado un botón más para insertar un nuevo campo de entrada después del último. Esta funcionando.

Ahora estoy tratando de sumar cada campo de entrada. Pero obtengo indefinido en la consola. No sé qué pasa porque soy nuevo en programación. Intenté obtener el valor de los campos de entrada con la clase .input-time y luego convertirlo en una matriz. Y luego haciendo un bucle for para sumarlos.

EDITAR:

Gracias a todos por la ayuda. Usé el código de @ Yoiki porque es una forma nueva y fácil. Edité el código cortado. Está funcionando ahora.

$(function() {
  
  // ADDING NEW INPUT FIELD
  $('.button-plus').on('click', function(event) {
    event.preventDefault();
    
    let inPut = $('.input-time');
    let inPutArr = jQuery.makeArray( inPut );
    // console.log(inPutArr);

    let lastInPut = inPutArr[inPutArr.length-1]; // get last elem of array
    $(lastInPut).addClass('lastone'); // add class to it
    $('.lastone').after('<input type=\"text\" class=\"input-time\">');
    $('.lastone').delay(10).removeClass('lastone');
  });
  
  /* OLD CODE - NOT WORKING!!!
  $('#button-calc').on('click', function(event) {
    event.preventDefault();
    let inPutV = $('.input-time').val();
    let inPutVal = jQuery.makeArray( inPutV );
    for (var i = 0; i < inPutVal.length; i++) {
      var sum = sum + inPutVal[i];
    }
    console.log(sum);
  });
  */
  
  // NEW CODE - WORKING!!!
  $('#button-calc').on('click', function(event) {
    event.preventDefault();

    let sum = 0;

    $('.input-time').each (function () {
      sum += +$(this).val();
    });
    console.log (sum);
  });
});
/* IGNORE THE STYLE ;) */

input {
  width: 160px;
  height: 20px;
  padding: 10px 20px 10px 20px;
  border: none;
  border-radius: 20px;
  font-size: 15px;
  display: block;
  margin-bottom: 10px;
}

.container {
  background-color: #dde4fe;
  padding: 20px;
  width: 200px;
  margin-right: 20px;
  margin-left: auto;
  margin-right: auto;
  margin-top: 100px;
}

.button-plus {
  width: 40px;
  height: 40px;
  background-color: #9aadfd;
  color: #fff;
  cursor: pointer;
  margin-top: 10px;
  margin-left: auto;
  margin-right: auto;
  border-radius: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
}


#button-calc {
  width: 200px;
  height: 40px;
  background-color: #5677fc;
  color: #fff;
  cursor: pointer;
  margin-top: 20px;
  margin-bottom: 0;
}

.btn-plus {
  width: 20px;
  margin-left: auto;
  margin-right: auto;
  height: 5px;
  background-color: #5677fc;
  border-radius: 5px;
  position: absolute;
}

.plus-1 {
  transition: 0.5s;
  transform: rotate(0deg);
}

.plus-2 {
  transition: 0.5s;
  transform: rotate(90deg);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<section class="container">
  <div class="container-inner">
    <input type="text" class="input-time">
    <input type="text" class="input-time">
    <div class="button-plus">
      <div class="btn-plus plus-1"></div>
      <div class="btn-plus plus-2"></div>
    </div>
    <input type="submit" id="button-calc" value="Calculate">
  </div>
</section>
0
user8820339 30 oct. 2017 a las 19:50

6 respuestas

La mejor respuesta

Lo que desea hacer es iterar todos los elementos con la clase input-time y obtener valor para cada elemento. No puede obtener directamente una matriz de valores.

$('#button-calc').on('click', function(event) {
   event.preventDefault();

   let sum = 0; // Init the variable outside the loop

   $('.input-time').each (function () { // This is how you iterate all .input-time element
    sum += +$(this).val(); // And then you get the value
   });
   console.log (sum);
});

$(this).val() devuelve el texto de la entrada pero es una cadena y necesita un número para agregar a sum. Es por eso que uso un + antes de $(this).val() para transformar una cadena en número .

También debe verificar si el elemento .input-time es una cadena para evitar comportamientos extraños.

0
Yoiki 30 oct. 2017 a las 17:18

Está intentando asignar los elementos devueltos de su selección de jQuery. Debe iterar sobre los elementos y extraer el objeto de cada uno. No hice un isNaN ni ningún error al verificar aquí, pero esto funciona.

$('#button-calc').on('click', function(event) {
  event.preventDefault();
  var total = 0;
  $.each( $('input.input-time'), function(idx, elm) {
    var v = $(elm).val()
    total += parseFloat(v);
  });

  console.log(total);

});

También usé parseFloat para dar cuenta de los números flotantes.

0
splitwire 30 oct. 2017 a las 17:01

sum no está definido, así que cuando le agregas un número, estás agregando ese número a undefined. Primero debe configurar sum = 0.

Una sugerencia para ayudar a evitar el uso accidental de valores indefinidos, intente incluir {{ X0}} al comienzo de su código: lo obliga a definir sus variables, entre otras cosas.

1
Nathan Hinchey 30 oct. 2017 a las 16:55

Su primer problema es el alcance variable, la suma no existe en el momento en que intenta registrarlo, en mi ejemplo defino la suma fuera de cualquier otra función para que sea global a nivel de bloque para su IIFE. El segundo problema estaba dentro de su devolución de llamada de cálculo, su variable inPutV extraía el valor de su selector, para iterar y sumarlos, necesitaría tirar del selector y luego repetirlo para obtener su suma. Tercer problema, sus entradas son de tipo texto, no número, por lo que tendrían que convertirse a números antes de que la adición sea exitosa (también puede cambiar su tipo de entrada, que sería mi recomendación).

$(function() {
  let sum = 0
  
  // ADDING NEW INPUT FIELD
  $('.button-plus').on('click', function(event) {
    event.preventDefault();
    
    let inPut = $('.input-time');
    let inPutArr = jQuery.makeArray( inPut );
    // console.log(inPutArr);

    let lastInPut = inPutArr[inPutArr.length-1]; // get last elem of array
    $(lastInPut).addClass('lastone'); // add class to it
    $('.lastone').after('<input type=\"text\" class=\"input-time\">');
    $('.lastone').delay(10).removeClass('lastone');
    
    sum = 0;
  });

  // DOING CALCULATION - NOT WORKING
  $('#button-calc').on('click', function(event) {
    event.preventDefault();
    let inPutV = $('.input-time');
    let inPutVal = jQuery.makeArray( inPutV );
    for (var i = 0; i < inPutVal.length; i++) {
      sum += Number(inPutVal[i].value);
    }
    console.log(sum);
    
    sum = 0;
  });

});
input {
  width: 160px;
  height: 20px;
  padding: 10px 20px 10px 20px;
  border: none;
  border-radius: 20px;
  font-size: 15px;
  display: block;
  margin-bottom: 10px;
}

.container {
  background-color: #dde4fe;
  padding: 20px;
  width: 200px;
  margin-right: 20px;
  margin-left: auto;
  margin-right: auto;
  margin-top: 100px;
}

.button-plus {
  width: 40px;
  height: 40px;
  background-color: #9aadfd;
  color: #fff;
  cursor: pointer;
  margin-top: 10px;
  margin-left: auto;
  margin-right: auto;
  border-radius: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
}


#button-calc {
  width: 200px;
  height: 40px;
  background-color: #5677fc;
  color: #fff;
  cursor: pointer;
  margin-top: 20px;
  margin-bottom: 0;
}

.btn-plus {
  width: 20px;
  margin-left: auto;
  margin-right: auto;
  height: 5px;
  background-color: #5677fc;
  border-radius: 5px;
  position: absolute;
}

.plus-1 {
  transition: 0.5s;
  transform: rotate(0deg);
}

.plus-2 {
  transition: 0.5s;
  transform: rotate(90deg);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<section class="container">
  <div class="container-inner">
    <input type="text" class="input-time">
    <input type="text" class="input-time">
    <div class="button-plus">
      <div class="btn-plus plus-1"></div>
      <div class="btn-plus plus-2"></div>
    </div>
    <input type="submit" id="button-calc" value="Calculate">
  </div>
</section>

Editar (en vainilla)

Solo para comparar, aquí está su funcionalidad sin jQuery.

Referencia

(function() {
  // Create object to store sum and number of inputs on page
  const data = { sum: 0, inputs: 2, };

  // Event handler for creating new inputs
  const addInput = e => {
    e.preventDefault();
    // create a new input element (eg: $('<input/>');)
    const newInput = document.createElement('input')
    // assign input type, and class to new element
    newInput.type = 'number';
    newInput.classList.add('input-time');

    // get input container (eg: $('.container-inner');)
    const container = document.querySelector('.container-inner')
    // this inserts the new input before the end of the element
    container.insertBefore(newInput, container.children[data.inputs]);

    // update number of inputs, to allow adding more.
    data.inputs += 1;
  };

  // Event handler for getting sum of inputs
  const sumInputs = e => {
    e.preventDefault();
    // get all elements of class input-time (eg: $('.input-time');)
    const inputs = document.querySelectorAll('.input-time');
    data.sum = Object.keys(inputs)                // keys for inputs object in array form
      .filter(key => !isNaN(key))                 // filter out non-numbers
      .map(val => parseInt(inputs[val].value)) .  // map new array from input values
      .reduce((sum, current) => sum + current, 0);// sum array of input values
    console.log(data.sum);
  };

  // get your add button and sum button (eg: $('.button-plus');)
  const buttonAdd = document.querySelector('.button-plus');
  const buttonSum = document.querySelector('#button-calc');

  // create event listeners (eg: $('.button-plus').on('click', addInput);)
  buttonAdd.addEventListener('click', addInput, false);
  buttonSum.addEventListener('click', sumInputs, false);
})();
input {
  width: 160px;
  height: 20px;
  padding: 10px 20px 10px 20px;
  border: none;
  border-radius: 20px;
  font-size: 15px;
  display: block;
  margin-bottom: 10px;
}

.container {
  background-color: #dde4fe;
  padding: 20px;
  width: 200px;
  margin-right: 20px;
  margin-left: auto;
  margin-right: auto;
  margin-top: 100px;
}

.button-plus {
  width: 40px;
  height: 40px;
  background-color: #9aadfd;
  color: #fff;
  cursor: pointer;
  margin-top: 10px;
  margin-left: auto;
  margin-right: auto;
  border-radius: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
}


#button-calc {
  width: 200px;
  height: 40px;
  background-color: #5677fc;
  color: #fff;
  cursor: pointer;
  margin-top: 20px;
  margin-bottom: 0;
}

.btn-plus {
  width: 20px;
  margin-left: auto;
  margin-right: auto;
  height: 5px;
  background-color: #5677fc;
  border-radius: 5px;
  position: absolute;
}

.plus-1 {
  transition: 0.5s;
  transform: rotate(0deg);
}

.plus-2 {
  transition: 0.5s;
  transform: rotate(90deg);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<section class="container">
  <div class="container-inner">
    <input type="number" class="input-time">
    <input type="number" class="input-time">
    <div class="button-plus">
      <div class="btn-plus plus-1"></div>
      <div class="btn-plus plus-2"></div>
    </div>
    <input type="submit" id="button-calc" value="Calculate">
  </div>
</section>
0
D Lowther 30 oct. 2017 a las 20:02

No use val() cuando esté reuniendo objetos.

inPutV = $('.input-time');

Pero use val() cuando extraiga valores:

sum = sum + inPutVal[i].val()

1
Ali Sheikhpour 30 oct. 2017 a las 18:43

Puede utilizar una operación de mapa / reducción aquí para simplificar su código. En lugar de recorrer su entrada, puede map() para devolver solo el valor y luego reduce() esta matriz de valores con una adición.

$(function() {
  
  // ADDING NEW INPUT FIELD
  $('.button-plus').on('click', function(event) {
    event.preventDefault();
    
    let inPut = $('.input-time');
    let inPutArr = jQuery.makeArray( inPut );
    // console.log(inPutArr);

    let lastInPut = inPutArr[inPutArr.length-1]; // get last elem of array
    $(lastInPut).addClass('lastone'); // add class to it
    $('.lastone').after('<input type=\"text\" class=\"input-time\">');
    $('.lastone').delay(10).removeClass('lastone');
  });

  // DOING CALCULATION - WORKING NOW
  $('#button-calc').on('click', function(event) {
    event.preventDefault();
    var sum = $('.container-inner input[type=text]').map(function(index, ob) {
    	return parseInt(ob.value);
    }).get().reduce(function(a, b) {
      return a + b;
    });
    console.log(sum);
  });

});
/* IGNORE THE STYLE ;) */

input {
  width: 160px;
  height: 20px;
  padding: 10px 20px 10px 20px;
  border: none;
  border-radius: 20px;
  font-size: 15px;
  display: block;
  margin-bottom: 10px;
}

.container {
  background-color: #dde4fe;
  padding: 20px;
  width: 200px;
  margin-right: 20px;
  margin-left: auto;
  margin-right: auto;
  margin-top: 100px;
}

.button-plus {
  width: 40px;
  height: 40px;
  background-color: #9aadfd;
  color: #fff;
  cursor: pointer;
  margin-top: 10px;
  margin-left: auto;
  margin-right: auto;
  border-radius: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
}


#button-calc {
  width: 200px;
  height: 40px;
  background-color: #5677fc;
  color: #fff;
  cursor: pointer;
  margin-top: 20px;
  margin-bottom: 0;
}

.btn-plus {
  width: 20px;
  margin-left: auto;
  margin-right: auto;
  height: 5px;
  background-color: #5677fc;
  border-radius: 5px;
  position: absolute;
}

.plus-1 {
  transition: 0.5s;
  transform: rotate(0deg);
}

.plus-2 {
  transition: 0.5s;
  transform: rotate(90deg);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<section class="container">
  <div class="container-inner">
    <input type="text" class="input-time">
    <input type="text" class="input-time">
    <div class="button-plus">
      <div class="btn-plus plus-1"></div>
      <div class="btn-plus plus-2"></div>
    </div>
    <input type="submit" id="button-calc" value="Calculate">
  </div>
</section>
0
Nicolas 30 oct. 2017 a las 17:02