Wednesday, 7 October 2020

Reactjs - Isotope layout - using data-attributes to filter/sort

I am trying to streamline the isotope handler in a react component -- I want to create filter options that would be like catergory[metal] or catergory[transition] -- and combo filters like catergory[metal, transition].

the sandbox for this. https://codesandbox.io/s/brave-sea-tnih7

So like filterFns[ filterValue, "param2" ] -- how to push 2 params into the filter functions - rather than these fixed greaterThan50 -- a "greaterThan(50)", "greaterThan(5) -- this dynamic filtering type of handler "

enter image description here

import React, { Component } from 'react';

import Isotope from 'isotope-layout';

import Button from '@material-ui/core/Button';
import ButtonGroup from '@material-ui/core/ButtonGroup';

import GenericForm from '../GenericForm/GenericForm';

import './IsotopeHandler.scss';


class IsotopeHandler extends Component {
    constructor() {
      super();
      this.myRef = React.createRef();


      let items = [{
        "name": "Mercury",
        "category": "transition",
        "weight": "122",
        "symbol": "Hg",
        "number": 12,
        "custom": "a",
        "isgas": false
      }, {
        "name": "Tellurium",
        "category": "metal",
        "weight": "12",
        "symbol": "Te",
        "number": 232,
        "custom": "b",
        "isgas": false
      }, {
        "name": "Bismuth",
        "category": "rock",
        "weight": "2200.59",
        "symbol": "Bi",
        "number": 1666,
        "custom": "c",
        "isgas": false
      }, {
        "name": "Cadmium",
        "category": "metal",
        "weight": "1200",
        "symbol": "Cd",
        "number": 454,
        "custom": "d",
        "isgas": false
      }, {
        "name": "Bosim",
        "category": "gas",
        "weight": "100",
        "symbol": "Gs",
        "number": 454,
        "custom": "e",
        "isgas": true
      }, {
        "name": "xosim",
        "category": "gas",
        "weight": "100",
        "symbol": "xs",
        "number": 44,
        "custom": "f",
        "isgas": true
      }]

      this.state = { sortBy: 'original-order', items: items };

      this.onFilterHandler = this.onFilterHandler.bind(this);
      this.onSortHandler = this.onSortHandler.bind(this);
    }

    onSortHandler(sortValue){
      if(sortValue){
        console.log("sortValue", sortValue);
        let bool = this.state.bool;
        let options = { sortBy: sortValue };
        
        options = Object.assign(options, {
            sortAscending: (bool = !bool),
        });        

        this.setState({ bool: bool });
        this.setState({ sortBy: sortValue });

        this.state.iso.arrange(options);
      }
    }

    onFilterHandler(filterName, filterField, filterValue){

        var filterFns = {
          //match
          matches: function(itemElem) {
            var values = itemElem.getAttribute('data-'+filterField);
            return values.match(filterValue);
          },

          //greaterThan 
          greaterThan: function(itemElem) {
            var number = itemElem.getAttribute('data-'+filterField);
            return parseInt(number, 10) > filterValue;
          },

          //lessThan 
          lessThan: function(itemElem) {
            var number = itemElem.getAttribute('data-'+filterField);
            return parseInt(number, 10) < filterValue;
          }, 

          //Between 
          between: function(itemElem) {
            var number = itemElem.getAttribute('data-'+filterField);
            return parseInt(number, 10) > parseInt(filterValue.split(",")[0], 10) && parseInt(number, 10) < parseInt(filterValue.split(",")[1], 10);
          }, 

        };

        // use matching filter function
        let val = filterFns[filterName] || filterValue;

        this.state.iso.arrange({ filter: val });
    }

    submitFilterFormHandler(data){
      console.log("data now with parent", data);

      if(data){
        //open dialog box
        //console.log("this", this);
      }
    }

    componentDidMount(){
        // init Isotope
        var iso = new Isotope(this.myRef.current, {
          itemSelector: '.grid-item',
          layoutMode: 'fitRows',
          getSortData: this.getCustomSortAttributes(this.state.items[0])
        });

        this.setState({ iso: iso });
        console.log("iso",iso);
    }

    getCustomSortAttributes(item){
      let keys = Object.keys(item);
      let dataObj = {};
      
      for (let i = 0; i < keys.length; i++) {
        var obj = {
          [keys[i]]: '[data-'+keys[i]+']'
        }
        dataObj = {...obj, ...dataObj}
      }
      return dataObj;      
    }

