A煤n no tienes acceso a esta clase

Crea una cuenta y contin煤a viendo este curso

Proyecto: Validar inputs

10/23
Recursos

Aportes 44

Preguntas 1

Ordenar por:

驴Quieres ver m谩s aportes, preguntas y respuestas de la comunidad? Crea una cuenta o inicia sesi贸n.

Con VanillaJS:

let description = document.getElementById('description')
let calories = document.getElementById('calories')
let carbs = document.getElementById('carbs')
let protein = document.getElementById('protein')

const validateInputs = () => {
  description.value ? '' : description.classList.add('is-invalid')
  calories.value ? '' : calories.classList.add('is-invalid')
  carbs.value ? '' : carbs.classList.add('is-invalid')
  protein.value ? '' : protein.classList.add('is-invalid')

  if(description.value && calories.value && carbs.value && protein.value) {
    console.log('OK!')
  }
}

description.addEventListener('keydown', () => description.classList.remove('is-invalid'))
calories.addEventListener('keydown', () => calories.classList.remove('is-invalid'))
carbs.addEventListener('keydown', () => carbs.classList.remove('is-invalid'))
protein.addEventListener('keydown', () => protein.classList.remove('is-invalid'))

Mi ejemplo:

const IS_INVALID = 'is-invalid'

const description = document.getElementById('description')
const calories = document.getElementById('calories')
const carbs = document.getElementById('carbs')
const protein = document.getElementById('protein')
const inputs = [description, calories, carbs, protein]

const isValid = elem => elem.value

const isFormValid = () =>
  isValid(description) && isValid(calories) && isValid(carbs) && isValid(protein)

const showInvalid =
  elem => isValid(elem) ? '' : elem.classList.add(IS_INVALID)

const addKeydownEvent = elem =>
  elem.addEventListener('keydown', () => elem.classList.remove(IS_INVALID))

inputs.forEach(addKeydownEvent)

const validateInputs = () => {
  inputs.forEach(showInvalid)

  if (isFormValid()) {
    console.log('OK')
  }
}
Badtante decepcionado del curso, que utilice jQuery en lugar de VanillaJS me desmotiva bastante.

Buen video para recordar javascript puro, con frameworks o librerias actualmente el manejo es mas sencillo. Para evitar el uso de JQuery, lo he realizado de otra manera:

const $ = id => document.getElementById(id);

let formInputs = {
  description: $('description'),
  calories: $('calories'),
  carbs: $('carbs'),
  protein: $('protein'),
}

const inputEntries = Object.entries(formInputs);

const validateInputs = () => {
  inputEntries.forEach(prop => {
    if (!prop[1].value) {
      formInputs[`${prop[0]}`].classList.add('is-invalid');
    }
  });

  if(Object.values(formInputs).every(({ value }) => value)) {
    alert('All inputs are fill')
  }
}

const removeInvalidType = () => {
  inputEntries.forEach(prop => {
    prop[1].addEventListener('keypress', () => {
      formInputs[`${prop[0]}`]
        .classList
          .remove('is-invalid')
    });
  })
}

removeInvalidType();


Un saludo a la comunidad 馃槂!

Esta es mi soluci贸n con vanilla JS. Si tienen dudas porfa comenten 馃槃

Les comparto mi soluci贸n con typescript鈥

Y les dejo mi repositorio por si quieren echar un vistazo, feedback bienvenido
repositorio-gus

const form = document.getElementById('form') as HTMLFormElement;

const validateInputs = (ele: HTMLInputElement) => {
  ele.value === '' &&
    (ele.classList.add('invalid'),
    window.setTimeout(() => ele.classList.remove('invalid'), 600));
  return { id: ele.id, value: ele.value };
};

const listener = (e: Event) => {
  e.preventDefault();
  const element = e.target as HTMLFormElement;
  const arr = Object.values(element).map(validateInputs).slice(0, 4);
  const flag = arr.every((ele) => ele.value !== '');

  if (flag) {
    console.log('OK');
    console.log(arr);
  }
};

form.addEventListener('submit', listener);

El operador ternario tambi茅n funciona en el 煤ltimo if y se escribir铆a de la siguiente manera

$description.value && $calories.value && $carbs.value && $proteins.value && console.log('works')

Aunque cabe destacar que es un poco confuso si no se tiene el else por que es el mismo s铆mbolo que la concatenaci贸n de condiciones

