본문 바로가기
Projects/NodeBoard

글 검색 기능과 페이징 개선

by DawIT 2021. 3. 2.
320x100

원하는 글을 제목, 글쓴이, 내용으로 검색할 수 있도록 검색기능을 추가하였다.

 

            <div id="wrap-upper">
                <% if(values.isSearch === false) { %>
                    <button type="button" class="btn btn-secondary" id="post-button" onclick="writePost()">글쓰기</button>
                <% } %>
                <form action="/search" accept-charset="utf-8" method="get">
                    <input type="hidden" name="type" value="<%=values.type%>">
                    <button type="submit" class="btn btn-primary" id="search-button">검색</button>
                    <input type="text" id="search-keyword" name="keyword" required minlength="2" maxlength="10">
                    <select class="form-control" id="search-mode" name="mode">
                        <option>제목</option>
                        <option>작성자</option>
                        <option>내용</option>
                    </select>
                </form>
            </div>

 

일단 list.ejs의 wrap-upper 부분에 검색을 위한 form을 추가하였다. 이 form은 get방식으로 전달되며, 어떤 종류(제목,작성자,내용)의 검색인지, 키워드는 무엇인지, 그리고 해당 페이지가 어떤 게시판을 보여주고 있었는지를 전달한다.

 

검색 바

 

 

var express = require('express');
var router = express.Router();
var db = require('../db-query');

router.get('/',function(req,res,next){
    let {type,mode,keyword,page} = req.query;
    if (page===undefined)
        page = 1;

    var data = {};
    data.type = type;
    data.mode = mode;
    data.keyword = keyword;
    data.page = page;
    data.isSearch = true;

    db.searchPost(data,20,(response,maxPage)=>{
        if (response===false)
            res.render('error');
        else
            res.render('list',{postData: response,values: data,maxPage: maxPage});
    });
});

module.exports = router;

 

그리고 검색 get을 맡은 search.js이다. 페이지가 넘어오지 않았다면 1로 설정해준다. 넘어온 파라미터들을 data객체에 담아서 db-query.js에 있는 searchPost함수에 넘겨준다. 20은 결과의 한 페이지당 표시할 게시글 수이다.

 

var searchPost = function(data,amount,callback){
    // DB 칼럼명에 맞게 변경
    if (data.mode=='제목')
        data.mode='TITLE';
    else if (data.mode=='작성자')
        data.mode='AUTHOR';
    else if (data.authormode=='내용')
        data.mode='CONTENT';


    if(data.type=='all'){
        db.query('SELECT COUNT(*) AS COUNT FROM POST WHERE ?? LIKE ?',[data.mode,"%"+data.keyword+"%"],(err,count)=>{
            if (err)
                callback(false);
            else{
                count = count[0].COUNT;
                var maxPage = Math.ceil(count / amount);

                db.query('SELECT * FROM POST WHERE ?? LIKE ? ORDER BY ID DESC LIMIT ?, ?',[data.mode,"%"+data.keyword+"%",(data.page-1)*amount,amount],(err,result)=>{
                    if(err)
                        callback(false);
                    else
                        callback(result,maxPage);
                });
            }
        });
    } else{
        db.query('SELECT COUNT(*) AS COUNT FROM POST WHERE TYPE=? AND ?? LIKE ?',[data.type,data.mode,"%"+data.keyword+"%"],(err,count)=>{
            if (err)
                callback(false);
            else{
                count = count[0].COUNT;
                var maxPage = Math.ceil(count / amount);

                db.query('SELECT * FROM POST WHERE TYPE=? AND ?? LIKE ? ORDER BY ID DESC LIMIT ?, ?',[data.type,data.mode,"%"+data.keyword+"%",(data.page-1)*amount,amount],(err,result)=>{
                    if(err)
                        callback(false);
                    else
                        callback(result,maxPage);
                });
            }
        });
    }
}

 

