Home > Enterprise >  How to update values of filter of products when one is selected
How to update values of filter of products when one is selected

Time:12-18

I am doing a React app that brings data from the backend related to products, in a view that is a type of eCommerce or store the products are shown and I developed a logic to filter the products that are showed depending the filter parameter, so just the ones that match the filter will be rendered, the problem is that I can't figure how to update the values of the filters when them are selected, regarding that the view is updated but the values of the filters continue showing old data that is filtered.

The code I have right now is:

import React ,{useState} from 'react';
import { Card, Breadcrumb, BreadcrumbItem, CardBody} from 'reactstrap';
import {Link} from 'react-router-dom';
// import { Loading } from './LoadingComponent';
import {baseUrl} from '../../shared/baseUrl';


function formatMoney(x) {
  return x.toString().replace(/\B(?=(\d{3}) (?!\d))/g, ".");
}

function RenderStoreItem ({product}) {
  
  //this is a const to retrieve the images that are stored on images/products
  const imagePath = baseUrl   "images/products/";
      return (
          <Card className='product-card'>
              <Link to={ `/store/${product._id}` } style={{textDecoration:"none",color:"black"}}>
                  <img
                    className='card-img-top-store' 
                    src={imagePath   product.marca   "_"   product.linea   "_"   product.modelo   "/"   product.images[0]  } 
                    alt={product.marca} />
                  {/* display the CardTitle inside CardImgOverlay in the right bottom corner */}
                  
                  <CardBody>
                    <h3 >${formatMoney(product.price)}</h3>
                    <div>
                    <h5>{product.marca} - {product.linea}</h5>
                    </div>
                    <h5>{product.modelo}</h5>
                    

                  </CardBody>
              </Link>
          </Card>
      );
  }


const Store= ({products}) =>{


  //this are the filters to apply to the products, so just the products that match the filters will be displayed
  // but if the filter is empty then all the products will be displayed
  const [filter, setFilter] = useState({
    marca: '',
    linea: '',
    modelo: 0
  });


  // this function is called when the user select a filter
  // the filter is stored in the state filter
  // when a filter is selected the products are filtered automatically, no need to click a button

  
  const handleFilter = (event) => {
    const target = event.target;
    const value = target.value;
    const name = target.name;
    setFilter({
      ...filter,
      [name]: value
    });
  }
  
  // this function is called when the user click the button to clear the filters
  // the filter is set to empty
  const clearFilter = () => {
    setFilter({
      marca: '',
      linea: '',
      modelo: 0
    });
  }

  // get distinc values
  const distinctValues = (array, key) => {
    const values = array.map((product) => product[key]);
    const distinctValues = [...new Set(values)];
    return distinctValues;
  }

  // when a filter is selected the products are filtered automatically, no need to click a button
  // the products are filtered by any of the filter selected
  // taking into account that if the filter is empty then all the products will be displayed and that marca is a String, linea is a String and modelo is a number
  const filteredProducts = products.products.filter((product) => {
    if (filter.marca === '' && filter.linea === '' && filter.modelo === 0) {
      return product;
    } else if (filter.marca !== '' && filter.linea === '' && filter.modelo === 0) {
      return product.marca === filter.marca;
    } else if (filter.marca === '' && filter.linea !== '' && filter.modelo === 0) {
      return product.linea === filter.linea;
    } else if (filter.marca === '' && filter.linea === '' && filter.modelo !== 0) {
      return product.modelo == filter.modelo;
    } else if (filter.marca !== '' && filter.linea !== '' && filter.modelo === 0) {
      return product.marca === filter.marca && product.linea === filter.linea;
    } else if (filter.marca !== '' && filter.linea === '' && filter.modelo !== 0) {
      return product.marca === filter.marca && product.modelo == filter.modelo;
    } else if (filter.marca === '' && filter.linea !== '' && filter.modelo !== 0) {
      return product.linea === filter.linea && product.modelo == filter.modelo;
    } else if (filter.marca !== '' && filter.linea !== '' && filter.modelo !== 0) {
      return product.marca === filter.marca && product.linea === filter.linea && product.modelo == filter.modelo;
    }
  });



  const store= filteredProducts.map((product) => {
        return (
          <div key={product.id} id = 'products' className="col-12 col-md-4 py-2">
            <RenderStoreItem product={product}/>
          </div>
        );
    });
      return (
        <div className="container product">
            <div className="row">
                <Breadcrumb>
                    <BreadcrumbItem><Link to="/home">Inicio</Link></BreadcrumbItem>
                    <BreadcrumbItem active>Product</BreadcrumbItem>
                </Breadcrumb>
                <div className="col-12">
                    <h3>Store</h3>
                    <hr />
                </div>                
            </div>
            <div className="row">
              <div className='col-2'>
              {/* here will be the filters selected, will show the data from the products available in the options*/}
                <div className='row'>
                  <div className='col-12'>
                    
                    // HERE are the filters that must be updated
                    <h5>Filtros</h5>

                    <div className='row'>
                      <div className='col-12'>
                        <label htmlFor='marca'>Marca</label>
                        <select className='form-control' name='marca' id='marca' onChange={handleFilter}>
                          <option value=''>Todas</option>
                          {/* display distinct values */}
                          {distinctValues(products.products, 'marca').map((marca) => {
                            return (
                              <option key={marca} value={marca}>{marca}</option>
                            );
                          })}
                          
                        </select>
                      </div>

                      <div className='col-12'>
                        <label htmlFor='linea'>Linea</label>
                        <select className='form-control' name='linea' id='linea' onChange={handleFilter}>
                          <option value=''>Todas</option>
                          {/* display distinct values and next to it the frequency(number of occurences represented by countDistinctValues)*/}
                          {distinctValues(products.products, 'linea').map((linea) => {
                            return (
                              <option key={linea} value={linea}>{linea}</option>
                            );
                          })}
                        </select>
                      </div>

                      <div className='col-12'>
                        <label htmlFor='modelo'>Modelo</label>
                        <select className='form-control' name='modelo' id='modelo' onChange={handleFilter}>
                          <option value=''>Todos</option>
                          {/* display distinct values and next to it the frequency(number of occurences represented by countDistinctValues)*/}
                          {distinctValues(products.products, 'modelo').map((modelo) => {
                            return (
                              <option key={modelo} value={modelo}>{modelo}</option>
                            );
                          })}
                        </select>
                      </div>
                    </div>
                  </div>
                </div>
                
              </div>

              <div className='col-10'>
                <div className='row'>
                {store}
                </div>
              </div>
            </div>
        </div>
      );
  }