    attributeGeneration(item){
      let keys = Object.keys(item);
      let dataObj = {};
      
      for (let i = 0; i < keys.length; i++) {
        var obj = {
          ["data-"+keys[i]]: item[keys[i]]
        }
        dataObj = {...obj, ...dataObj}
      }
      return dataObj;
    }

    render() {


        var sorts = [{
          "label": "Original Order",
          "value": "original-order"
        },{
          "label": "Name",
          "value": "name"
        },{
          "label": "Symbol",
          "value": "symbol"
        },{
          "label": "Number",
          "value": "number"
        },{
          "label": "Weight",
          "value": "weight"
        },{
          "label": "Category",
          "value": "category"
        },{
          "label": "Custom",
          "value": "custom"
        }]


        let filters = [{
            "label": "show all",
            "params": {
              "filter": "showAll",
              "field": "",
              "value": "*"
            }
          },{
            "label": "number > 50",
            "params": {
              "filter": "greaterThan",
              "field": "number",
              "value": 50
            }
          },{
            "label": "number < 350",
            "params": {
              "filter": "lessThan",
              "field": "number",
              "value": 350
            }
          },{
            "label": "between- number < 350 && number < 600",
            "params": {
              "filter": "between",
              "field": "number",
              "value": "350,600"
            }
          },{
            "label": "metal category",
            "params": {
              "filter": "matches",
              "field": "category",
              "value": "metal"
            }
          },{
            "label": "metal transition",
            "params": {
              "filter": "matches",
              "field": "category",
              "value": "transition"
            }
          },{
            "label": "metal gas and transition",
            "params": {
              "filter": "matches",
              "field": "category",
              "value": "gas|transition"
            }
          },{
            "label": "isGas",
            "params": {
              "filter": "matches",
              "field": "isgas",
              "value": true
            }
          }]



        let initialFilterFormValues = {
          "manual": "type to filter"
        }

        let fieldsFilterForm = [
            {
              "type": "text",
              "label": "Manual Entry",
              "name": ["manual"],
              "options": []
            },
            {
              "type": "buttons",
              "label": "Sweets2",
              "name": ["sweets2"],
              "options": [
                {
                  "label": "Sherbert",
                  "value": "0"
                },
                {
                  "label": "Peach Jam",
                  "value": "1"
                },
                {
                  "label": "Almond Butter",
                  "value": "2"
                }
              ],
              //"validate": ["required"],
            }            
          ];

        let buttonsFilterForm = [
          /*{
            "label": "Submit3",
            "variant": "contained",
            "color": "primary",
            "type": "submit",
            "disabled": ["submitting"],
            "onClick" : null
          }*/
        ];


        return (
          <div 
            className={"isotope"}
          >

            <div className="button-group filters-button-group">
              <ButtonGroup variant="outlined" color="primary" aria-label="outlined primary button group">
              {                
                filters.map((item, j) => {
                  return(
                    <Button 
                      key={j} 
                      className="button" 
                      onClick={() => this.onFilterHandler(item.params.filter, item.params.field, item.params.value)}
                    >
                      {item.label}
                    </Button>
                  )
                })
              }
              {/*
              <Button className="button" data-filter=".alkali, .alkaline-earth">alkali and alkaline-earth</Button>
              <Button className="button" data-filter=":not(.transition)">not transition</Button>
              <Button className="button" data-filter=".metal:not(.transition)">metal but not transition</Button>
              */}
              </ButtonGroup>   
            </div>

            <div className="button-group sort-by-button-group">
              <ButtonGroup variant="outlined" color="primary" aria-label="outlined primary button group">
                {                
                  sorts.map((item, j) => {
                    return(
                      <Button 
                        key={j} 
                        className="button" 
                        onClick={() => this.onSortHandler(item.value)}
                      >
                        {item.label}
                      </Button>
                    )
                  })
                }                
              </ButtonGroup>
            </div>


            {/*
            <GenericForm 
              initialValues={initialFilterFormValues} 
              fields={fieldsFilterForm}
              buttons={buttonsFilterForm}
              submitHandler={this.submitFilterFormHandler}
            />
            */}


            <div 
              className="grid" 
              ref={this.myRef}
            >
              {
                this.state.items.map((item, j) => {
                  return(
                    <div
                      key={j} 
                      className="grid-item"
                      {...this.attributeGeneration(item)}
                    >
                      <h3>{item.name}</h3>
                      <p>{item.weight}</p>
                      <p>{item.number}</p>
                      <p>{item.symbol}</p>
                      <p>{item.category}</p>
                    </div>
                  )
                })
              }
            </div>

          </div>
        );
    }
}

export default IsotopeHandler;


from Reactjs - Isotope layout - using data-attributes to filter/sort

No comments:

Post a Comment