Espero que mi c贸digo sirva! Si es as铆 hac茅dmelo saber y seguir茅 public谩ndolo 馃槂

const description = $('#description');
const carbs = $('#carbs');
const calories = $('#calories');
const protein = $('#protein');


removeIsInvalidOnKeyPress = (...inputs) => {
  for(let input of inputs) {
    input.keypress(() => {
        input.removeClass('is-invalid');
    })
  }
}

removeIsInvalidOnKeyPress(description, carbs, calories, protein);

const isInputValid = input => {
  const inputValue = input.val();
  
  if(!inputValue) input.addClass('is-invalid');

  return Boolean(inputValue);
}

const inputsAreValid = (...inputs) => {
  return !inputs
    .map(input => isInputValid(input))
    .includes(false) 
}

const validateInputs = () => {
  if(inputsAreValid(description, carbs, calories, protein)) {
    alert('OK')
  }
} ```

Hola chicos, les dejo mi c贸digo:

const compose = (...functions) => data =>
  functions.reduceRight((value, func) => func(value), data)

let description = document.getElementById('description');
let calories = document.getElementById('calories');
let carbs = document.getElementById('carbs');
let protein = document.getElementById('protein');

description.onkeypress = () => {
  description.classList.remove('is-invalid');
};

calories.onkeypress = () => {
  calories.classList.remove('is-invalid');
}

carbs.onkeypress = () => {
  carbs.classList.remove('is-invalid');
}

protein.onkeypress = () => {
  protein.classList.remove('is-invalid');
}

const validateInputs = () => {
  description.value ? '' : description.classList.add('is-invalid');
  calories.value ? '' : calories.classList.add('is-invalid');
  carbs.value ? '' : carbs.classList.add('is-invalid');
  protein.value ? '' : protein.classList.add('is-invalid');

  if (description.value && calories.value && carbs.value && protein.value) {
    console.log('ok');
  }
}

para Vanilla: classList.add()
para Jquery: addClass()

Intentando ser muy funcional:

const compose = (...functions) => data => functions.reduceRight((value, func) => func(value), data)

let $description = document.querySelector('#description')
let $calories = document.querySelector('#calories')
let $carbs = document.querySelector('#carbs')
let $proteins = document.querySelector('#proteins')
let $addButton = document.querySelector('#add-button')

var trackInput = ($input) => {
  setTimeout(() => {
    $input.value !== '' ? $input.classList.remove('is-invalid') : $input.classList.add('is-invalid')
  }, 200)
}

$description.addEventListener('keypress', trackInput.bind(null, $description))
$calories.addEventListener('keypress', trackInput.bind(null, $calories))
$carbs.addEventListener('keypress', trackInput.bind(null, $carbs))
$proteins.addEventListener('keypress', trackInput.bind(null, $proteins))

const validateInputs = ($inputs) => $inputs.forEach(trackInput)
const validateForm = validateInputs.bind(null, [$description, $calories, $carbs, $proteins])
const processInputs = ($inputs, calllback) => {
  const flag = $inputs.every($input => $input.value !== '')
  flag === true ? $inputs.forEach($input => { console.log($input.value) }) : console.log('Skipping')
}

const processForm = processInputs.bind(null, [$description, $calories, $carbs, $proteins], console.log)
const manageCaloriesForm = compose(validateForm, processForm)
$addButton.addEventListener('click', manageCaloriesForm)

Mi aportaci贸n, con bonito efecto UX:

  • Primero, poned como id del h1 鈥榗ounter鈥:

<div class=鈥渃ard-header鈥>
<h1 id=鈥渃ounter鈥>Calories Counter</h1>
</div>

  • Segundo:

let description = $(鈥#description鈥) // id鈥檚 de los inputs
let calories = $(鈥#calories鈥)
let carbs = $(鈥#carbs鈥)
let protein = $(鈥#protein鈥)

calories.keypress(() =>{
calories.removeClass(鈥榠s-invalid鈥)
counter.innerHTML=counter.innerHTML==鈥淧or favor, inserta datos鈥?鈥淐alories Counter鈥:鈥淐alories Counter鈥
})

carbs.keypress(() =>{
carbs.removeClass(鈥榠s-invalid鈥)
counter.innerHTML=counter.innerHTML==鈥淧or favor, inserta datos鈥?鈥淐alories Counter鈥:鈥淐alories Counter鈥
})

description.keypress(() =>{
description.removeClass(鈥榠s-invalid鈥)
counter.innerHTML=counter.innerHTML==鈥淧or favor, inserta datos鈥?鈥淐alories Counter鈥:鈥淐alories Counter鈥
})

protein.keypress(() =>{
protein.removeClass(鈥榠s-invalid鈥)
counter.innerHTML=counter.innerHTML==鈥淧or favor, inserta datos鈥?鈥淐alories Counter鈥:鈥淐alories Counter鈥
})

const validateInputs = () => {
description.val() ? 鈥樷 : description.addClass(鈥榠s-invalid鈥)
calories.val() ? 鈥樷 : calories.addClass(鈥榠s-invalid鈥)
carbs.val() ? 鈥樷 : carbs.addClass(鈥榠s-invalid鈥)
protein.val() ? 鈥樷 : protein.addClass(鈥榠s-invalid鈥)
description.val() ? 鈥樷 : counter.innerHTML=counter.innerHTML==鈥淐alories Counter鈥?鈥淧or favor, inserta datos鈥:"Por favor, inserta datos"
calories.val() ? 鈥樷 : counter.innerHTML=counter.innerHTML==鈥淐alories Counter鈥?鈥淧or favor, inserta datos鈥:"Por favor, inserta datos"
carbs.val() ? 鈥樷 : counter.innerHTML=counter.innerHTML==鈥淐alories Counter鈥?鈥淧or favor, inserta datos鈥:"Por favor, inserta datos"
protein.val() ? 鈥樷 : counter.innerHTML=counter.innerHTML==鈥淐alories Counter鈥?鈥淧or favor, inserta datos鈥:鈥淧or favor, inserta datos鈥
}

No esta m谩s decir que el callback, reultado de evento de escribir dentro de un input devuleve this en el caso de jQuery y event en el caso de Vanilla, por lo que no es necesario volver a escribir el nombre del input para quitarle la clase:

const compose = (...functions) => data =>
  functions.reduceRight((value, func) => func(value), data)

  let $description = $('#description');
  let $carbs = $('#carbs');
  let $calories = $('#calories');
  let $protein = $('#protein');


  $description.bind('input', function(){
    $(this).removeClass('is-invalid');
  })

  $carbs.bind('input', function(){
    $(this).removeClass('is-invalid');
  })

  $calories.bind('input', function(){
    $(this).removeClass('is-invalid');
  })

  $protein.bind('input', function(){
    $(this).removeClass('is-invalid');
  })

  const  validateInputs = () => {
    $description.val() ? '': $description.addClass('is-invalid');
    $carbs.val() ? '': $carbs.addClass('is-invalid');
    $calories.val() ? '': $calories.addClass('is-invalid');
    $protein.val() ? '': $protein.addClass('is-invalid');

    if($description.val() && $carbs.val() && $calories.val() && $protein.val()){
      console.log('ok');
    }
  }

Podemos reducir los keypress removiendo los corchetes de cada arrow function 馃槉

Tambi茅n en lugar de usar el operador ternario para a帽adir las clases podemos usar el operador &&, de la siguiente forma:

description.val() && description.addClass('is-invalid')

El operador and solo ejecuta lo que est谩 despu茅s 煤nicamente si la primera expresi贸n da un Truthy.

Mi aporte 馃槂

let validaInput = document.querySelector('.mb-2').addEventListener('click', () => {
  let description = document.getElementById('description');
  let calories = document.getElementById('calories');
  let carbs = document.getElementById('carbs');
  let protein = document.getElementById('protein');

  description.value ? '' : description.classList.add('is-invalid'), description.classList.add('is-valid');
  calories.value ? '' : calories.classList.add('is-invalid'), calories.classList.add('is-valid');
  carbs.value ? '' : carbs.classList.add('is-invalid'), carbs.classList.add('is-valid');
  protein.value ? '' : protein.classList.add('is-invalid'), protein.classList.add('is-valid');

  description.addEventListener('keypress', () => { description.classList.remove('is-invalid');});
  calories.addEventListener('click', () => { description.classList.remove('is-invalid');});
  carbs.addEventListener('click', () => { carbs.classList.remove('is-invalid');});
  protein.addEventListener('click', () => { protein.classList.remove('is-invalid');});

  if(description.value  && calories.value && carbs.value && protein.value) {
    console.log('ok');
  }

});```

