checkbox filtering in react - reactjs

I have such data:
const dataList = [
{
id: 1,
title: 'obj1',
published: true,
},
{
id: 2,
title: 'obj2',
published: true,
},
{
id: 3,
title: 'obj3',
published: false,
},
{
id: 4,
title: 'obj4',
published: true,
},
{
id: 5,
title: 'obj5',
published: false,
},
];
I also have two checkboxes with this structure:
enter image description here
filterList = [
{
id: 1,
title: 'published',
label: 'published',
checked: false,
},
{
id: 2,
title: 'unpublished',
label: 'unpublished',
checked: false,
},
],
how do I filter this kind of data using these checkboxes? I have implemented switching their state, but I don't understand how to filter the data
I'm trying to implement this in a function
const applyFilter = () => {
let updData = dataList;
const filterChecked = filterList.filter((item: any) => item.checked);
if (filterChecked.length) {
// how to dynamically substitute data from checkboxes?
updData = updData.filter((item) => item.published === //true//);
}
};

Here's an attempt at a minimal example that hopefully gives a clear overview of how it's possible to filter elements. You can use your state to control how the elements are filtered out of the list, and then render those that remain:
const App = () => {
const [showingBs, setShowingBs] = React.useState(true);
return (<div>
<input
type = "checkbox"
checked = {showingBs}
onChange = {
() => setShowingBs(!showingBs)
}
/>
{
['a', 'b', 'a', 'b', 'b', 'a', 'b']
.filter(x => showingBs || x !== 'b')
.map(x => <p>{x}</p>)
}
</div>)
}
ReactDOM.render( < App / > , document.getElementById("mount"))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="mount"></div>

Related

change the value of component with function

I am kinda new to reactjs I am using the react-dropdown library https://github.com/fraserxu/react-dropdown and I am trying to make a dropdown menu so my user can switch between 2 languages. However, I am not sure how to properly update the new value for language.
Here's my code:
const Navbar = () => {
const languages = [
{
code: 'fr',
name: 'Français',
country_code: 'fr',
key : 1
},
{
code: 'en',
name: 'English',
country_code: 'gb',
key: 2
},
]
const defaultLanguages = languages[0].name;
const changeLanguage = (e) => {
console.log(e)
}
return (
<div className={color ? 'header header-bg' : 'header'}>
<ul>
<li>
<DropDown options={languages} value={defaultLanguages} onChange={(e) => changeLanguage} />
</li>
</ul>
</div>
)
}
export default Navbar
as you can see I want to switch between french and english but I am not sure how to pass the value to the dropdown component.
You need to use the same attributes in your options (languages) passed to the Dropdown component. You can see the examples of both flag options and object options on the official repo:
//Options
//Flat Array options
const options = [
'one', 'two', 'three'
];
//Object Array options
const options = [
{ value: 'one', label: 'One' },
{ value: 'two', label: 'Two', className: 'myOptionClassName' },
{
type: 'group', name: 'group1', items: [
{ value: 'three', label: 'Three', className: 'myOptionClassName' },
{ value: 'four', label: 'Four' }
]
},
{
type: 'group', name: 'group2', items: [
{ value: 'five', label: 'Five' },
{ value: 'six', label: 'Six' }
]
}
];
Below code worked on my side:
import Dropdown from 'react-dropdown';
const Navbar = () => {
const languages = [
{
value: 'fr',
label: 'Français',
},
{
value: 'en',
label: 'English',
country_code: 'gb',
},
];
const defaultLanguages = languages[0].label;
const changeLanguage = (e) => {
console.log(e);
};
return (
<div className={'header'}>
<ul>
<li>
<Dropdown
options={languages}
value={defaultLanguages}
onChange={changeLanguage}
/>
</li>
</ul>
</div>
);
};
export default Navbar;
enter image description here
Create local state for tracking currently selected language. Also move out languages array outside of component. Here is the code:
const languages = [
{
code: 'fr',
name: 'Français',
country_code: 'fr',
key : 1
},
{
code: 'en',
name: 'English',
country_code: 'gb',
key: 2
},
]
const Navbar = () => {
const [selectedLanguage, setSelectedLanguage] = useState(languages[0].name);
const changeLanguage = (option) => {
setSelectedLanguage(option.name)
}
return (
<div className={color ? 'header header-bg' : 'header'}>
<ul>
<li>
<DropDown options={languages} value={selectedLanguage} onChange={changeLanguage} />
</li>
</ul>
</div>
)
}
export default Navbar

How to show length of filtered items using react redux. Im getting data using list. Using list how can i get the length of filtered items length

This is shop page.jsx file here i want to show the list of filtered items at the top of the page. Here im using data list for getting all the details. Here i want to show length of filtered products at showing 9 0f 9 products.
import React, { useEffect, useState } from 'react';
import EmptyView from '../components/common/EmptyView';
import FilterPanel from '../components/Home/FilterPanel';
import List from './Home/List';
// import SearchBar from '../../components/Home/SearchBar';
import { dataList } from '../constants';
// import './styles.css';
import '../App.css';
import ButtonAppBar from "./Header";
const Shop = () => {
// const [selectedCategory, setSelectedCategory] = useState(null);
// const [selectedRating, setSelectedRating] = useState(null);
const [selectedPrice, setSelectedPrice] = useState([0, 150]);
const [cuisines, setCuisines] = useState([
{ id: 1, checked: false, label: 'Furniture' },
{ id: 2, checked: false, label: 'Decoration' },
{ id: 3, checked: false, label: 'Bedding' },
{ id: 4, checked: false, label: 'Lighting' },
{ id: 5, checked: false, label: 'Bath&Shower' },
{ id: 6, checked: false, label: 'Curtains' },
{ id: 7, checked: false, label: 'Toys' },
]);
const [brand, setBrand] = useState([
{ id: 1, checked: false, label: 'Poliform' },
{ id: 2, checked: false, label: 'Rochie Bobois' },
{ id: 3, checked: false, label: 'Edra' },
{ id: 4, checked: false, label: 'Kartell' },
]);
const [availability, setAvailability] = useState([
{ id: 1, checked: false, label: 'Onstock' },
{ id: 2, checked: false, label: 'Outofstock' },
]);
const [list, setList] = useState(dataList);
const [resultsFound, setResultsFound] = useState(true);
// const [searchInput, setSearchInput] = useState('');
// const handleSelectCategory = (event, value) =>
// !value ? null : setSelectedCategory(value);
// const handleSelectRating = (event, value) =>
// !value ? null : setSelectedRating(value);
const handleChangeChecked = (id) => {
const cusinesStateList = cuisines;
const changeCheckedCuisines = cusinesStateList.map((item) =>
item.id === id ? { ...item, checked: !item.checked } : item
);
setCuisines(changeCheckedCuisines);
};
const handleChangeCheckeds = (id) => {
const brandStateList = brand;
const changeCheckedsBrand = brandStateList.map((item) =>
item.id === id ? { ...item, checked: !item.checked } : item
);
setBrand(changeCheckedsBrand);
};
const handleChangeCheckedss = (id) => {
const availabilityStateList = availability;
const changeCheckedssAvailability = availabilityStateList.map((item) =>
item.id === id ? { ...item, checked: !item.checked } : item
);
setAvailability(changeCheckedssAvailability);
};
const handleChangePrice = (event, value) => {
setSelectedPrice(value);
};
const applyFilters = () => {
let updatedList = dataList;
// // Rating Filter
// if (selectedRating) {
// updatedList = updatedList.filter(
// (item) => parseInt(item.rating) === parseInt(selectedRating)
// );
// }
// // Category Filter
// if (selectedCategory) {
// updatedList = updatedList.filter(
// (item) => item.category === selectedCategory
// );
// }
// Cuisine Filter
const cuisinesChecked = cuisines
.filter((item) => item.checked)
.map((item) => item.label.toLowerCase());
if (cuisinesChecked.length) {
updatedList = updatedList.filter((item) =>
cuisinesChecked.includes(item.cuisine)
);
}
// brand filter
const brandChecked = brand
.filter((item) => item.checked)
.map((item) => item.label.toLowerCase());
if (brandChecked.length) {
updatedList = updatedList.filter((item) =>
brandChecked.includes(item.brand)
);
}
// availabilty filter
const availabilityChecked = availability
.filter((item) => item.checked)
.map((item) => item.label.toLowerCase());
if (availabilityChecked.length) {
updatedList = updatedList.filter((item) =>
availabilityChecked.includes(item.availability)
);
}
// // Search Filter
// if (searchInput) {
// updatedList = updatedList.filter(
// (item) =>
// item.title.toLowerCase().search(searchInput.toLowerCase().trim()) !==
// -1
// );
// }
// // Price Filter
const minPrice = selectedPrice[0];
const maxPrice = selectedPrice[1];
updatedList = updatedList.filter(
(item) => item.price >= minPrice && item.price <= maxPrice
);
setList(updatedList);
!updatedList.length ? setResultsFound(false) : setResultsFound(true);
};
useEffect(() => {
applyFilters();
}, [cuisines, brand, availability, selectedPrice]);
return (
<div>
<ButtonAppBar />
<div className='home'>
{/* Search Bar */}
{/* <SearchBar
value={searchInput}
changeInput={(e) => setSearchInput(e.target.value)}
/> */}
<br /><br /><br /> <div className='home_panelList-wrap'>
{/* Filter Panel */}
<div className='home_panel-wrap'>
<FilterPanel
// selectedCategory={selectedCategory}
// selectCategory={handleSelectCategory}
// selectedRating={selectedRating}
selectedPrice={selectedPrice}
// selectRating={handleSelectRating}
cuisines={cuisines}
changeChecked={handleChangeChecked}
brand={brand}
changeCheckeds={handleChangeCheckeds}
availability={availability}
changeCheckedss={handleChangeCheckedss}
changePrice={handleChangePrice}
/>
</div>
{/* List & Empty View */}
<div className='home_list-wrap'>
<h6>Showing
<span style={{ color: "#bd744c" }}><b>{dataList.length}</b></span> of
<span style={{ color: "#bd744c" }}><b>9</b></span>
Products</h6>
{resultsFound ? <List list={list} /> : <EmptyView />}
</div>
</div>
</div>
</div>
);
};
export default Shop;
This is constant.js file from here we are getting all our details in shop.jsx file.
export const dataList = [
{
id: 1,
title: 'AwesomeLamp',
cuisine: 'lighting',
price: 40,
image: '/images/AwesomeLamp.png',
brand: 'poliform',
availability: 'onstock',
name: 'AwesomeLamp',
tagName: 'AwesomeLamp'
},
{
id: 2,
title: 'CozySofa',
cuisine: 'furniture',
price: 150,
image: '/images/CozySofa.png',
brand: 'edra',
availability: 'outofstock',
name: 'CozySofa',
tagName: 'CozySofa'
},
{
id: 3,
title: 'AwesomeCandle',
cuisine: 'lighting',
price: 15,
image: '/images/AwesomeCandle.png',
brand: 'kartell',
availability: 'onstock',
name: 'AwesomeCandle',
tagName: 'AwesomeCandle',
},
{
id: 4,
title: 'FancyChair',
cuisine: 'furniture',
price: 70,
image: '/images/FancyChair.png',
brand: 'poliform',
availability: 'outofstock',
name: 'FancyChair',
tagName: 'FancyChair'
},
{
id: 5,
title: 'ChineseTeapot',
cuisine: 'decoration',
price: 50,
image: '/images/ChineseTeapot.png',
brand: 'rochie bobois',
availability: 'onstock',
name: 'ChineseTeapot',
tagName: 'ChineseTeapot'
},
{
id: 6,
title: 'SoftPillow',
cuisine: 'bedding',
price: 30,
image: '/images/SoftPillow.png',
brand: 'edra',
availability: 'onstock',
name: 'SoftPillow',
tagName: 'SoftPillow'
},
{
id: 7,
title: 'WoodenCasket',
cuisine: 'decoration',
price: 20,
image: '/images/WoodenCasket.png',
brand: 'kartell',
availability: 'onstock',
name: 'WoodenCasket',
tagName: 'WoodenCasket'
},
{
id: 8,
title: 'AwesomeArmChair',
cuisine: 'furniture',
price: 90,
image: '/images/AwesomeArmChair.png',
brand: 'poliform',
availability: 'onstock',
name: 'AwesomeArmchair',
tagName: 'AwesomeArmchair'
},
{
id: 9,
title: 'CoolFlower',
cuisine: 'decoration',
price: 20,
image: '/images/CoolFlower.png',
brand: 'none',
availability: 'onstock',
name: 'CoolFlower',
tagName: 'CoolFlower'
},
];

TypeError: arrayObject.sort is not a function in react jest enzyme

I am trying to write assertion for a menu list which render after full fill the expression condition and sorted such as:
{packageFamilyId &&
packageMap[packageFamilyId] &&
packageMap[packageFamilyId].sort(Constants.sortAlphabeticallyAscending)
.map((p) => (
<MenuItem value={p.id} key={p.id} data-test="package-menu">{p.name}</MenuItem>
}
I am passing props as:
const props = {
packageFamilyId: 1,
packageMap: [
{
packageFamilyId: [],
},
{
packageFamilyId: [
{
active: true,
code: "0",
id: 121,
is_price_applicable: false,
name: "ctest_name",
typeId: 2,
},
{
active: true,
code: "0",
id: 121,
is_price_applicable: false,
name: "btest_name",
typeId: 2,
},
{
active: true,
code: "0",
id: 121,
is_price_applicable: false,
name: "atest_name",
typeId: 2,
}
],
},
],
};
import React from "react";
import { shallow } from "enzyme";
import { componentName } from "./componentName ";
import componentNameMock from "../../../test/mockData/componentName";
describe("componentNameComponent", () => {
const wrapper = shallow(<component {...props} />);
const menuList = wrapper.find("[data-test='package-menu']");
expect(menuList .length()).toEqual(1);
});
But it is giving me Type Error:
TypeError: packageMap[packageFamilyId].sort is not a function
packageMap[packageFamilyId] &&
packageMap[packageFamilyId]
.sort(Constants.sortAlphabeticallyAscending)
............................................................................
where Constants.sortAlphabeticallyAscending is sorting function
sortAlphabeticallyAscending: (a, b) => {
if (a !== undefined && b !== undefined) {
if (a.name?.toLowerCase() < b.name?.toLowerCase()) return -1;
else if (a.name?.toLowerCase() > b.name?.toLowerCase()) return 1;
else return 0;
}
}
Issue
packageMap[packageFamilyId] is an object:
{
packageFamilyId: [
{
active: true,
code: "0",
id: 121,
is_price_applicable: false,
name: "ctest_name",
typeId: 2,
},
{
active: true,
code: "0",
id: 121,
is_price_applicable: false,
name: "btest_name",
typeId: 2,
},
{
active: true,
code: "0",
id: 121,
is_price_applicable: false,
name: "atest_name",
typeId: 2,
}
],
}
This is not an array nor is there a sort property that is a function that can be called. In otherwords, packageMap[packageFamilyId].sort is undefined and not callable.
Solution
Access the property that is an array and sort this.
{packageMap[packageFamilyId]?.packageFamilyId?.sort(
Constants.sortAlphabeticallyAscending
).map((p) => (
<MenuItem value={p.id} key={p.id} data-test="package-menu">
{p.name}
</MenuItem>
)
)}
Since there are actually 3 elements in the specified array the test should be updated to assert against the correct length. length is also a property, not a function to call.
describe("componentNameComponent", () => {
const wrapper = shallow(<component {...props} />);
const menuList = wrapper.find("[data-test='package-menu']");
expect(menuList.length).toEqual(3);
});
it worked with mockup setting , instead of familyPackageId string i gave value 1(index value).
it("expects to render package-menu ", () => {
const wrapper = shallow(<componentNameComponent{...props} />);
const menuList = wrapper.find("[data-test='package-menu']");
expect(menuList .length).toEqual(props.packageMap["1"].length);
});
packageMap: {
1: [
{
id: 4,
isPriceApplicable: true,
is_price_applicable: true,
name: "ctest_name",
packageAgentType: "FoS",
typeId: 1,
},
{
id: 3,
isPriceApplicable: true,
is_price_applicable: true,
name: "btest_name",
packageAgentType: "FoS",
typeId: 1,
},
{
id: 4,
isPriceApplicable: true,
is_price_applicable: true,
name: "atest_name",
packageAgentType: "FoS",
typeId: 1,
},
],
},

How to use spread operator to update array inside an object?

What the fetch returns is a list of items. I want to add those into state.
const [state, setState] = useState({
list: {
items: [],
}
});
fetch('http://example.com/list/')
// GET response: [{ name: 'foo' }, { name: 'bar' }, { name: 'baz' }]
.then((resList) => resList.json())
.then((list) => {
list.forEach(({ name }) => {
const itemUrl = `https://example.com/list/${name}`;
fetch(itemUrl)
// GET responses:
// { name: 'foo', desc: '123' }
// { name: 'bar', desc: '456' }
// { name: 'baz', desc: '789' }
.then((itemRes) => itemRes.json())
.then((item) => {
setState((prevState) => ({
...prevState,
list: {
items: [...state.list.items, item]
},
});
})
})
}
})
console.log(state);
// result: [{ name: 'baz', desc: '789' }]
// but wanted: [{ name: 'foo', desc: '123' }, { name: 'bar', desc: '456' }, { name: 'baz', desc: '789' }]
In your case no need to use prevState in setState.
I prepared an example for you. Just be careful at using hooks.
https://codesandbox.io/s/recursing-wood-4npu1?file=/src/App.js:0-567
import React, { useState } from "react"
import "./styles.css"
export default function App() {
const [state, setState] = useState({
list: {
items: [
{ name: "foo", desc: "123" },
{ name: "bar", desc: "456" },
],
},
})
const handleClick = () => {
setState(() => ({
list: {
items: [...state.list.items, { name: "baz", desc: "789" }],
},
}))
}
return (
<div className="App">
<button onClick={handleClick}>Click Me </button>
<hr />
{JSON.stringify(state)}
</div>
)
}
You can't directly access the callback for useState hooks. This is how you can update state after fetching the data:
setState({
...state,
list: {
items:[...state.list.items, item]
},
});

react-absolute-grid, displayObject issue

I am trying to use this component: https://github.com/jrowny/react-absolute-grid.
The documentation says I should pass a displayObject which renders items.
So I created a displayObject, like the one in the docs which has this render method:
render: function() {
// Supposing your item shape is something like {name: 'foo'}
const { item, index, itemsLength } = this.props;
return <div>Item {index} of {itemsLength}: {item.name}</div>;
}
I passed it to the component like this:
<AbsoluteGrid
items={SampleData.screens}
displayObject={<DisplayObject/>}
onMove={onMoveDebounced}
dragEnabled={true}
responsive={true}
verticalMargin={42}
itemWidth={250}
itemHeight={250}
filteredProp={'name'}
/>
Where SampleData.screens is:
module.exports = {
screens: [
{'url': 'http://invisionapp.com/subsystems/do_ui_kit/assets/img/screens/original-1x/screen-1-1-login.jpg', 'name': 'login', 'sort': 1, 'key': 1},
{'url': 'http://invisionapp.com/subsystems/do_ui_kit/assets/img/screens/original-1x/screen-1-2-sign-up.jpg', 'name': 'signup', 'sort': 2, 'key': 2},
{'url': 'http://invisionapp.com/subsystems/do_ui_kit/assets/img/screens/original-1x/screen-1-3-walkthrough.jpg', 'name': 'walkthrough', 'sort': 3, 'key': 3}
]
};
When I open the page in the browser, I don't see the text from the displayObject.
How can I use the displayObject?
DisplayObject works good when is a function that return the render html, I try creating a different React.Component for it but got some issues
const items = [
{ key: "0", sort: 0, name: 'Test 1', filtered: false },
{ key: "1", sort: 1 ,name: 'Test 2', filtered: false },
{ key: "2",sort: 2, name: 'Test 3', filtered: false},
{ key: "3", sort: 3,name: 'Test 4', filtered: false }
]
function GridItem(props) {
const { item, index, itemsLength } = props;
return <div >
<span>{item.name}</span>
</div>;
}
const AbsoluteGrid = createAbsoluteGrid(GridItem);

Resources