앞선 다음 글에서, Firebase의 DB 데이터를 특정 필드를 기준으로 오름차순 또는 내림차순으로 정렬하여 불러오는 방법을 소개했었다.
그런데 이렇게 하면, 한 가지 아쉬운 점이 있다. DB의 데이터를 보여주는 순서가 반드시 특정 필드를 기준으로 하게 된다는 점이다. 때로는 등록순서가 아니라, 이름 순서대로 정렬해서 데이터를 살펴본다든가, 또는 가격을 기준으로 정렬해서 데이터를 보고 싶을 때가 많기 때문이다.
본 글에서는 이런 점을 개선하고자, 다음과 같이 화면 상단에 버튼을 추가하고, 이들을 눌러서 정렬의 기준이 되는 순서를 바꿔보기로 했다.
이러한 버튼은 다음과 같은 방식으로 생성하였고, 각각의 버튼마다 부트스트랩을 이용하여 다른 색상을 지정했다.
그리고, 다음과 같은 각각의 버튼별 핸들러를 만들어주고 이 핸들러에서 실제 데이터를 불러오는 함수를 호출하되, 정렬의 기준이 되는 필드 이름을 함수의 인자로 전달하도록 했다. 이중 첫 줄에 있는 부분은 특정 정렬 순서 버튼이 눌려지지 않더라도 데이터가 표시되도록 하기 위한 기본값으로 지정해 주었다.
데이터를 불러오는 함수인 loadProducts는 다음과 같은 형식으로 해당 정렬의 기준이 되는 필드 이름을 인자로 넘겨받은 후, db.collection().orderBy(정렬기준필드).get().then() 메서드를 이용해 정렬된 순서로 데이터들을 표시하게 된다.
이렇게 골격을 만든 후, 다음과 같이 부트스트랩을 활용하여 버튼의 모양을 좀 더 보기 좋게 외곽선 형식의 버튼으로 변경해 주었고
화면상으로는 다음과 같이 표시되게 되었다.
이러한 버튼 형식은 해당 버튼이 선택되면 다음과 같이 반전 효과가 있어 시각적으로도 보기에 좋은 편이다.
이렇게 버튼을 변경하고 나서 보니, 한 가지 욕심이 더 생겼다. 정렬의 순서조차 때로는 올림차순이 되도록, 또한 때로는 내림차순이 되도록 변경할 수 있었으면 좋겠다는 생각이 들었다.
이러한 방법에 대해 고민하다가, 다소 코드가 길어져 무식해 보이지만, 직관적이라 이해가 쉽고, 구현도 쉬운 방법을 택하기로 했다. 즉, 오름차순과 내림차순 각각의 버튼을 따로 만들기로 한 것이다.
우선 다음과 같이 버튼을 추가로 만들고, 각각에 위 방향 화살표와 아래 방향 화살표를 특수 부호 코드를 이용해서 만들어주었다.
화면상으로는 다음과 같이 각각의 화살표 방향이 지정된 별도의 버튼들로 표시된다.
다음 각각의 버튼별로 핸들러를 추가하되, 앞에서와 다르게 loadProducts 함수를 호출할 때, 정렬의 기준이 되는 필드 이름과 함께, 정렬 순서 값을 문자열로 “asc” 또는 “desc” 형태로 함께 전달해 주었다.
버튼의 수가 2배로 늘어났기에, 핸들러의 수도 2배로 늘어나 다소 무식해 보이기는 한다.
실제 값을 불러오는 loadProducts 함수는 다음과 같이 전달받은 인자 값을 orderBy(필드명, 정렬 순서) 메서드에 넣어 주도로 인수의 값을 늘려주었다.
이제 각각의 정렬 버튼을 눌러보면 원하는 대로 잘 정렬되어 데이터들이 표시된다. 의도한대로 완성되었다.
참고 – 가격을 나타내는 price 필드를 선택한 경우에는 현재 입력된 가격정보가 가격 단위 표시를 위해 단순한 문자 데이터 형식으로 입력되어 있기에, 문자를 기준으로 정렬된 순서로 보여주게 된다.
참고로 이렇게 개선된 코드의 전체 소스코드는 다음과 같다.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>데이타 읽기</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
<style>
.card-body {
padding-top: 0.1rem !important; /* 원하는 간격으로 조정하세요 */
}
.card-text {
margin-bottom: 0.1rem !important; /* 원하는 간격으로 조정하세요 */
}
</style>
<script src="https://www.gstatic.com/firebasejs/8.6.5/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/8.6.5/firebase-auth.js"></script>
<script src="https://www.gstatic.com/firebasejs/8.6.5/firebase-firestore.js"></script>
<script src="https://www.gstatic.com/firebasejs/8.6.5/firebase-storage.js"></script>
<script src="https://code.jquery.com/jquery-3.7.1.min.js" integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=" crossorigin="anonymous"></script>
<script src="/firebaseConfig.js"></script>
</head>
<body>
<div class="container">
<div class="m-3">
<button id="sortByRegNumAsc" class="btn btn-sm btn-outline-primary">번호↑</button>
<button id="sortByRegNumDesc" class="btn btn-sm btn-outline-primary">번호↓</button>
<button id="sortByNameAsc" class="btn btn-sm btn-outline-success">상품명 ↑</button>
<button id="sortByNameDesc" class="btn btn-sm btn-outline-success">상품명↓</button>
<button id="sortByPriceAsc" class="btn btn-sm btn-outline-danger">가격↑</button>
<button id="sortByPriceDesc" class="btn btn-sm btn-outline-danger">가격↓</button>
<button id="sortByDateAsc" class="btn btn-sm btn-outline-secondary">등록일 ↑</button>
<button id="sortByDateDesc" class="btn btn-sm btn-outline-secondary">등록일 ↓</button>
</div>
<div id="productList" class="m-3"></div>
</div>
<script>
var db = firebase.firestore();
var storage = firebase.storage();
function loadProducts(orderBy, orderDir) {
$('#productList').empty();
db.collection("products").orderBy(orderBy, orderDir).get().then((querySnapshot) => {
querySnapshot.forEach((doc) => {
var data = doc.data();
var date = new Date(data.날짜.seconds * 1000).toLocaleString();//YYYY/MM/DD hh:mm:ss 형식
var html = `
<div class="card mb-6" style="max-width: 540px;">
<div class="row g-0">
<div class="col-md-4">
<img src="${data.사진}" alt="${data.상품명}" style="width: 180px; height: 180px;">
</div>
<div class="col-md-7">
<div class="card-body">
<p class="card-text"><small class="text-muted">ID : ${data.상품등록번호}</small></p>
<h7 class="card-title" style="color: red;">${data.상품명}</h7>
<p class="card-text">${data.상품설명}</p>
<p class="card-text"><small class="text-muted">${data.가격}</small></p>
<p class="card-text"><small class="text-muted">${date}</small></p>
<p class="card-text"><small class="text-muted">Note: ${data.참고노트}</small></p>
<p class="card-text"><small class="text-muted">♥ : ${data.좋아요}</small></p>
</div>
</div>
</div>
</div>
`;
$('#productList').append(html);
});
});
};
$(document).ready(function() {
loadProducts("상품등록번호", "asc");
$('#sortByRegNumAsc').click(function() {
loadProducts("상품등록번호", "asc");
});
$('#sortByRegNumDesc').click(function() {
loadProducts("상품등록번호", "desc");
});
$('#sortByNameAsc').click(function() {
loadProducts("상품명", "asc");
});
$('#sortByNameDesc').click(function() {
loadProducts("상품명", "desc");
});
$('#sortByPriceAsc').click(function() {
loadProducts("가격", "asc");
});
$('#sortByPriceDesc').click(function() {
loadProducts("가격", "desc");
});
$('#sortByDateAsc').click(function() {
loadProducts("날짜", "asc");
});
$('#sortByDateDesc').click(function() {
loadProducts("날짜", "desc");
});
});
</script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
</body>
</html>
