在NextJS中通过两个查询筛选条目

huangapple go评论65阅读模式
英文:

Filter entries in NextJS by two queries

问题

// Filter by category and year
const filteredWorks = work.filter((listItem) => {
  if (selectedCat && listItem.category.includes(selectedCat)) {
    if (selectedYear === '' || listItem.year.toString() === selectedYear) {
      return true;
    }
  } else if (selectedYear !== '' && listItem.year.toString() === selectedYear) {
    return true;
  }
  return false;
});

// Check if no elements are found
if (filteredWorks.length === 0) {
  return <p>Nothing found. Select other filters.</p>;
}

// Display the filtered works
return (
  <div>
    {/* Your code to display filteredWorks */}
  </div>
);

This code snippet should help you filter the works by both category and year simultaneously and display a message if no elements are found. Make sure to define selectedYear appropriately based on the user's selection for the year filter.

英文:

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

[
	{
		&quot;title&quot;: &quot;Плагин WordPress для Рекомендательного виджета Яндекса&quot;,
		&quot;image&quot;: &quot;/images/works/yk.jpg&quot;,
		&quot;year&quot;: 2022,
		&quot;category&quot;: &quot;WordPress&quot;,
		&quot;link&quot;: &quot;https://188.ru/&quot;,
		&quot;description&quot;: &quot;Заказчик использует на некоторых сайтах виджет рекомендаций от Яндекса, который позволяет показывать ссылки на статьи сайта вместе с рекламой Яндекса. Проблема в том, что система от отечественного поисковика не очень умная и тянет в виджет не только статьи, но и много чего не нужного. Я написал микроплагин, который дает возможность автоматически проставлять специальный тег на страницах, которые не нужно показывать в виджете, а также позволяет исключать некоторые статьи из виджета вручную&quot;
	},
	{
		&quot;title&quot;: &quot;Сайт студии переводов &#171;АкадемПеревод&#187;&quot;,
		&quot;image&quot;: &quot;/images/works/ap.jpg&quot;,
		&quot;year&quot;: 2022,
		&quot;category&quot;: &quot;WordPress&quot;,
		&quot;link&quot;: &quot;https://academperevod.ru/&quot;,
		&quot;description&quot;: &quot;Осовременивали сайт, не перезжая с WordPress на другие платформы. В основе проекта - дизайн в Фигме и редактор Elementor. Сложная, долгая и кропотливая работа&quot;,
		&quot;scroll&quot;: 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 &quot;@/content/works/data.json&quot;


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

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


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


                    })}
            &lt;/ul&gt;

        &lt;/div&gt;
    )
}

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 &quot;react&quot;
import Seo from &quot;@/components/global/seo&quot;;
import Work from &quot;../components/work&quot;;
import {getAllWork} from &quot;@/lib/getAllData&quot;;
import styles from &quot;@/styles/home/featuredWork.module.css&quot;

import FilterWork from &quot;@/components/filter-work&quot;;

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

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