Mi aporte:

const compose = (...functions) => data =>
  functions.reduceRight((value, func) => func(value), data)

  // DOM elements
let $description = document.querySelector('#description')
let $calories = document.querySelector('#calories')
let $carbs = document.querySelector('#carbs')
let $proteins = document.querySelector('#proteins')
let $addButton = document.querySelector('#add-button')

// Update an input field depending of input value
var trackInput = ($input) => {
  setTimeout(() => {
    if ($input.value !== '') {
      $input.classList.remove('is-invalid')
    }
  }, 250)
}

// Add handlers to validate keypresses
$description.addEventListener('keypress', trackInput.bind(null, $description))
$calories.addEventListener('keypress', trackInput.bind(null, $calories))
$carbs.addEventListener('keypress', trackInput.bind(null, $carbs))
$proteins.addEventListener('keypress', trackInput.bind(null, $proteins))

// Validate a list of input fields
const validateInputs = ($inputs) => {
  $inputs.forEach($input => {
    if ($input.value === '') {
      $input.classList.add('is-invalid')
    } else {
      $input.classList.remove('is-invalid')
    }
  })
}

// Bind inputs before to make the function point free
const validateForm = validateInputs.bind(null, [$description, $calories, $carbs, $proteins])

// Process the inputs
const processInputs = ($inputs, calllback) => {
  const flag = $inputs.every($input => $input.value !== '')
  if (flag === true) {
    $inputs.forEach($input => { console.log($input.value) })
  }
}

