Home > Blockchain >  How can I count the numbers of checkbox selected?
How can I count the numbers of checkbox selected?

Time:12-16

I want to count the numbers of checkbox selected and showed inside the button.

The functionality is in the Card component (also the button and input checkbox)

import React, { useState, useEffect } from "react";
import "./card.css";
import semImagem from "../../../../../fileContents/imagensVitrineProfissional/no-image.png";

function Card(props) {
  let nomeEmpresa = props.dadosProfissionais.nomeEmpresa;
  let segmento = props.dadosProfissionais.segmento;
  let valorMinimo = props.dadosProfissionais.valorMinimo;
  let cidade = props.dadosProfissionais.cidade;
  let estado = props.dadosProfissionais.estado;
  let idProfissional = props.dadosProfissionais.idProfissional;
  let imagemVitrine = props.dadosProfissionais.imagemMarketplace;

  let imagemArquivo = imagemVitrine ? imagemVitrine : semImagem;

  const [checkedState, setCheckedState] = useState({});

  const handleOnChange = (e) => {
    setCheckedState((p) => ({ ...p, [e.target.name]: e.target.checked }));
  };


  console.log(Object.keys(checkedState).filter((i) => checkedState[i]).length)

  return (
    <>
      <div className="card__profissional" key={idProfissional}>
        <div className="card__header">
          <img
            className="card-imagem"
            src={imagemArquivo}
            alt={`${nomeEmpresa}`}
          />
        </div>
        <div className="card__body">
          <h2 className="card__titulo">{nomeEmpresa}</h2>
          <span className="tag">{cidade}</span>
          <div className="checkbox">
            <label className="checkbox-label">
              Orçamento
              <input
                type="checkbox"
                className="checkbox-input"
                name={nomeEmpresa}
                value={nomeEmpresa}
                checked={checkedState[nomeEmpresa] || false}
                onChange={handleOnChange}
              />
              <span className="checkmark"></span>
            </label>
          </div>
        </div>
      </div>
      <button type="submit" className="botao-orcamento">
        Solicitar Orçamento (
        {Object.keys(checkedState).filter((i) => checkedState[i]).length})
      </button>
    </>
  );
}

export default Card;

I did a console.log, and it's returning this: Notice that the button doesn't show the count

[enter image description here

Here is the parent component:

import React, { useEffect, useState } from "react";
import "./popupOrcamentoSimultaneo.css";
import Card from "./Card";
import api from "../../../../api";

function PopupOrcamentoSimultaneo({ setOpenPopup }) {
  const [profissionais, setProfissionais] = useState([]);
  const [value, setValue] = useState(
    "Olá! Vamos nos casar e gostariamos de mais informações sobre seu serviço."
  );

  const [profissionalID, setProfissionalID] = useState([]);

  useEffect(() => {
    api.get("profissionais/listarTodos/").then(({ data }) => {
      setProfissionais(data);
    });
  }, []);

  let urlParam = window.location.href.split("=");
  let idProfissionalURL = null;

  if (urlParam.length > 1) {
    idProfissionalURL = urlParam[1];
  }

  useEffect(() => {
    api.get(`detalhesProfissional/${idProfissionalURL}`).then(({ data }) => {
      setProfissionalID(data);
    });
  }, []);

  let testID = profissionalID.idProfissional;
  let cardsProfissionais = profissionais;
  let listaCardsProfissionais = [];
  const found = cardsProfissionais.find((obj) => obj.idProfissional == testID);
  const foundSegmento = found?.segmento;

  for (let i = 0; i < cardsProfissionais.length; i  ) {
    if (cardsProfissionais[i].segmento == foundSegmento) {
      listaCardsProfissionais.push(
        <Card key={i} dadosProfissionais={cardsProfissionais[i]} />
      );
      if (listaCardsProfissionais.length == 4) {
        break;
      }
    }
  }

  const changeValue = (e) => {
    setValue(e.target.value);
  };

  return (
    <div className="popup">
      <div className="popup__container">
        <div className="close-container" onClick={() => setOpenPopup(false)}>
          <i className="fa-solid fa-xmark"></i>
        </div>
        <h2 className="popup__titulo">
          Profissionais desse segmento recomendados para você.
        </h2>

        <div className="cards__profissionais">{listaCardsProfissionais}</div>

        <div className="input-box">
          <label for="input" className="input-label">
            Escreva sua mensagem
          </label>
          <div>
            <input
              type="text"
              id="input"
              className="input-text"
              placeholder="Olá! Vamos nos casar e gostaríamos de mais informações sobre seu serviço."
              value={value}
              onChange={changeValue}
            />
            <i className="fa-solid fa-pencil"></i>
          </div>
        </div>
      </div>
    </div>
  );
}

export default PopupOrcamentoSimultaneo;

I appreciate any help!

CodePudding user response:

My initial thoughts are that you're tracking the state of the check for each checkbox independently in each card. If that's the case, then it can't possibly know if others are being checked, because each individual card has its own checkedState.

There are a few approaches you can use to fix it, but I think the easiest one for you is to handle the checkedState logic inside the parent component using a function that you later pass into the props for each Card. Then you can directly pass that prop as the onChange handler for each checkbox.

Then I would move the "Solicitar Orçamento" button to be in the parent component.

Parent:

function PopupOrcamentoSimultaneo({ setOpenPopup }) {
  // Other code

  let testID = profissionalID.idProfissional;
  let cardsProfissionais = profissionais;
  let listaCardsProfissionais = [];
  const found = cardsProfissionais.find((obj) => obj.idProfissional == testID);
  const foundSegmento = found?.segmento;

  const [checkedState, setCheckedState] = useState({});

  const handleOnChange = (e) => {
    setCheckedState((p) => ({ ...p, [e.target.name]: e.target.checked }));
  };

  for (let i = 0; i < cardsProfissionais.length; i  ) {
    if (cardsProfissionais[i].segmento == foundSegmento) {
      listaCardsProfissionais.push(
        <Card key={i} dadosProfissionais={cardsProfissionais[i]} handleOnChange={handleOnChange} />
      );
      if (listaCardsProfissionais.length == 4) {
        break;
      }
    }
  }

// ... other code

 return (
    <div className="popup">
      <div className="popup__container">
        <div className="close-container" onClick={() => setOpenPopup(false)}>
          <i className="fa-solid fa-xmark"></i>
        </div>
        <h2 className="popup__titulo">
          Profissionais desse segmento recomendados para você.
        </h2>

        <div className="cards__profissionais">{listaCardsProfissionais}</div>

        <div className="input-box">
          <label for="input" className="input-label">
            Escreva sua mensagem
          </label>
          <div>
            <input
              type="text"
              id="input"
              className="input-text"
              placeholder="Olá! Vamos nos casar e gostaríamos de mais informações sobre seu serviço."
              value={value}
              onChange={changeValue}
            />
            <i className="fa-solid fa-pencil"></i>
          </div>
      <button type="submit" className="botao-orcamento">
        Solicitar Orçamento (
        {Object.keys(checkedState).filter((i) => checkedState[i]).length})
      </button>
        </div>
      </div>
    </div>
  );
}

Child

function Card(props) {
   // Other code

  return (
    <>
         // Other Code
          <div className="checkbox">
            <label className="checkbox-label">
              Orçamento
              <input
                /* Other props */
                onChange={props.handleOnChange}
              />
              <span className="checkmark"></span>
            </label>
          </div>
        </div>
      </div>
    </>
  );
}

You might need to mess around with your CSS a bit to get it looking right, but this should correct your logic.

  • Related