db-query.js 에서는 DB에 접근하여 값을 가져온다. 일단 data.mode에는 한글로 된 값이 들어 있으므로 query문에서 사용할 수 있도록 column명으로 바꿔준다. 검색은 SELECT문과 %LIKE%문을 사용하면 된다. 그리고 list.js와 비슷하게 해당 검색 결과의 개수를 받아와서 최대 페이지를 결과로 넘겨줄 것이다.

 

또한 type변수가 all(전체글 보기)이라면 모든 칼럼에서 값을 가져오고, all이 아닌 다른 값(자유게시판 or 유머게시판)이라면 해당 게시판의 글만 가져온다.

 

 

이제 '전체글 보기' 상태에서 '테스트'를 검색하면,

 

검색 결과

 

이렇게 검색 결과로 모든 게시판에서 '테스트'를 제목에 포함한 글을 불러온다. 만약 유머 게시판을 보고있던 상태로 이를 검색한다면,

 

 

이렇게 검색 결과가 없다는 문구를 띄운다.

 

그리고 페이징 기능을 조금 개선했다. list.ejs가 단순 글 리스트 보기의 역할 뿐만 아니라 검색 결과도 띄워야 하는 템플릿이 되었기 때문에 이번에 확실하게 페이징을 만들어 놓았다.

 

<div id="pages">
	<hr>
	<% if(values.page>1) { %>
		<a class="btn btn-default" role="button" onclick="movePage('<%=Number(values.page)-1%>',<%=values.isSearch%>,'<%=values.type%>','<%=values.mode%>','<%=values.keyword%>',<%=maxPage%>)">이전</a>
	<% } %>
	<%=values.page%> of <%=maxPage%>
	<% if(values.page < maxPage) { %>
		<a class="btn btn-default" role="button" onclick="movePage('<%=Number(values.page)+1%>',<%=values.isSearch%>,'<%=values.type%>','<%=values.mode%>','<%=values.keyword%>',<%=maxPage%>)">다음</a>
	<% } %>
	<input type="text" placeholder="<%=values.page%>" id="target-page">
	<button class="btn btn-default" onclick="movePage($('#target-page').val(),<%=values.isSearch%>,'<%=values.type%>','<%=values.mode%>','<%=values.keyword%>',<%=maxPage%>)" role="button">이동</a>
</div>

 

이전 혹은 다음 버튼을 클릭하거나 직접 페이지를 입력해서 이동할 때 사용할 함수 movePage를 정의했다. 이 함수는(목표 페이지, 해당 페이지가 검색 결과인지의 여부, 게시판 종류, 검색 종류, 검색 키워드, 최대 페이지) 를 인자로 받는다.

 

function movePage(target,isSearch,type,mode,keyword,maxPage){
    console.log(typeof maxPage);
    if (target < 1 || target > maxPage){
        alert('페이지 범위를 벗어났습니다!');
        $('#target-page').val('');
        return;
    }

    var url = '';

    if (isSearch)
        url = '/search?mode='+mode+'&keyword='+keyword+'&';
    else
        url = '/list?';
    
    url += 'type='+type+'&page='+target;

    location.href = url;
}

 

functions.js에 정의되어있는 movePage함수에서는 만약 페이지 직접입력에서 범위를 벗어나는 페이지를 입력했을 경우 이를 알리고, 그렇지 않을 경우 url을 만들어서 이동한다.

 

이제..

 

  • 같은 글은 ip당 한 번만 추천할 수 있도록 설정
  • AJAX를 이용한 비동기 방식의 댓글
  • 소셜 로그인 기능으로 로그인 상태에서도 글,댓글 쓸 수 있도록 변경
  • socket.io를 이용한 실시간 유저 채팅

 

을 구현하면 된다.

'Projects > NodeBoard' 카테고리의 다른 글

AJAX로 댓글달기 기능 구현  (5) 2021.03.06
추천하기 기능 구현  (0) 2021.03.03
글 수정 기능과 글 리스트 페이징  (0) 2021.02.27
글 삭제 기능 제작  (0) 2021.02.26
글 작성 기능 제작  (0) 2021.02.25

댓글