위 프로젝트에서는 수정 / 삭제 버튼이 각 책의 목록마다 나와있었는데 그것을 아래로 내려 한 버튼에 구현하게 하는 새로운 버전을 만들었다. 원래 이렇게 만드려고 했으나 시간상 윗 글처럼 만든건데 수정했다고 보면 될 것같다. 로컬스토리지로 만들었을 때와 같은 방식이다.
index.html
<!DOCTYPE html>
<html>
<head>
<title>작은 도서관</title>
</head>
<style>
</style>
<link rel="stylesheet" href="./style.css">
<body onload="startServer()">
<div id="library">
<center>
<div id="logo"><br>
<center>
<a href="#"><img src="./vendit-logo-white.png" onclick="location.reload()" width="150px"></a>
</center>
</div>
</center>
<center>
<div id="search">
<center>
<!--<b>서적 검색</b><br>-->
<input type="search" id="searchInput" placeholder="제목, 내용, 저자로 검색">
<input class="dateSet" type="date" id="dateStart" >
~
<input class="dateSet" type="date" id="dateEnd" >
<button id="searchBtn" type="submit" onclick="searchBook(document.getElementById('searchInput').value,
new Date(document.getElementById('dateStart').value),
new Date(document.getElementById('dateEnd').value))">검색</button>
</center><br>
</div>
</center>
<center>
<div id="table">
<!--<b>찾은 서적 목록</b><br>-->
<center>
<table>
<thead>
<tr><th>순번</th><th>제목</th><th>내용</th><th>저자</th><th>출간날짜</th></tr>
</thead>
<tbody id="bTable"></tbody>
</table>
</center>
</div>
</center>
<center>
<div id="newBooks">
<center><br>
<!--<b>새로운 서적 등록</b><br>-->
<input class="new" type="text" id="title" name="title" placeholder="제목">
<input class="new" type="text" id="author" name="author" placeholder="저자">
<input class="dateSet" type="date" id="date" name="date" placeholder="출간날짜"><br><br>
<textarea name="contents" type="text" id="content" name="content" placeholder="내용"></textarea><br>
<button id="putBtn" type="submit" onclick="inputEditBook()">등록 / 수정</button>
<button id="delBtn" type="submit" onclick="deleteBook()">삭제</button>
</center><br>
</div>
</center>
</div>
<script src="./library.js"></script>
</body>
</html>
/server/index.js
'use strict';
const express = require('express');
const app = express();
const { Sequelize, DataTypes } = require('sequelize');
const env = process.env.NODE_ENV || 'development';
const config = {
"development": {
"username": "root",
"password": "****",
"database": "library",
"host": "127.0.0.1",
"dialect": "mysql"
},
}[env];
let cors = require('cors')
let http = require('http');
let bodyParser = require('body-parser');
let sequelize;
if (config.use_env_variable) {
sequelize = new Sequelize(process.env[config.use_env_variable], config);
} else {
sequelize = new Sequelize(config.database, config.username, config.password, config);
}
const books = sequelize.define('books', {
title: {
type: DataTypes.STRING(200),
allowNull: true,
},
content: {
type: DataTypes.STRING,
allowNull: true,
},
author: {
type: DataTypes.STRING,
allowNull: true,
},
date: {
type: DataTypes.STRING,
allowNull: true,
}
});
sequelize.sync({ force: false }).then( () => {
console.log("DB connection is successful");
}).catch(err => {
console.log("DB connection faild");
console.log(err);
});
app.use(cors())
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended : false}));
app.get('/get', async(req, res) => {
await books.findAll().then(result => {
res.json(result)
});
});
app.post('/inputBook', async (req, res) => {
await books.create({
title : req.body.title,
content : req.body.content,
author : req.body.author,
date : req.body.date
}).then(result => {
console.log("Success input data" + result);
res.redirect('/');
}).catch(err => {
console.log("Fail update data" + err);
});
});
app.patch('/edit/', async(req, res) => {
await books.update({
title : req.body.title,
content : req.body.content,
author : req.body.author,
date : req.body.date
}, {
where : {id: req.body.id}
}).then(result => {
console.log("Success update data" + result);
res.redirect('/');
}).catch(err => {
console.log("Fail update data" + err)
})
})
app.delete('/delete/:id', async(req, res) => {
await books.destroy({
where: {id: req.params.id}
}).then(result => {
console.log(result)
res.redirect('/');
}).catch(err => {
console.log("Fail delete data" + err);
});
});
http.createServer(app).listen(3000, () => {'Server is running on port 3000...'})
library.js
const element = document.getElementById("bTable");
let db = [];
let temp = [];
function showHtml(i) {
return `
<td>${i + 1}</td>
<td><a href="#" id='${i}' onclick='popInfo(this.id);'>${db[i].title}</a></td>
<td>${db[i].content}</td>
<td>${db[i].author}</td>
<td>${db[i].date}</td>
`;
}
function startServer() {
fetch("http://localhost:3000/get")
.then((response) => response.json())
.then((data) => {db = data; showTable();})
.catch(err => {
console.log('Fetch Error', err)
})
}
function showTable() {
for(let i = 0; i <= db.length - 1; i++) {
element.innerHTML += showHtml(i);
};
for(let i = 0; i < 5 - db.length; i++) {
element.innerHTML += `<td>-</td>
<td>-</td>
<td>-</td>
<td>-</td>
<td>-</td>
`;
};
};
function inputEditBook() {
if(temp.length === 0) {
fetch("http://localhost:3000/inputBook", {
method: "POST",
body: JSON.stringify({
title: document.getElementById("title").value,
content: document.getElementById("content").value,
author: document.getElementById("author").value,
date: document.getElementById("date").value
}),
headers: {
"Content-type": "application/json; charset=UTF-8"
}
})
.then(response => response.json())
.then(json => console.log(json))
location.reload();
} else if(temp.length !== 0) {
fetch("http://localhost:3000/edit/", {
method: "PATCH",
body: JSON.stringify({
id: temp[temp.length - 1],
title: document.getElementById("title").value,
content: document.getElementById("content").value,
author: document.getElementById("author").value,
date: document.getElementById("date").value
}),
headers: {
"Content-type": "application/json; charset=UTF-8"
}
})
.then(response => response.json())
.then(json => console.log(json))
location.reload();
}
}
function deleteBook(){
fetch("http://localhost:3000/delete/" + temp[temp.length - 1], {
method: "DELETE"
})
.then(response => response.json())
.then(json => console.log(json))
location.reload();
}
function popInfo(id) {
document.getElementById("title").value = db[id].title;
document.getElementById("content").value = db[id].content;
document.getElementById("author").value = db[id].author;
document.getElementById("date").value = db[id].date;
temp.push(db[id].id);
};
function searchBook(data, sDate, eDate) {
console.log(data, sDate, eDate)
element.innerHTML = ``;
if(!data && isNaN(sDate)) {
location.reload();
} else {
for(let i = 0; i <= db.length - 1; i++) {
let popData = (db[i].title.includes(data)) || (db[i].author.includes(data)) || (db[i].content.includes(data));
if(!isNaN(sDate) ? popData && sDate <= new Date(db[i].date) && eDate >= new Date(db[i].date) : popData) {
element.innerHTML += showHtml(i);
};
};
};
};
style.css
.dateSet {
width: 110px;
height: 16px;
}
#logo {
background-color: #5E6698;
width: 950px;
padding: 5px;
}
#search {
background-color: #5E6698;
width: 950px;
padding: 5px;
}
#table {
background-color: white;
width: 950px;
padding: 5px;
height: 276px;
overflow: auto;
}
#newBooks {
background-color: #5E6698;
width: 950px;
padding: 5px;
}
#searchInput {
width: 440px;
}
#searchBtn {
width: 100px;
}
#putBtn {
width: 400px;
height: 50px;
}
#delBtn {
width: 400px;
height: 50px;
}
#title {
width: 505px;
}
#content {
width: 798px;
height: 100px;
resize: none;
}
table {
background-color: white;
width: 810px;
table-layout: fixed;
word-break: break-all;
}
tr {
background-color: white;
padding: 10px;
border: 0px solid black;
}
th {
padding: 10px;
border: 0px solid black;
}
td {
padding: 10px;
border: 0px solid black;
text-align: center;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
a {
color: black;
text-decoration: none;
}
a:hover {
color: rgb(74, 138, 211);
}
사실상 크게 변화를 준건 library.js밖에 없다.
아래 github 주소에서 정확한 소스코드 다운파일을 받을 수 있다.
github.com/ukcasso/library_git
'토이 프로젝트' 카테고리의 다른 글
[자바스크립트 ] 매크로 만들기 - puppeteer (간단한 자동 로그인) (0) | 2021.01.15 |
---|---|
로또 추점기, 로또 번호 생성기 (로또 추첨 사이트) (0) | 2020.10.30 |
[자바스크립트] 작은 도서관 프로그램 만들기 (MySQL, Express, Fetch API, Node.js) - Mysql, express, fetch api crud example (1) (0) | 2020.10.13 |
[자바스크립트] 작은 도서관 프로그램 만들기 (MySQL, Express, ejs, Node.js) - Mysql, express, ejs crud example (0) | 2020.10.08 |
[자바스크립트] 로또 번호 분석기 (Lotto Analysis) (0) | 2020.09.16 |