// Bind inputs before to make the function point free
const processForm = processInputs.bind(null, [$description, $calories, $carbs, $proteins], console.log)

// Compose validateForm and ProcessForm in one general event handler
const manageCaloriesForm = compose(validateForm, processForm)

// Add the composed handler to validate and process the form
$addButton.addEventListener('click', manageCaloriesForm)

Para todos los que no queremos utilizar jQuery podrias intentar generar la practica usando JS puro tambi茅n conocido como VanillaJS, les comparto el ejemplo que estoy realizando sin utilizar jQuery se que varios est谩n haciendo lo mismo.

const compose = (...functions) => data =>
    functions.reduceRight((value, func) => func(value), data)

// Se utiliza $ para identificar que una variable o constante hace referencia 
// a elementos del DOM
const $DESCRIPTION = document.getElementById("description");
const $CALORIAS = document.getElementById("calorias");
const $CARBOIDRATOS = document.getElementById("carboidratos");
const $PROTEINAS = document.getElementById("proteinas");
const ERROR_CLASS = "is-invalid";

// Asignacion de evntos siempre que se desea asignar un evento aun elemento del DOM
// es necesario utilizar addEventListener
$DESCRIPTION.addEventListener("keypress", () => $DESCRIPTION.classList.remove(ERROR_CLASS));
$CALORIAS.addEventListener("keypress", () => $CALORIAS.classList.remove(ERROR_CLASS));
$CARBOIDRATOS.addEventListener("keypress", () => $CARBOIDRATOS.classList.remove(ERROR_CLASS));
$PROTEINAS.addEventListener("keypress", () => $PROTEINAS.classList.remove(ERROR_CLASS));

// funcion para validar los inputs
const validateInputs = () => {
    // Por cuestion de buenas practicas el resultado de una condici贸n
    // Ternaria tiene que ser asignada a una variable o constante
    const DESCRIPTION_CLASS = (($DESCRIPTION.value) ? "" : ERROR_CLASS);
    $DESCRIPTION.classList.add(DESCRIPTION_CLASS);

    const CALORIAS_CLASS = (($CALORIAS.value) ? "" : ERROR_CLASS);
    $CALORIAS.classList.add(CALORIAS_CLASS);

    const CARBOIDRATOS_CLASS = (($CARBOIDRATOS.value) ? "" : ERROR_CLASS);
    $CARBOIDRATOS.classList.add(CARBOIDRATOS_CLASS);

    const PROTEINAS_CLASS = (($PROTEINAS.value) ? "" : ERROR_CLASS);
    $PROTEINAS.classList.add(PROTEINAS_CLASS);

    if ($DESCRIPTION.value && $CALORIAS.value && $CARBOIDRATOS.value && $PROTEINAS.value) {
        console.log("Oki Doki");
    }
};

驴Qu茅 tal comunidad? Les dejo mi implementaci贸n para quitar la clase 鈥渋s-invalid鈥
.
Lo que hice fue colocar un id al elemento padre en com煤n de los 4 inputs, a este le puse al eventListener y mediante event bubbling puedo obtener cual de todos los elementos fue activado para as铆 quitar la clase.
.
De este modo solo estoy agrando 1 eventListener en lugar de 4

