Aún no tienes acceso a esta clase

Crea una cuenta y continúa viendo este curso

Proyecto: Actualizando el total de calorías

19/23
Recursos

Aportes 13

Preguntas 0

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad? Crea una cuenta o inicia sesión.

Comprendo la facilidad que ofrece el uso de jQuery en el proyecto para seleccionar elementos del DOM; pero, creo que hubiera estado más acorde con la onda EcmaSript-ProgramaciónFuncional, si en lugar de jQuery, se hubiera usado JavaScript vanilla: document.querySelector('#id-selector')

¡Aún así, el curso va muy bien!
Seguimos.

Si les parece mas rápido y sencillo utilizar la nomenclatura de jQuery $('#element') para acceder a los elementos del dom, pueden hacer uso de esta sin necesidad de cargar la librería con la siguiente función:

//probando en la home de platzi (https://platzi.com/) desde la consola

const $ = element => document.querySelector(element)
const spanNumber = $('#home-v4 > div > div.HeroContent > div > div.HeroContent-content > div.HeroContent-stats > div > div:nth-child(1) > span:nth-child(1)')
console.log(spanNumber) // nos mostrara un elemento span

AVISO: de esta forma no podrás usar los métodos de jQuery como val() o text() ,pero tendrás disponibles todos los métodos nativos de los elementos HTML como .innerText o .textContent entre muchísimos mas claro.

VanillaJS

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


const attrsToString = (obj = {}) => {

  const keys = Object.keys(obj)
  let attrs = []

  for(let i = 0; i < keys.length; i++){
    let attr = keys[i]
    attrs.push(`${attr}="${obj[attr]}"`)
  }
  
  const string = attrs.join('')
  return string
}// string

const tagAttrs = obj => (content = '') => 
`<${obj.tag} ${obj.attrs ? ' ' : ''}${attrsToString(obj.attrs)}>content<${obj.tag}>`

const tag = t => {
  if (typeof t === 'String'){
    tagAttrs({tag: t})
  }else{
    tagAttrs(t)
  }
}

const tableRowTag = tag('tr')
// const tableRow = items => tableRowTag(tableCells(items))
const tableRow = items => compose(tableRowTag, tableCells)(items)

const tableCell = tag('td')
const tableCells = items => item.map(tableCell).join('')


let list = []
let description = document.getElementById('description')
let calories = document.getElementById('calories')
let carbs = document.getElementById('carbs')
let protein = document.getElementById('proteins')
let btn = document.getElementById('btn')

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!')
    add()
    cleanInputs()
    updateTotals()
  }
}

btn.addEventListener('click', validateInputs)

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

const add = () => {
  const newItem = {
    description: description.value,
    calories: parseInt(calories.value),
    carbs: parseInt(carbs.value),
    proteins: parseInt(proteins.value)
  }
  list.push(newItem)
  console.log(list)
}

const updateTotals = () => {
  let calories = 0, carbs = 0, proteins = 0

  list.map(item => {
    calories += item.calories
    carbs += item.carbs
    proteins += item.proteins
  })

  document.getElementById('totalCalories').innerHTML = calories
  document.getElementById('totalCarbs').innerHTML = carbs
  document.getElementById('totalProteins').innerHTML = proteins

}

const cleanInputs = () => {
  description.value = ' '
  calories.value = ' '
  carbs.value = ' '
  protein.value = ' '
}

let updateTotals = () => {
let scal = items.reduce((acum,item) => acum +=parseInt(item.cal) ,0)
let scarb = items.reduce((acum,item) => acum +=parseInt(item.carb) ,0)
let sprote = items.reduce((acum,item) => acum +=parseInt(item.prote) ,0)
}

Veo esto y veo Vue y recuerdo por qué amo Vue jaja, con Vue solo tienes que actualizar el valor y ya Vue se encarga de actualizar todo el en DOM xD

Ejemplo utlizando JS puro o lo que tambien se conoce como vanilla

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";
const SUCCESS_CLASS = "is-valid";

// Arreglo de elementos
const LIST = [];

// consiguiendo los atributes para las etiquetas HTML
const attributesToString = (obj = {}) => {
    const ENTRIES = Object.entries(obj);
    const ATTRS = [];
    for (let i = 0; i < ENTRIES.length; i += 1) {
        const AUX = ENTRIES[i];
        const ATTR = AUX[0];
        const VALUE = AUX[1];
        ATTRS.push(`${ATTR}="${VALUE}"`);
    }
    return ATTRS.join("");
};

// Creando etiquetas html con atributos
const createTagAttr = obj => (content = "") => {
    const { tag, attr } = obj;
    return `
      <${tag}${attr ? ` ${attributesToString(attr)}` : ""}>
        ${content}
      </${tag}>`;
};

// Generando tag de maner dinamica
const createTag = (tag) => {
    const TAG = (typeof tag === "string")
        ? createTagAttr({ tag })
        : createTagAttr(tag);
    return TAG;
};

// 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));

