ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • OnlineShop 만들기 - 6) Landing Page 만들기 3(check 필터링, price 필터링 만들기)
    NODE.JS 2021. 5. 15. 22:03

    순서

    체크한 나라에 관한 (continents) 자료들만 로드되도록 한다.

     

    checkbox에 관한 내용들은 sections폴더안에 따로 생성한다. 

    src>components>views>LandingPage>Sections>CheckBox.js파일을 생성한다.

    import React from 'react'
    import { Checkbox, Collapse } from 'antd';
    
    
    const continents = [
        {
            "_id": 1,
            "name": "Africa"
        },
        {
            "_id": 2,
            "name": "Europe"
        },
        {
            "_id": 3,
            "name": "Asia"
        },
        {
            "_id": 4,
            "name": "North America"
        },
        {
            "_id": 5,
            "name": "South America"
        },
        {
            "_id": 6,
            "name": "Australia"
        },
        {
            "_id": 7,
            "name": "Antarctica"
        }
    ]
    
    function CheckBox() {
        return (
            <div>
                <Collapse defaultActiveKey={['0']} >
                    <Panel header key="1">
                    <React.Fragment key={index}>
                    <Checkbox
                        onChange
                        type
                        checked
                    />
                    <span>{value.name}</span>
                    </React.Fragment>
                    ))                
                    </Panel>
                </Collapse>
            </div>
        )
    }

     

     

    랜딩페이지안에도 넣어준다.

    import CheckBox from './Sections/CheckBox';
    
    			{/* Filter  */}
    
                <CheckBox />

    현재상태

     

     

    onChange Function을 만들어보자.

    import React ,{useState} from 'react'
    import { Checkbox, Collapse } from 'antd';
    
    
    
    function CheckBox(props) {
        const [Checked, setChecked] = useState([])//어떤걸 체크했는지 배열에 넣어서 알려준다.
    
    
        const handleToggle = (value) => {//어떤 체크박스를 넣어줄건지 value를 준다.
    
            const currentIndex = Checked.indexOf(value);//체크된 것의 인덱스를 가져온다.
            const newChecked = [...Checked]; //체크된것들
    
            if (currentIndex === -1) {//체크가 안되어 있었으면
                newChecked.push(value)//가져올 checked에 값을 추가한다.
            } else {//이미 체크가 되어있으면
                newChecked.splice(currentIndex, 1)//체크에서 제외해준다.
            }
    
            setChecked(newChecked)//새로 체크 변화된 것 다시 한번 세팅
            props.handleFilters(newChecked)//변화된것 부모에게 전달해준다. 
            //update this checked information into Parent Component 
    
        }
    
        const renderCheckboxLists = () => props.list && props.list.map((value, index) => (
            <React.Fragment key={index}>
                <Checkbox
                    onChange={() => handleToggle(value._id)}//체크 표시 
                    type="checkbox"
                    checked={Checked.indexOf(value._id) === -1 ? false : true}//체크 여부(되지않으면 -1, 되어있으면 !=-1)에 따라서 checked 가 true, false
                />&nbsp;&nbsp;
                <span>{value.name}</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
            </React.Fragment>
        ))
        
        
        return (
            <div>
                <Collapse defaultActiveKey={['0']} >
                    <Panel header="Continents" key="1">
                        {renderCheckboxLists()}
                    </Panel>
                </Collapse>
            </div>
        )
    }

    여기서 부모에게 전달해줄 handletoggle함수는 부모가 가지고 있어야 하므로 

    랜딩페이지에 구현해준다.

    순서

     

    	 const [Filters, setFilters] = useState({//두가지의 필터를 가지고 있다. 
            continents: [],
            price: []
        })
        
        
        
            const showFilteredResults = (filters) => {//필터링한 결과를 가지고 온다.
    
            const variables = {
                skip: 0,//체크박스를 새로 설정하면 처음부터 다시 보여줘야 한다.
                limit: Limit,
                filters: filters
    
            }
            getProducts(variables)//결과를 가져오기 위해서 getProducts사용한다.
            setSkip(0)
    
        }
    
    
    
        const handleFilters = (filters, category) => {//체크된것들에 변화가 있으면 새로 받아오는 것(자식으로 부터 변화 받아오는 함수 )
            //체크가 된다면 배열 안에 체크된 인덱스 번호가 추가될 것이다. 
            const newFilters = { ...Filters }//새로운 필터만들고
    
            newFilters[category] = filters//해당카테고리의 필터는 입력된 filters가 될 것이다. 
    
            if (category === "price") {
    
            }
    
            console.log(newFilters)
    
            //필터링한 결과를 세팅해준다.
            showFilteredResults(newFilters)
            //필터의 상태를 새로운 필터로 바꿔준다.
            setFilters(newFilters)
        }
    
        
        
        
                    {/* Filter  */}    
       					 <CheckBox
                            handleFilters={filters => handleFilters(filters, "continents")}
                        />

    getproducts 라우터에서 필터링에 따라서 가져오는 종류가 달라질 수 있도록 수정해준다.

     

    router.post("/getProducts", (req, res) => {
    
        //variables가 있을때와 없을 때를 나눈다.
        let order = req.body.order ? req.body.order : "desc";
        let sortBy = req.body.sortBy ? req.body.sortBy : "_id";
        let limit = req.body.limit ? parseInt(req.body.limit) : 100;
        let skip = parseInt(req.body.skip);
    
        let findArgs = {};
    
        for (let key in req.body.filters) { //필터에 따라서 
    
            if (req.body.filters[key].length > 0) {
                if (key === "price") {
     
                    }
                } else {//키가 price가 아니라면
                    findArgs[key] = req.body.filters[key];//findArgs[continents] = [인덱스 배열]의 형태
                }
            }
        }
    
    
            Product.find(findArgs)
                .populate("writer")
                .sort([[sortBy, order]])
                .skip(skip)
                .limit(limit)
                .exec((err, products) => {
                    if (err) return res.status(400).json({ success: false, err })
                    res.status(200).json({ success: true, products, postSize: products.length })
                })
        
    
    });

     

     

    이제 가격에 의한 필터링을 만들어보자.

    순서

    체크박스 component처럼 라디오 박스 component를 만들어준다.

    src>component>views>Sections>RadioBox.js파일

    import React from 'react'
    import { Collapse, Radio } from 'antd';
    const { Panel } = Collapse;
    
    const price = [
        {
            "_id": 0,
            "name": "Any",
            "array": []
        },
        {
            "_id": 1,
            "name": "$0 to $199",
            "array": [0, 199]
        },
        {
            "_id": 2,
            "name": "$200 to $249",
            "array": [200, 249]
        },
        {
            "_id": 3,
            "name": "$250 to $279",
            "array": [250, 279]
        },
        {
            "_id": 4,
            "name": "$280 to $299",
            "array": [280, 299]
        },
        {
            "_id": 5,
            "name": "More than $300",
            "array": [300, 1500000]
        }
    ]
    
    function RadioBox() {
        const [Value, setValue] = useState('0')
    
        const renderRadioBox = () => (
            props.list &&  props.list.map((value) => (
                <Radio key={value._id} value={`${value._id}`}>{value.name}</Radio>
            ))
        )
    
    
    
        return (
            <div>
                <Collapse defaultActiveKey={['0']}>
                    <Panel header="price" key="1">
                        <Radio.Group onChange value>
    
                            {renderRadioBox()}
    
                        </Radio.Group>
                    </Panel>
                </Collapse>
            </div>
        )
    }
    
    export default RadioBox

     

    랜딩페이지에도 추가해준다.

    import RadioBox from './Sections/RadioBox';
    
                {/* Filter  */}
    			<RadioBox
                        handleFilters={filters => handleFilters(filters, "price")}
                
                />

    antd를 이용해서 col, row디자인을 준다.

     

     		 {/* Filter  */}
    
                
                <Row gutter={[16, 16]}>
                    <Col lg={12} xs={24} >
                        <CheckBox
                            list={continents}
                            handleFilters={filters => handleFilters(filters, "continents")}
                        />
                    </Col>
                    <Col lg={12} xs={24}>
                        <RadioBox
                            list={price}
                            handleFilters={filters => handleFilters(filters, "price")}
                        />
                    </Col>
                </Row>
    

     

    RadioBox 에 onChange Function을 만들어준다.

        const [Value, setValue] = useState('0')//id가 0부터 시작하니까
        const handleChange = (event) => {
            setValue(event.target.value)
            props.handleFilters(event.target.value)//부모컴포넌트로 보내준다.
        }
        return (
            <div>
                <Collapse defaultActiveKey={['0']}>
                    <Panel header="price" key="1">
                        <Radio.Group onChange={handleChange} value={Value}>
    
                            {renderRadioBox()}
    
                        </Radio.Group>
                    </Panel>
                </Collapse>
            </div>
        )
    }

     

     

    handleFilter Function을 만들어보자.

    순서

     

    먼저 가격정보랑 continents 정보를 담았던 CheckBox, RadioBox에서 정보들만 따로 모으자.

    Sections>Datas.js파일을 만든다.

    const price = [
        {
            "_id": 0,
            "name": "Any",
            "array": []
        },
        {
            "_id": 1,
            "name": "$0 to $199",
            "array": [0, 199]
        },
        {
            "_id": 2,
            "name": "$200 to $249",
            "array": [200, 249]
        },
        {
            "_id": 3,
            "name": "$250 to $279",
            "array": [250, 279]
        },
        {
            "_id": 4,
            "name": "$280 to $299",
            "array": [280, 299]
        },
        {
            "_id": 5,
            "name": "More than $300",
            "array": [300, 1500000]
        }
    ]
    
    
    
    
    const continents = [
        {
            "_id": 1,
            "name": "Africa"
        },
        {
            "_id": 2,
            "name": "Europe"
        },
        {
            "_id": 3,
            "name": "Asia"
        },
        {
            "_id": 4,
            "name": "North America"
        },
        {
            "_id": 5,
            "name": "South America"
        },
        {
            "_id": 6,
            "name": "Australia"
        },
        {
            "_id": 7,
            "name": "Antarctica"
        }
    ]
    
    
    export {
        price, 
        continents
    }

    랜딩페이지에 둘다 임포트 해준다.

     

    import { continents, price } from './Sections/Datas';
    

     

    각각 CheckBox, RadioBox에는 props로 보내주자.

     

                {/* Filter  */}
    
                <Row gutter={[16, 16]}>
                    <Col lg={12} xs={24} >
                        <CheckBox
                            list={continents}//filter보내준다.
                            handleFilters={filters => handleFilters(filters, "continents")}
                        />
                    </Col>
                    <Col lg={12} xs={24}>
                        <RadioBox
                            list={price}//filter보내준다.
                            handleFilters={filters => handleFilters(filters, "price")}
                        />
                    </Col>
                </Row>
    
    //각각 radiobox, checkbox도 props.list로 변경해준다.
    
    	const renderRadioBox = () => (
            props.list &&  props.list.map((value) => (
                <Radio key={value._id} value={`${value._id}`}>{value.name}</Radio>
            ))
        )
        
        
        
        
        const renderCheckboxLists = () => props.list && props.list.map((value, index) => (

     

    랜딩페이지에서 handleFilters함수에 다음 내용을 추가한다.

     

        const handlePrice = (value) => {//가격 조정함수
            const data = price;
            let array = [];
    
            for (let key in data) {//데이터 안의 키들
    
                if (data[key]._id === parseInt(value, 10)) {// key는 가격이 아니라 인덱스, value는 string으로 되어있는데 이를 int로 바꿔준다.
                    array = data[key].array;
                }
            }
            console.log('array', array)
            return array //가격[300, 1500]의 형태
        }
    
        const handleFilters = (filters, category) => {//체크된것들에 변화가 있으면 새로 받아오는 것(자식으로 부터 변화 받아오는 함수 )
            //체크가 된다면 배열 안에 체크된 인덱스 번호가 추가될 것이다. 
            const newFilters = { ...Filters }//새로운 필터만들고
    
            newFilters[category] = filters//해당카테고리의 필터는 입력된 filters가 될 것이다. 
    
            if (category === "price") {//필터카테고리가 가격이라면
                let priceValues = handlePrice(filters)
                newFilters[category] = priceValues//가격범위 지정
    
            }
    
            console.log(newFilters)
    
            //필터링한 결과를 세팅해준다.
            showFilteredResults(newFilters)
            //필터의 상태를 새로운 필터로 바꿔준다.
            setFilters(newFilters)
        }

     

    가격조정이라면 route가 다르게 행동하도록 다음과 같이 수정해준다.

        for (let key in req.body.filters) { //필터에 따라서 
    
            if (req.body.filters[key].length > 0) {
                if (key === "price") {
                    findArgs[key] = {
                        $gte: req.body.filters[key][0],//greater than equal
                        $lte: req.body.filters[key][1]//lower than equal
                    }
                } else {//키가 price가 아니라면
                    findArgs[key] = req.body.filters[key];//findArgs[continents] = [인덱스 배열]의 형태
                }
            }
        }

     

     

     

    완성된 화면

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

Designed by Tistory.