const $inputsRow = document.querySelector('#inputs-row')
$inputsRow.addEventListener('keypress', event => event.target.classList.remove('is-invalid'))

.
Una ventaja es que de este modo si despu茅s fu茅ramos a agregar o quitar inputs no habr铆a necesidad de modificar el c贸digo de JS.
.

馃槂

Pueden a帽adir un eventListener sobre los inputs para escuchar cambios, en cuanto haya un cambio comprobar si el input.value esta vacio o no y devolver la clase invalid o remove tal clase.

Agrego codigo en Vanilla Js

const compose = (...functions) => data =>
  functions.reduceRight((value, func) => func(value), data)

//Values
let $description = document.getElementById("description"),
      $calories = document.getElementById("calories"),
      $carbs = document.getElementById("carbs"),
      $protein = document.getElementById("protein");


function emptyValue(){
  $description.value=='' ?  
  $description.style.setProperty("border","solid .1px red"):''

  $calories.value=='' ?  
  $calories.style.setProperty("border","solid .1px red"):''

  $carbs.value=='' ?  
  $carbs.style.setProperty("border","solid .1px red"):''

  $protein.value=='' ?  
  $protein.style.setProperty("border","solid .1px red"):''

  if($calories.value && $carbs.value && $description.value && $protein.value !== ''){
    console.log("OK")
  }
}



const btnAdd = document.getElementById('btnAdd');
btnAdd.addEventListener("click", emptyValue)


$description.addEventListener('input', ()=> $description.style.setProperty("border",""))
$calories.addEventListener('input',()=> $calories.style.setProperty("border",""))
$carbs.addEventListener('input',()=>  $carbs.style.setProperty("border",""))
$protein.addEventListener('input',()=>  $protein.style.setProperty("border",""))


const compose = (...functions) => data =>
  functions.reduceRight((value, func) => func(value), data);

let description = document.getElementById('description');
let calories = document.getElementById('calories');
let carbs = document.getElementById('carbs');
let proteins = document.getElementById('proteins');
let addItem = document.getElementById('addItem'); // Agreg茅 un id en button

const inputs = [description, calories, proteins, carbs];

loadEventListeners();

function loadEventListeners() {
  document.addEventListener('keyup', checkEmptyInput);
  addItem.addEventListener('click', validateInputs);
}

function checkEmptyInput() {
  inputs.forEach(item => {
    if (item.value && item.classList.contains('is-invalid')) {
      item.classList.remove('is-invalid');
    }
  });
}

function validateInputs() {
  inputs.forEach(item => {
    item.value ? '' : item.classList.add('is-invalid');
  });
}

MI forma de validar de forma individual

  • Vista
  • Con el atributo input llava a la funcion 鈥渧alidateInput()鈥 y le pasa su elemento como atributo con 鈥渢his鈥
<input type="text" class="form-control mb-2 mr-sm-2" 
id="description" placeholder="Description" oninput="validateInput(this)">

<input type="number" min="0" class="form-control mb-2 mr-sm-2"
id="calories" placeholder="Calories" oninput="validateInput(this)">

<input type="number" min="0" class="form-control mb-2 mr-sm-2"
id="carbs" placeholder="Carbs" oninput="validateInput(this)">

<input type="number" min="0" class="form-control mb-2 mr-sm-2"
id="protein" placeholder="Protein" oninput="validateInput(this)">

<button class="btn btn-primary mb-2"
onclick="validateInputs()">
  <i class="fas fa-plus"></i>
</button>
  • Javascript
const description = document.querySelector('#description')
const calories    = document.querySelector('#calories')
const carbs       = document.querySelector('#carbs')
const protein     = document.querySelector('#protein')

validateInput = (input) => input.value === '' ? input.classList.add('is-invalid') : input.classList.remove('is-invalid') 

const validateInputs = () => {
  description.value === '' && description.classList.add('is-invalid') 
  calories.value    === '' && calories.classList.add('is-invalid')
  carbs.value       === '' && carbs.classList.add('is-invalid')
  protein.value     === '' && protein.classList.add('is-invalid')

  if(
    description.value !== '' &&
    calories.value    !== '' &&
    carbs.value       !== '' &&
    protein.value     !== ''
  ) {
    console.log('Ok')
  }
}
const inputDescription = document.querySelector('#description')
const inputCalories = document.querySelector('#calories')
const inputCarbs = document.querySelector('#carbs')
const inputProtein = document.querySelector('#protein')