// Limpiando inputs
const cleanInputs = () => {
    $DESCRIPTION.classList.remove(SUCCESS_CLASS);
    $DESCRIPTION.value = "";
    $CALORIAS.classList.remove(SUCCESS_CLASS);
    $CALORIAS.value = "";
    $CARBOIDRATOS.classList.remove(SUCCESS_CLASS);
    $CARBOIDRATOS.value = "";
    $PROTEINAS.classList.remove(SUCCESS_CLASS);
    $PROTEINAS.value = "";
};

const updateTotals = () => {
    let carboidratos = 0;
    let proteinas = 0;
    let calorias = 0;
    // Por buenas praxticas se utiliza un forEach y cumple la mism funcion que se busca
    // practicamente una funcion de alto orden, no utiizo el map por que  map siempre regresa
    // algo y de momento no importa capturar lo que regresa la iteracion que realizamos.
    LIST.forEach((item) => {
        carboidratos += item.carboidratos;
        proteinas += item.proteinas;
        calorias += item.calorias;
    });
    document.querySelector("#totalCalorias").textContent = calorias;
    document.querySelector("#totalCarboidratos").textContent = carboidratos;
    document.querySelector("#totalProteinas").textContent = proteinas;
};

// Agregar elementos en la lista
const addElement = () => {
    const newItem = {
        description: $DESCRIPTION.value,
        calorias: parseInt($CALORIAS.value, 10),
        carboidratos: parseInt($CARBOIDRATOS.value, 10),
        proteinas: parseInt($PROTEINAS.value, 10),
    };
    LIST.push(newItem);
    cleanInputs();
    updateTotals();
};

// 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) ? SUCCESS_CLASS : ERROR_CLASS);
    $DESCRIPTION.classList.add(DESCRIPTION_CLASS);

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

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

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

    if ($DESCRIPTION.value && $CALORIAS.value && $CARBOIDRATOS.value && $PROTEINAS.value) {
        addElement();
    }
};

Este es mi código para la parte de updateTotals, utilize textContent, ya que innerHTML no me convence mucho para este caso

//Las puse a parte por si se usan en otro momento, si no simplemente se pasan a la función
const totalCalories = document.getElementById('totalCalories')
const totalCarbs = document.getElementById('totalCarbs')
const totalProteins = document.getElementById('totalProteins')

const updateTotals = () => {
	let calories = 0, carbs = 0, protein= 0
	list.map(item => {
		calories += item.calories,
		carbs += item.carbs,
		protein += item.protein
	})
	console.log(calories)
	totalCalories.textContent = calories
	totalCarbs.textContent = carbs
	totalProteins.textContent = protein
}
// update total inputs
function updateTotals () {
  let calories = 0, carbs = 0, protein = 0;

  List.map(item => {
    calories += item.calories;
    carbs += item.carbs;
    protein += item.protein;
  })

  document.querySelector('#totalCalories').innerHTML = calories;
  document.querySelector('#totalCarbs').innerHTML = carbs;
  document.querySelector('#totalProtein').innerHTML = protein;

}```

Desde mi personal punto de vista, yo hubiera hecho la función con un .forEach, ya que el este método hace casi lo que hace un ciclo for, lo que vendría siendo el recorrer todo el arreglo y ya, sin regresar ningún tipo de array nuevo, como en el caso de .map

Mi función con parseFloat porque me estaba concatenando!


const updateTotals = () => {
  let cal = 0, carb = 0, prot = 0;
  list.map(item => {
    cal += parseFloat(item.calories),
    carb += parseFloat(item.carbs),
    prot += parseFloat(item.protein)
  })
  document.getElementById('totalCalories').textContent= cal;
  document.getElementById('totalCarbs').textContent= carb;
  document.getElementById('totalProtein').textContent= prot;
}```

Para los que validaron anteriormente como yo lo hice, en esta clase les arrojará un error, hay que agregar una línea de código en la siguiente función.

// tagAttrs
function tagAttrs (obj, content = '') {
  if (!obj.attrs) obj = {...obj, attrs: {}}

  return (
    `<${obj.tag}${Object.keys(obj.attrs).length > 0 && ' '}${attrsToString(obj.attrs)}>${content}</${obj.tag}>`
  )
}```

Yo lo hice así:

const updateTotals = () => {
  let calories = 0, carbs = 0, protein = 0;

  list.forEach(item => {
    calories += item.calories
    carbs += item.carbs
    protein += item.protein
  })

  const query = document.querySelector.bind(document)
  query('#totalCalories').textContent = calories
  query('#totalCarbs').textContent = carbs
  query('#totalProtein').textContent = protein
}

Así quedó en VanillaJS

const $totalCalories = document.getElementById("totalCalories");
const $totalCarbs = document.getElementById("totalCarbs");
const $totalProtein = document.getElementById("totalProtein");

const updateTotals = () => {
  let calories = 0;
  let carbs = 0;
  let protein = 0;

  list.map((item) => {
    calories += item.calories;
    carbs += item.carbs;
    protein += item.protein;
  });

  $totalCalories.textContent = calories;
  $totalCarbs.textContent = carbs;
  $totalProtein.textContent = protein;
};

.textContent resulta text/plain mientras que innerHTML resulta text/html