app.js 파일을 간소화 시키기 위해 campground 경로를 사용하는 메소드만 별도로 저장
const express = require('express');
const router = express.Router();
const catchAsync = require('../utils/catchAsync')
const { campgroundSchema } = require('../schemas.js')
const ExpressError = require('../utils/ExpressError')
const Campground = require('../models/campground');
const validateCampground = (req,res,next) => {
//스키마가 정의되면 스키마에 데이터를 전달해야함.
const { error } = campgroundSchema.validate(req.body)
if(error){
// join : 메시지가 한개 이상이면 콤마로 연결시킴.
const msg = error.details.map(el => el.message).join(',');
throw new ExpressError(msg, 400)
} else {
//next를 해야 catchAsync에서 오류 잡아냄.
next();
}
}
//index page
router.get('/', catchAsync(async (req, res) => {
const campgrounds = await Campground.find({});
res.render('campgrounds/index', { campgrounds })
}));
//중요!!! 바로 밑 코드에서 router.get('/campgrounds:/id') 밑에 해당 코드를 적어주면
//new를 id로 인지해서 new라는 id의 캠핑장을 찾게됨
// 따라서 id 가 적혀진 코드보다 위에 적어줘야함.
//Add Campground
router.get('/new', (req, res)=> {
res.render('campgrounds/new');
})
//Add button Click
//validateCampground : 폼 제출시 규칙을 지켜가며 제출했는지에 대한 점검
//catchAsync :
router.post('/', validateCampground , catchAsync(async(req, res, next)=> {
//if(!req.body.campground) throw new ExpressError('Invalid Campground Data', 400)
//Campground의 새로운 객체 (폼에 입력된 새로운 캠프장 정보)
//mongoose스키마는 아님. 몽구스로 저장하기 전에 데이터 유효성 검사 진행.
const campground = new Campground(req.body.campground);
await campground.save();
res.redirect(`/campgrounds/${campground._id}`)
}))
//when Click one of the Campground (Information)
router.get('/:id' , catchAsync(async (req, res,next) => {
const { id } = req.params;
const campground = await Campground.findById(id).populate('reviews')
res.render('campgrounds/show', { campground });
}));
//Edit Campground
router.get('/:id/edit', catchAsync(async(req,res,next)=>{
//해당 id로 캠핑장 찾기.
const campground = await Campground.findById(req.params.id);
res.render('campgrounds/edit', { campground })
}));
// Update button Click
router.put('/:id', catchAsync(async(req, res, next)=> {
const { id } = req.params;
// 두번째 인수는 실제로 업데이트 할 쿼리, '...'을 붙이는 이유는 업데이트된 정보를 전체 객체에 전달하기위해
const campground = await Campground.findByIdAndUpdate(id, {...req.body.campground});
res.redirect(`/campgrounds/${campground._id}`)
}))
router.delete('/:id', catchAsync(async (req,res,next)=> {
const { id } = req.params;
const campground = await Campground.findByIdAndDelete(id);
res.redirect('/campgrounds')
}));
module.exports = router;
app.js
<review.js>
const express = require('express');
const router = express.Router({ mergeParams = true });
const catchAsync = require('../utils/catchAsync')
const { reviewSchema } = require('../schemas.js')
const ExpressError = require('../utils/ExpressError')
const Campground = require('../models/campground');
const Review = require('../models/review')
const validateReview = (req,res,next) => {
const { error } = reviewSchema.validate(req.body)
if(error) {
const msg = error.details.map(el => el.message).join(',');
throw new ExpressError(msg, 400)
} else {
next();
}
}
router.post('/' , validateReview , catchAsync(async(req,res) => {
const { id } = req.params;
const campground = await Campground.findById(id);
const review = new Review(req.body.review);
campground.reviews.push(review);
await review.save();
await campground.save();
res.redirect(`/campgrounds/${campground._id}`)
}))
router.delete('/:reviewId', catchAsync(async(req,res,next)=> {
const {id, reviewId} = req.params;
//두번쨰 인자는 객체 전달
//$pull : 배열에 있는 모든 인스턴스 중 특정 조건에 만족하는 값을 지움
// reviews 객체들 중 reviewId가 있는걸 모두 지움.
await Campground.findByIdAndDelete(id, { $pull: {reviews: reviewId }})
await Review.findByIdAndDelete(reviewId);
res.redirect(`/campgrounds/${id}`);
}))
module.exports = router;
app.js 와 reviews.js의 분리된 id 매개변수 병합시키기
const router = express.Router({ mergeParams = true });
<validateFomrs.js>
// Example starter JavaScript for disabling form submissions if there are invalid fields
(function () {
"use strict";
// Fetch all the forms we want to apply custom Bootstrap validation styles to
const forms = document.querySelectorAll(".validated-form");
// Loop over them and prevent submission
Array.from(forms).forEach((form) => {
form.addEventListener(
"submit",
(event) => {
if (!form.checkValidity()) {
event.preventDefault();
event.stopPropagation();
}
form.classList.add("was-validated");
},
false
);
});
})();
boilerplate.js
app.js에 public 폴더 내 파일들을 사용할거라고 알려주기.
npm i connect-flash (터미널 설치 명령어)
<app.js>
const flash = require('connect-flash')
app.use(flash());
req.flash
<flash.ejs>
<% if(success && success.length) %>
<div class="alert alert-success alert-dismissible fade show" role="alert">
<%= success %>
<button
type="button"
class="btn-close"
data-bs-dismiss="alert"
aria-label="Close"
>
<span aria-hidden="true">×</span>
</button>
</div>
<% } %>
boilerplate.ejs에 flash.ejs 사용 알리기.
router 파일에 req.flash 설정
boilerpalte.ejs
해당 캠핑장 삭제 후 url 입력시 정보를 불러 올 수 없을 때