const inputs = [inputCalories, inputCarbs, inputDescription, inputProtein]

const validateInputs = () => {
	inputs.map((input) => (input.value ? '' : input.classList.add('is-invalid')))

	if (
		inputCalories.value &&
		inputDescription.value &&
		inputProtein.value &&
		inputCarbs.value
	) {
		console.log('Guardado')
	}
}

inputs.map((input) =>
	input.addEventListener('keypress', () => {
		input.classList.remove('is-invalid')
	})
)

Comparto mi soluci贸n, si ven mejoras por favor comentenme 馃槃
#SinJQueryPapa

const { description, calories, carbs, protein } = document.getElementsByTagName("input");

const validateInputs = () => {
  const validClass = "is-valid";
  const invalidClass = "is-invalid";

  description.value == ""
    ? changeClass(description, invalidClass, validClass)
    : changeClass(description, validClass, invalidClass);

  calories.value == ""
    ? changeClass(calories, invalidClass, validClass)
    : changeClass(calories, validClass, invalidClass);

  carbs.value == ""
    ? changeClass(carbs, invalidClass, validClass)
    : changeClass(carbs, validClass, invalidClass);

  protein.value == ""
    ? changeClass(protein, invalidClass, validClass)
    : changeClass(protein, validClass, invalidClass);
};

const changeClass = (element, newClass, previousClass) => {
  element.classList.add(newClass);
  element.classList.remove(previousClass);
};
const btn = document.getElementById("add");

btn.addEventListener("click", validateInputs);

Otra forma de realizar la validaci贸n es poner &&, esto nos permite ahorranos el else cuando solo queremos que haya una sola validaci贸n, asi no colocamos que cuando no se cumpla vaya vacio.