export default Store;

How can I update the data that is shown in the filters when one is selected and the view is updated, so the filtered data is no longer shown in the filters?

CodePudding user response:

Instead of using all the products to build the select elements, you can use only the ones that will be displayed to only show the available options, here is an example:

<select className='form-control' name='linea' id='linea' onChange={handleFilter}>
  <option value=''>Todas</option>
  {distinctValues(filteredProducts, 'linea').map((linea) => {
    return (
      <option key={linea} value={linea}>{linea}</option>
    );
   })}
</select>

Here, I've used distinctValues(filteredProducts, 'linea').map(..) instead of distinctValues(products.products, 'linea').map(..)

CodePudding user response:

To update the values of the filters when they are selected, you can use the "useEffect" hook to listen for changes in the "filter" state and update the valus of the filters =>

// other code

const Store = ({ products }) => {
  const [filter, setFilter] = useState({
    marca: '',
    linea: '',
    modelo: 0
  });

  // listen for changes in the filter state
  useEffect(() => {
    // update the values of the filters here
  }, [filter]);

  // other code
}

AND inside the "useEffect" hook, you can use the "getElementById" to get the elements for the filters and update their value isng the .value property.

// listen for changes in the filter state

useEffect(() =>{
// update the values of the filters here...
document.getElementByid("marca").value = filter.marca;
// the same for "linea" and "modelo"
, [filter]}

Let me know if its clear or i didnt understand your question

Edit:

Second option

another way you can do this is by adding an onChange event to your filter elements (e.g., ", "). You can then use this event to call the handleFilter function that you have defined.

Like this =>

<select name="marca" value={filter.marca} onChange={handleFilter}>
  <option value="">All</option>
  {distinctValues(products.products, 'marca').map((marca) => (
    <option key={marca} value={marca}>
      {marca}
    </option>
  ))}
</select>
  • Related