export default function WorkPage({work}) {

     const [selectedCat, setSelectedCat] = useState(&quot;&quot;);

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

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

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) =&gt; listItem.category.includes(selectedCat)) &amp;&amp; work.filter((listItem) =&gt; 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 (&amp;&amp; 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?

And can you tell me how to output some message if no element is shown? For example, "Nothing found. Select other filters"

答案1

得分: 2

多个筛选条件时,需要将筛选函数定义如下:

const filteredWork = work.filter(w => {
   const catFilter = selectedCat ? w.category === selectedCat : true; // 如果未选择类别,则为true
   const yearFilter = selectedYear ? w.year === selectedYear : true; // 如果未选择年份,则为true
   return catFilter && yearFilter;
})

根据下面的注释,要么将selectedYear设为数字,要么在===的地方使用==

英文:

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

const filteredWork = work.filter(w =&gt; {
   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 &amp;&amp; yearFilter;
})

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

答案2

得分: 0

const work = [{
    "title": "WordPress Plugin for Yandex Recommender Widget",
    "image": "/images/works/yk.jpg",
    "year": 2022,
    "category": "WordPress",
    "link": "https://188.ru/",
    "description": "The client uses Yandex's recommendation widget on some websites, which allows displaying links to site articles along with Yandex ads. The problem is that the domestic search engine's system is not very smart and pulls not only articles but also a lot of unnecessary content into the widget. I wrote a micro-plugin that allows automatically adding a special tag to pages that should not be displayed in the widget, and also allows manually excluding certain articles from the widget."
  },
  {
    "title": "Website for the 'AkademPerevod' Translation Studio",
    "image": "/images/works/ap.jpg",
    "year": 2022,
    "category": "WordPress",
    "link": "https://academperevod.ru/",
    "description": "We updated the website without migrating from WordPress to other platforms. The project is based on Figma design and Elementor editor. It was a complex, lengthy, and meticulous task.",
    "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" />
英文:

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

const work = [{
&quot;title&quot;: &quot;Плагин WordPress для Рекомендательного виджета Яндекса&quot;,
&quot;image&quot;: &quot;/images/works/yk.jpg&quot;,
&quot;year&quot;: 2022,
&quot;category&quot;: &quot;WordPress&quot;,
&quot;link&quot;: &quot;https://188.ru/&quot;,
&quot;description&quot;: &quot;Заказчик использует на некоторых сайтах виджет рекомендаций от Яндекса, который позволяет показывать ссылки на статьи сайта вместе с рекламой Яндекса. Проблема в том, что система от отечественного поисковика не очень умная и тянет в виджет не только статьи, но и много чего не нужного. Я написал микроплагин, который дает возможность автоматически проставлять специальный тег на страницах, которые не нужно показывать в виджете, а также позволяет исключать некоторые статьи из виджета вручную&quot;
},
{
&quot;title&quot;: &quot;Сайт студии переводов &#171;АкадемПеревод&#187;&quot;,
&quot;image&quot;: &quot;/images/works/ap.jpg&quot;,
&quot;year&quot;: 2022,
&quot;category&quot;: &quot;WordPress&quot;,
&quot;link&quot;: &quot;https://academperevod.ru/&quot;,
&quot;description&quot;: &quot;Осовременивали сайт, не перезжая с WordPress на другие платформы. В основе проекта - дизайн в Фигме и редактор Elementor. Сложная, долгая и кропотливая работа&quot;,
&quot;scroll&quot;: true
}
];
const selected = {
cat: &quot;otherCat&quot;,
year: &quot;2021&quot;
};
document.getElementById(&quot;year&quot;).addEventListener(&quot;change&quot;, e =&gt; {
console.log(e.target.value);
selected.year = e.target.value;
printFiltered();
});
document.getElementById(&quot;cat&quot;).addEventListener(&quot;change&quot;, e =&gt; {
console.log(e.target.value);
selected.cat = e.target.value;
printFiltered();
});
function printFiltered() {
const filteredWork = work.filter(w =&gt; {
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 &amp;&amp; yearFilter;
})
console.log(filteredWork);
}

<!-- language: lang-html -->

&lt;select id=&quot;year&quot;&gt;
&lt;option value=&quot;2021&quot;&gt;2021&lt;/option&gt;
&lt;option value=&quot;2022&quot;&gt;2022&lt;/option&gt;
&lt;/select&gt;
&lt;select id=&quot;cat&quot;&gt;
&lt;option value=&quot;otherCat&quot;&gt;otherCat&lt;/option&gt;
&lt;option value=&quot;WordPress&quot;&gt;WordPress&lt;/option&gt;
&lt;/select&gt;
&lt;p id=&quot;result&quot; /&gt;

<!-- end snippet -->

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

huangapple
  • 本文由 发表于 2023年7月10日 14:24:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/76651127.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定