const validForm = () => {
  !description.val() && description.addClass("is-invalid");
  !calories.val() && calories.addClass("is-invalid");
  !carbs.val() && carbs.addClass("is-invalid");
  !protein.val() && protein.addClass("is-invalid");

  if (
    description.val() &&
    calories.val() &&
    carbs.val() &&
    protein.val()
  ) {
    console.log("ok")
  }
Bastante decepcionado del curso, que utilice jQuery en lugar de VanillaJS d

let inputs = document.getElementsByTagName(鈥榠nput鈥)
let btn = document.getElementById(鈥榖tn鈥)
let con = 0

let validInput = () => {
con = 0
for (let input of inputs) {
input.addEventListener(鈥渒eypress鈥,validKeyPress)
addClassInvalid(input)
}

if(con == 4){
     console.log("todo esta ok")
}else{
     console.log("algo esta mal")
}

}

let validKeyPress = (e) => {
e.target.classList.remove(鈥榠s-invalid鈥)
}

let addClassInvalid = (input) => {
if(input.value == 鈥溾){
input.classList.add(鈥渋s-invalid鈥)
con鈥
}else{
con++
input.classList.remove(鈥渋s-invalid鈥)
}
}

btn.addEventListener(鈥榗lick鈥,validInput)

const compose = (...functions) => data =>
  functions.reduceRight((value, func) => func(value), data)


description.onkeypress = () => {
  description.classList.remove('is-invalid');
}

carbs.onkeypress = () => {
  carbs.classList.remove('is-invalid');
}

calories.onkeypress = () => {
  calories.classList.remove('is-invalid');
}

protein.onkeypress = () => {
  protein.classList.remove('is-invalid');
}

const validateInputs = () => {
  description.value ? '' : description.classList.add('is-invalid');
  carbs.value ? '' : carbs.classList.add('is-invalid');
  calories.value ? '' : calories.classList.add('is-invalid');
  protein.value ? '' : protein.classList.add('is-invalid');

  if (description.value && carbs.value && calories.value && protein.value) {
    console.log('OK');
  }
}
const compose = (...functions) => data =>
    functions.reduceRight((value, func) => func(value), data)

const description = document.getElementById("description");
const calories = document.getElementById("calories");
const carbs = document.getElementById("carbs");
const protein = document.getElementById("protein");

description.addEventListener('keypress', () => {
    description.classList.remove('is-invalid')
})
calories.addEventListener('keypress', () => {
    calories.classList.remove('is-invalid')
})
carbs.addEventListener('keypress', () => {
    carbs.classList.remove('is-invalid')
})
protein.addEventListener('keypress', () => {
    protein.classList.remove('is-invalid')
})

const validateInputs = () => {

    description.value ? '' : description.classList.add('is-invalid'), description.classList.add('is-valid')
    calories.value ? '' : calories.classList.add('is-invalid'), calories.classList.add('is-valid')
    carbs.value ? '' : carbs.classList.add('is-invalid'), carbs.classList.add('is-valid')
    protein.value ? '' : protein.classList.add('is-invalid'), protein.classList.add('is-valid')

    if (description.value && calories.value && carbs.value && protein.value) {
        console.log('ok');
    }
}

<code>



No me funcion贸 addClass, as铆 que tuve que usar .classList.add(鈥榠s-invalid鈥): Dejo el c贸digo por si alguien mas tiene el problema

queda mejor, para mi.

description.val() && description.addClass(鈥榠s-invalid鈥);

Les comparto tambi茅n otra forma de validar los campos, d贸nde el Bot贸n de enviar o agregar est谩 desactivado hasta que todos los campos est茅n llenos, todo con JavaScript Vanilla

Hice una sola clase que remueva la clase seg煤n el id

const removeClass = (id) => {
  id.classList.remove('is-invalid')
}

y con onkeypress en cada input de esta forma

<input type="text" class="form-control mb-2 mr-sm-2" id="description" placeholder="Description" onkeypress="removeClass(description)">

<input type="number" min="0" class="form-control mb-2 mr-sm-2" id="calories"  placeholder="Calories" onkeypress="removeClass(calories)">

<input type="number" min="0" class="form-control mb-2 mr-sm-2" id="carbs" placeholder="Carbs" onkeypress="removeClass(carbs)">

<input type="number" min="0" class="form-control mb-2 mr-sm-2" id="protein" placeholder="Protein" onkeypress="removeClass(protein)">
const $ButtonClick = document.getElementById('ButtonClick');

const ClassError = 'is-invalid';

// Campos
const $description = document.querySelector('#description');
const $calories = document.querySelector('#calories');
const $carbs = document.querySelector('#carbs');
const $protein = document.querySelector('#protein');

// onClick
$ButtonClick.onclick = validationInputs;

$description.onkeypress = () => $description.classList.remove(ClassError);
$calories.onkeypress = () => $calories.classList.remove(ClassError);
$carbs.onkeypress = () => $carbs.classList.remove(ClassError);
$protein.onkeypress = () => $protein.classList.remove(ClassError);

// function validate campos
function validationInputs () {
  $description.value.trim() === '' && $description.classList.add(ClassError);
  $calories.value.trim() === '' && $calories.classList.add(ClassError);
  $carbs.value.trim() === '' && $carbs.classList.add(ClassError);
  $protein.value.trim() === '' && $protein.classList.add(ClassError);

  if ($description.value.trim() !== '' && $calories.value.trim() !== '' && $carbs.value.trim() !== '' && $protein.value.trim() !== '') {
    console.log('ok');
  };
};
const compose = (...functions) => data =>
  functions.reduceRight((value, func) => func(value), data)

const ButtonClick = document.getElementById('ButtonClick')
const description = document.getElementById('description')
const calories = document.getElementById('calories')
const carbs = document.getElementById('carbs')
const protein = document.getElementById('protein')


description.onkeypress = () => description.classList.remove('is-invalid')

calories.onkeypress = () => calories.classList.remove('is-invalid')

carbs.onkeypress = () => carbs.classList.remove('is-invalid')

protein.onkeypress = () => protein.classList.remove('is-invalid')

const validateInput = () => {
  description.value === '' && description.classList.add('is-invalid')
  calories.value === '' && calories.classList.add('is-invalid')
  carbs.value === '' && carbs.classList.add('is-invalid')
  protein.value === '' && protein.classList.add('is-invalid')


  if(description.value !== '' && calories.value !== '' && carbs.value !== '' && protein.value !== ''){
    console.log('Ok')
  }

}

ButtonClick.onclick = validateInput

Excelente

Yo lo hice asi:

let description = document.querySelector('#description');
let carbs = document.querySelector('#carbs');
let calories = document.querySelector('#calories');
let protein = document.querySelector('#protein');

const handleKeyPress = function () {
  this.classList.remove('is-invalid')
}

description.addEventListener('keypress', handleKeyPress)
carbs.addEventListener('keypress', handleKeyPress)
calories.addEventListener('keypress', handleKeyPress)
protein.addEventListener('keypress', handleKeyPress)

const validateInputs = () => {
  !description.value && description.classList.add('is-invalid')
  !calories.value && calories.classList.add('is-invalid')
  !carbs.value && carbs.classList.add('is-invalid')
  !protein.value && protein.classList.add('is-invalid')

  if (description.value && calories.value && carbs.value && protein.value) {
    console.log('Ok')
  }
}

Aqu铆 va mi c贸digo en vanilla

const $ = (id) => document.getElementById(id);

let formInputs = {
  description: $('description'),
  calories: $('calories'),
  carbs: $('carbs'),
  protein: $('protein'),
};

const init = () => {
  Object.keys(formInputs).forEach((key) => {
    formInputs[key].addEventListener('change', keyPress);
  });
};

const validateInputs = () => {
  let errors = 0;
  Object.keys(formInputs).forEach((key) => {
    if (!formInputs[key].value) {
      errors += 1;
      formInputs[key].classList.add('is-invalid')
    }
  });
  if (!errors) {
    console.log('ok');
  }
};

const keyPress = ({ target }) => {
  target.value ? target.classList.remove('is-invalid') : '';
};

Otra forma en vez de repetir tanto c贸digo y practicar con m茅todos de arrays es al momento de a帽adir el item usar el m茅todo every que devuelve tru o false si todos los elementos del array cumplen con la funci贸n

Este es mi aporte hecho con Vanilla JS:

const log = console.log
const id = document.getElementById.bind(document)

const $description = id(鈥榙escription鈥)
const $carbs = id(鈥榗arbs鈥)
const $calories = id(鈥榗alories鈥)
const $protein = id(鈥榩rotein鈥)
const $btnAdd = id(鈥榖tnAdd鈥)

//Creamos funcion para remover las clases
const removeClass = $element => {
$element.addEventListener(鈥榢eypress鈥, () =>
$element.classList.remove(鈥榠s-invalid鈥)
)
}

//
$btnAdd.addEventListener(鈥榗lick鈥, () => {
$description.value === 鈥樷 && $description.classList.add(鈥榠s-invalid鈥)
$carbs.value === 鈥樷 && $carbs.classList.add(鈥榠s-invalid鈥)
$calories.value === 鈥樷 && $calories.classList.add(鈥榠s-invalid鈥)
$protein.value === 鈥樷 && $protein.classList.add(鈥榠s-invalid鈥)

if ($description.value && $calories.value && $carbs.value && $protein.value) {
log(鈥極K!鈥)
}
})

removeClass($description)
removeClass($carbs)
removeClass($calories)
removeClass($protein)

mi soluci贸n con JS vanilla

const isEmpty = input => input.value == ''

const showInvalid = elem => {
    elem.classList.add("is-danger")
}

const removeInvalid = elem => {
    elem.classList.remove("is-danger")
}

const addKeydownReset = elem => {
    elem.addEventListener('keydown', ()=> {
        removeInvalid(elem)
    })
}

const validateInputs = (inputs) => {
    let isValidated = true;
    inputs.forEach(input => {
       if(isEmpty(input)){
        showInvalid(input) 
        isValidated = false
       } 
    });
    if(isValidated){
        console.log("Ok")
    }
}

document.querySelector('button').addEventListener('click', () => {
    let description = document.querySelector('#description');
    let calories = document.querySelector('#calories');
    let carbs = document.querySelector('#carbs');
    let protein = document.querySelector('#protein');
    const inputs = [description, calories, carbs, protein]
    
    validateInputs(inputs);
    inputs.forEach(elem =>{
        addKeydownReset(elem)
    })
})
const description = $("#description");
const calories = $("#calories");
const carbs = $("#carbs");
const proteins = $("#proteins");

const validateInputs = () => { 
    validateInput(description);
    validateInput(calories);
    validateInput(carbs);
    validateInput(proteins);
};

const validateInput = (value) => {
    if (value && value.val() && value.val().trim()) {   
        value.removeClass("is-invalid");
    }
    else {
        value.addClass("is-invalid");
    }
};

Una cosa, yo descargu茅 el boilerplate de la secci贸n de archivos y enlaces, pero ese no trae los ids agregados, faltar铆a agregarselos a los respectivos id鈥檚 de html