skip to Main Content

Hello everyone I have a project on NextJS. There is a portfolio of works that is generated from json.

[
    {
        "title": "Плагин WordPress для Рекомендательного виджета Яндекса",
        "image": "/images/works/yk.jpg",
        "year": 2022,
        "category": "WordPress",
        "link": "https://188.ru/",
        "description": "Заказчик использует на некоторых сайтах виджет рекомендаций от Яндекса, который позволяет показывать ссылки на статьи сайта вместе с рекламой Яндекса. Проблема в том, что система от отечественного поисковика не очень умная и тянет в виджет не только статьи, но и много чего не нужного. Я написал микроплагин, который дает возможность автоматически проставлять специальный тег на страницах, которые не нужно показывать в виджете, а также позволяет исключать некоторые статьи из виджета вручную"
    },
    {
        "title": "Сайт студии переводов «АкадемПеревод»",
        "image": "/images/works/ap.jpg",
        "year": 2022,
        "category": "WordPress",
        "link": "https://academperevod.ru/",
        "description": "Осовременивали сайт, не перезжая с WordPress на другие платформы. В основе проекта - дизайн в Фигме и редактор Elementor. Сложная, долгая и кропотливая работа",
        "scroll": true
    }
]

I decided to filter the elements by category, which is specified by json.
Here is my component that displays a list of categories and adds filtering on the page above the list of all portfolio works:

//filter-work.js

import works from "@/content/works/data.json"


export default function FilterWork({selectedCat, onSelect}) {

    const splitCats = works.flatMap((w) => w.category.split());
    const categories = Array.from(new Set(splitCats));


    return (
        <div>
            <ul>
                <li
                    className={!selectedCat ? "bg-indigo-50 p-2 rounded-md" : "p-2"}
                    onClick={() => onSelect("")}
                >
                    <a>Все</a>
                </li>
                {categories.map((category, i) => {
                    const isSelected = category === selectedCat
                    return (
                        <li key={i} item={category}
                            className={isSelected ? "bg-indigo-50 p-2 rounded-md" : "p-2"}
                            onClick={() => onSelect(category)}
                        >
                            {category}
                        </li>
                    )


                    })}
            </ul>

        </div>
    )
}

And here is the code of the page that displays both a list of all the works and a list of categories in the filter. My main filter code is also here.

import { useState } from "react"
import Seo from "@/components/global/seo";
import Work from "../components/work";
import {getAllWork} from "@/lib/getAllData";
import styles from "@/styles/home/featuredWork.module.css"

import FilterWork from "@/components/filter-work";

export async function getStaticProps() {
    const work = getAllWork();

    return {
        props: {
            work,
        },
    };
}

export default function WorkPage({work}) {

     const [selectedCat, setSelectedCat] = useState("");

    const filteredCat = selectedCat ? work.filter((listItem) => listItem.category.includes(selectedCat))
    : work;

    return (
        <div>
            <Seo
                title="Все работы Колтан Леонида"
                description="Здесь собраны некоторые из работ разработчика Колтан Леонида"
                ogImageUrl={`http://localhost:3000/api/og?title=Все работы Колтан Леонида&description=Здесь собраны некоторые из работ разработчика Колтан Леонида`}
            />
            <section className='px-6'>
                <div className='wrapper'>
                    <h1 className='sectionTitle'>Проекты</h1>
                    <FilterWork
                        selectedCat={selectedCat}
                        onSelect={setSelectedCat}
                    />
                    <div className={styles.featuredWorkInner}>
                        {filteredCat.map((workItem) => (
                            <Work key={workItem.title} item={workItem} />
                        ))}
                    </div>
                </div>
            </section>
        </div>
    )
}

The filter works, here it is on the test domain – https://next-site-ivory-six.vercel.app/work . The question is that I would like to add another filter by year, which is also specified in the json file. I tried to do something like this:

    const filteredCat = selectedCat ? work.filter((listItem) => listItem.category.includes(selectedCat)) && work.filter((listItem) => listItem.year.toString().includes(selectedCat)): work;

But nothing works like that. It is filtered either by categories or by years depending on the operator that I will specify in the code above (&& or ||), and I need there to be mutual filtering – that is, if I chose WordPress and 2022, so that only works with the WordPress category with the year 2022 are displayed. How to do it?

2

Answers


  1. For multiple filters you need to define your filter function as follows

    const filteredWork = work.filter(w => {
       const catFilter = selectedCat ? w.category === selectedCat : true; // true if no category selected
       const yearFilter = selectedYear ? w.year === selectedYear : true; // true if no year selected
       return catFilter && yearFilter;
    })
    

    As per the comment below, either have selectedYear as number or use == in place of ===.

    Login or Signup to reply.
  2. const work = [{
        "title": "Плагин WordPress для Рекомендательного виджета Яндекса",
        "image": "/images/works/yk.jpg",
        "year": 2022,
        "category": "WordPress",
        "link": "https://188.ru/",
        "description": "Заказчик использует на некоторых сайтах виджет рекомендаций от Яндекса, который позволяет показывать ссылки на статьи сайта вместе с рекламой Яндекса. Проблема в том, что система от отечественного поисковика не очень умная и тянет в виджет не только статьи, но и много чего не нужного. Я написал микроплагин, который дает возможность автоматически проставлять специальный тег на страницах, которые не нужно показывать в виджете, а также позволяет исключать некоторые статьи из виджета вручную"
      },
      {
        "title": "Сайт студии переводов «АкадемПеревод»",
        "image": "/images/works/ap.jpg",
        "year": 2022,
        "category": "WordPress",
        "link": "https://academperevod.ru/",
        "description": "Осовременивали сайт, не перезжая с WordPress на другие платформы. В основе проекта - дизайн в Фигме и редактор Elementor. Сложная, долгая и кропотливая работа",
        "scroll": true
      }
    ];
    
    const selected = {
      cat: "otherCat",
      year: "2021"
    };
    
    document.getElementById("year").addEventListener("change", e => {
      console.log(e.target.value);
      selected.year = e.target.value;
      printFiltered();
    });
    
    document.getElementById("cat").addEventListener("change", e => {
      console.log(e.target.value);
      selected.cat = e.target.value;
      printFiltered();
    });
    
    function printFiltered() {
      const filteredWork = work.filter(w => {
        const catFilter = selected.cat ? w.category === selected.cat : true; // true if no category selected
        const yearFilter = selected.year ? w.year == selected.year : true; // true if no year selected
        return catFilter && yearFilter;
      })
    
      console.log(filteredWork);
    }
    <select id="year">
      <option value="2021">2021</option>
      <option value="2022">2022</option>
    </select>
    
    <select id="cat">
      <option value="otherCat">otherCat</option>
      <option value="WordPress">WordPress</option>
    </select>
    
    <p id="result" />

    Note that I am using == instead of using parseInt for year.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search