주소록 - Show, Edit, Update, Destroy

소스코드

이 게시물에는 코드작성이 포함되어 있습니다. 소스코드를 받으신 후 진행해 주세요. MEAN Stack/개발 환경 구축에서 설명된 프로그램들(git, npm, atom editor)이 있어야 아래의 명령어들을 실행할 수 있습니다.

이 게시물의 소스코드는 주소록 만들기 / 주소록 - Index, New, Create에서 이어집니다.

contact-book.git 을 clone 한 적이 있는 경우: 터미널에서 해당 폴더로 이동 후 아래 명령어들을 붙여넣기합니다. 폴더 내 모든 코드가 이 게시물의 코드로 교체됩니다. 이를 원치 않으시면 이 방법을 선택하지 마세요.

git reset --hard
git pull
git reset --hard dd4a967
git reset --soft 67c2949
npm install
atom .

contact-book.git 을 clone 한 적이 없는 경우: 터미널에서 코드를 다운 받을 폴더로 이동한 후 아래 명령어들을 붙여넣기하여 contact-book.git 을 clone 합니다.

git clone https://github.com/a-mean-blogger/contact-book.git
cd contact-book
git reset --hard dd4a967
git reset --soft 67c2949
npm install
atom .

- Github에서 소스코드 보기: https://github.com/a-mean-blogger/contact-book/tree/dd4a967c5d8c1ab90719d89c0f716505e978e921


7 actions 중 나머지 show, edit, update, destroy를 구현해 봅시다.

전체 목록(index)에서 하나를 선택하면 해당 데이터를 보여주고(show)
해당 데이터를 수정할 수 있는 form을 만들어서 이 정보를 서버로 전달할 수 있게 하고(edit)
서버가 이 정보를 사용해서 DB에 정보를 수정하고(update)
해당 데이터를 삭제할 수도 있습니다(destroy).

폴더구조

주황색은 변경된 파일, 녹색은 새로 생성된 파일, 회색은 변화가 없는 파일입니다.

Package 설치

7 actions 중 update과 destroy는 HTTP Methods 중 put과 delete을 사용하는데, 대부분의 브라우저의 form은 get과 post 만을 허용하고 나머지는 허용하지 않습니다. 브라우저에서 허용하진 않지만 나중에 API로 연결할 때는 문제가 없기 때문에 HTTP를 올바르게 사용하는 법을 익히는 것이 더 중요합니다. 지금은 일단 method override라는  package를 설치하여 이를 우회하도록하겠습니다.

$ npm install --save method-override

이 package는 query로 method 값을 받아서 request의 HTTP method를 바꿔주는 역할을 합니다.

해당 부분은 코드에서 살펴보겠습니다.

코드

// index.js

var express = require('express');
var mongoose = require('mongoose');
var bodyParser = require('body-parser');
var methodOverride = require('method-override'); // 1
var app = express();

// DB setting ...

// Other settings
app.set('view engine', 'ejs');
app.use(express.static(__dirname+'/public'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended:true}));
app.use(methodOverride('_method')); // 2

// DB schema ...

// Routes
// Home ...
// Contacts - Index ...
// Contacts - New ...
// Contacts - create ...
// Contacts - show // 3
app.get('/contacts/:id', function(req, res){
  Contact.findOne({_id:req.params.id}, function(err, contact){
    if(err) return res.json(err);
    res.render('contacts/show', {contact:contact});
  });
});
// Contacts - edit // 4
app.get('/contacts/:id/edit', function(req, res){
  Contact.findOne({_id:req.params.id}, function(err, contact){
    if(err) return res.json(err);
    res.render('contacts/edit', {contact:contact});
  });
});
// Contacts - update // 5
app.put('/contacts/:id', function(req, res){
  Contact.findOneAndUpdate({_id:req.params.id}, req.body, function(err, contact){
    if(err) return res.json(err);
    res.redirect('/contacts/'+req.params.id);
  });
});
// Contacts - destroy // 6
app.delete('/contacts/:id', function(req, res){
  Contact.deleteOne({_id:req.params.id}, function(err){
    if(err) return res.json(err);
    res.redirect('/contacts');
  });
});

// Port setting ...

...으로 표시된 부분은 이전과 변화가 없는 부분입니다.

새로 추가된 부분들을 각각 살펴봅시다.

var methodOverride = require('method-override'); // 1 

1. method-override module을 methodOverride변수에 담습니다.

app.use(methodOverride('_method')); // 2 

2. _method의 query로 들어오는 값으로 HTTP method를 바꿉니다. 예를들어 http://example.com/category/id?_method=delete를 받으면 _method의 값인 delete을 읽어 해당 request의 HTTP method를 delete으로 바꿉니다.

// Contacts - show // 3 
app.get('/contacts/:id', function(req, res){
  Contact.findOne({_id:req.params.id}, function(err, contact){
    if(err) return res.json(err);
    res.render('contacts/show', {contact:contact});
  });
});

3. "contacts/:id"에 get 요청이 오는 경우 :

:id처럼 route에 콜론(:)을 사용하면 해당 위치의 값을 받아 req.params에 넣게 됩니다. 예를 들어 "contacts/abcd1234"가 입력되면 "contacts/:id" route에서 이를 받아 req.params.id에 "abcd1234"를 넣게 됩니다.

Model.findOne은 DB에서 해당 model의 document를 하나 찾는 함수입니다. 첫번째 parameter로 찾을 조건을 object로 입력하고 data를 찾은 후 콜백 함수를 호출합니다. Model.find와 비교해서 Model.find는 조건에 맞는 결과를 모두 찾아 array로 전달하는데 비해 Model.findOne은 조건에 맞는 결과를 하나 찾아 object로 전달합니다. (검색 결과가 없다면 null이 전달됩니다.)

위 경우에는 {_id:req.params.id}를 조건으로 전달하고 있는데, 즉 DB의 contacts collection에서 _id가 req.params.id와 일치하는 data를 찾는 조건입니다.

에러가 없다면 검색 결과를 받아 views/contacts/show.ejs를 render합니다.

// Contacts - edit // 4 
app.get('/contacts/:id/edit', function(req, res){
  Contact.findOne({_id:req.params.id}, function(err, contact){
    if(err) return res.json(err);
    res.render('contacts/edit', {contact:contact});
  });
});

4. "contacts/:id/edit"에 get 요청이 오는 경우 :

Model.findOne이 다시 사용되었습니다. 검색 결과를 받아 views/contacts/edit.ejs를 render합니다.

// Contacts - update // 5 
app.put('/contacts/:id', function(req, res){
  Contact.findOneAndUpdate({_id:req.params.id}, req.body, function(err, contact){
    if(err) return res.json(err);
    res.redirect('/contacts/'+req.params.id);
  });
});

5. "contacts/:id"에 put 요청이 오는 경우 :

Model.findOneAndUpdate는 DB에서 해당 model의 document를 하나 찾아 그 data를 수정하는 함수입니다. 첫번째 parameter로 찾을 조건을 object로 입력하고 두번째 parameter로 update할 정보를 object로 입력data를 찾은 후 callback함수를 호출합니다.
이때 callback함수로 넘겨지는 값은 수정되기 전의 값입니다. 만약 업데이트 된 후의 값을 보고 싶다면 콜백 함수 전에 parameter로 {new:true}를 넣어주면 됩니다.

Data 수정 후 "/contacts/"+req.params.id로 redirect합니다.

// Contacts - destroy // 6
app.delete('/contacts/:id', function(req, res){
  Contact.deleteOne({_id:req.params.id}, function(err){
    if(err) return res.json(err);
    res.redirect('/contacts');
  });
});

6. "contacts/:id"에 delete 요청이 오는 경우 :

Model.deleteOne은 DB에서 해당 model의 document를 하나 찾아 삭제하는 함수입니다. 첫번째 parameter로 찾을 조건을 object로 입력하고 data를 찾은 후 callback함수를 호출합니다.

Data 삭제후 "/contacts"로 redirect합니다.

다음으로 view 파일들을 살펴봅시다.

<!-- views/contacts/index.ejs-->

<!DOCTYPE html>
<html>
  <head>
    <%- include('../partials/head') %>
  </head>
  <body>
    <%- include('../partials/nav') %>

    <div class="contact contact-index">
      <h2>Index</h2>
      <ul>
        <% contacts.forEach(function(contact) { %>
          <li>
            <a href="/contacts/<%= contact._id %>"><%= contact.name %></a> <!-- 1 -->
          </li>
        <% }) %>
      </ul>
    </div>
  </body>
</html>

1. 이름에 a tag를 추가하여 show action과 연결했습니다.

<!-- views/contacts/show.ejs -->

<!DOCTYPE html>
<html>
  <head>
    <%- include('../partials/head') %>
  </head>
  <body>
    <%- include('../partials/nav') %>

    <div class="contact contact-show">
      <h2>Show</h2>
      <div>
        <h3><%= contact.name%></h3>
        <label>Email</label><span><%= contact.email %></span>
        <br>
        <label>Phone</label><span><%= contact.phone %></span>
      </div>
      <div class="contact-menu">
        <a href="/contacts/<%= contact._id %>/edit">Edit</a> <!-- 1 -->
        <form action="/contacts/<%= contact._id %>?_method=delete" method="post"> <!-- 2 -->
          <a href="#" onclick="confirm('Do you want to delete this?')?this.parentElement.submit():null;">Delete</a>
        </form>
      </div>
    </div>
  </body>
</html>

1. a tag로 Edit을 만들어 edit action에 연결했습니다.

2. a tag로는 get만 요청할 수 있기 때문에 Delete은 form으로 처리해야 합니다. form에서도 post밖에 요청할 수 없기 때문에 ?_method=delete이 action에 query로 추가되었습니다. 이 부분은 서버의 method override package에 의해 처리되어 delete 요청으로 변경됩니다.

3. Delete을 눌렀을때 onclick을 사용해서 confirm을 띄우고 yes인 경우 form을 submit하게 합니다.

<!-- views/contacts/edit.ejs -->

<!DOCTYPE html>
<html>
  <head>
    <%- include('../partials/head') %>
  </head>
  <body>
    <%- include('../partials/nav') %>

    <div class="contact contact-edit">
      <h2>Edit</h2>
      <form class="contact-form" action="/contacts/<%= contact._id %>?_method=put" method="post">
        <div>
          <label for="name">Name</label>
          <input type="text" id="name" name="name" value="<%= contact.name %>">
        </div>
        <div>
          <label for="email">Email</label>
          <input type="text" id="email" name="email" value="<%= contact.email %>">
        </div>
        <div>
          <label for="phone">Phone</label>
          <input type="text" id="phone" name="phone" value="<%= contact.phone %>">
        </div>
        <div>
          <button type="submit">Submit</button>
        </div>
      </div>
    </form>
  </body>
</html>

edit.ejs는 new.ejs와 거의 같지만 form에 해당 data의 값들이 미리 들어 있고, form action이 다릅니다.

put 역시 form에서 사용할 수 없으므로 _method=put을 사용하였습니다.

/* public/css/master.css */

.contact h2{
  color: tomato;
}
.contact .contact-form label,
.contact-show label{
  display: inline-block;
  width: 70px;
}
.contact .contact-menu form{
  display: inline-block;
}

CSS 는 따로 설명하지 않겠습니다.

실행결과

nodemon으로 실행결과를 확인합시다.

$ nodemon

contacts/new로 들어가면 데이터를 생성할 수 있는 form이 나옵니다.

새로운 데이터를 생성한 후 submit 합니다.

test가 생성되었습니다.

test를 클릭하면 Edit과 Delete이 새로 생긴 것이 보입니다.

Edit을 클릭하면 값을 수정할 수 있는 form이 나옵니다.

값을 수정한 후 submit합니다.

값이 변경되었습니다.

Delete을 눌러봅시다.

경고가 보입니다. OK를 누릅니다.

값이 지워졌습니다.

마치며..

마침내 CRUD가 모두 되는 주소록의 기능이 완성되었습니다.
index.js 파일에 제법 코드가 많아졌는데, 다음 강의에서는 코드가 더 복잡해지기 전에 Node.js Module을 사용하여 코드를 정리하는 법을 알아보겠습니다.

댓글

Deleted Comment
Deleted Comment
s
seung joo Rim (Jeremy) 2017.04.03
사소한 오타지만 index.html이 아니라 index.ejs 으로 저장해야 실행이 되네요^^  index부분 첫줄 주석부분에 오타입니다^^ 잘보고 있습니다.
I
Ian H 2017.04.03
@seung joo Rim (Jeremy),
앗, 수정했습니다. 알려주셔서 감사합니다^^
정석호 2017.07.03
method override 모듈을 쓰지 않고 클라이언트단에서 ajax 로 메소드 설정해줘서 통신해도 문제 없나요??
I
Ian H 2017.07.03
@정석호,
ajax를 쓰시면 method override 안쓰셔도 됩니다^^
정석호 2017.07.04
@Ian H,
감사합니당
Y
Ye Lyn Kim 2017.07.17
죄송합니다만ㅠㅠ TypeError: Cannot read property 'id' of undefined     at C:\workspace\contact-book\index.js:85:43와 같은 에러는 왜 발생하는것인지 궁금합니다. 그대로 했는데 잘 안되네요ㅠㅠ
I
Ian H 2017.07.17
@Ye Lyn Kim,
소스코드를 봐야 알 수 있을 것 같은데요,  https://github.com/a-mean-blogger/contact-book/blob/bc0cc4993e1f3c117619e484a5485a5140be12e6/index.js 제 코드의 index.js 85번째 줄에는 'id'가 없어서..
현재 소스코드를 github에 올리시고 저에게 주소를 알려주시면 살펴보겠습니다.
정영호 2017.07.17
질문이 있습니다! form 부분에서 보안상의 이유로 get과 post만 사용이 가능하다고 되어있는데 method-override를 사용하면 그 보안을 억지로 깨는 것(?) 아닌가요??
I
Ian H 2017.07.17
@정영호,
제가 배울때 보안상의 이유라고 들었는데, 사실 더 찾아보니까 보안상의 이유라기 보다 표준을 만들 때 form은 post와 get만 허용해야한다 vs form이 나머지 method도 허용해야 한다는 논란이 있었는데 결국 form은 post와 get만 허용하는 걸로 결정이 났고, 사람들은 계속 나머지도 허용해야 한다고 주장하고 있는 상태네요.. 출처: https://softwareengineering.stackexchange.com/questions/114156/why-are-there-are-no-put-and-delete-methods-on-html-forms 본문 내용도 수정을 하였습니다.
C
Chooni Jo 2018.08.10
사소하지만, "contracts/new로 들어가면 데이터를 생성할 수 있는 form이 나옵니다." 에 오타가 있습니다. contacts/new 로 정정하시면 될 것 같습니다~!!
I
Ian H 2018.08.10
@Chooni Jo,
알려주셔서 감사합니다^^ 수정하였습니다!
즐기면서공부하자 2018.08.21
정말재밌네욤 ㅋㅋㅋ 좋은 강의 감사합니다~ 꾸벅.
I
Ian H 2018.08.21
@즐기면서공부하자,
와 재미있으면 공부도 더 잘되죠. 화이팅!
안성현 2019.06.25
아이템을 생성하는것까지는 문제가 없는데, 생성된 아이템의 정보를 확인하려고 클릭을 하면 {"message":"Cast to ObjectId failed for value \"5d11d7cbe7bca2070e2cba85\" at path \"_id\" for model \"contact\"","name":"CastError","stringValue":"\"5d11d7cbe7bca2070e2cba85\"","kind":"ObjectId","value":"5d11d7cbe7bca2070e2cba85","path":"_id"} 이와 같은 에러 문이 발생됩니다. 
운영체제, 노드제이에스, 몽고디비 간의 버전 차이로 호환이 잘 안되는걸까요? 참고로 설치는 윈도우에서 하지 않고 공부삼아서 하려고 가상머신에 리눅스 우분투 16.04 를 셋팅하고  소스는 git에서 다운받아 실행시켜보았습니다. 원인이 뭘까요?
I
Ian H 2019.06.26
@안성현,
안녕하세요 방금 소스코드 받아서 실행해 봤는데 잘 됩니다. MongoDB를 local에 설치해서 사용하시나요? 
https://www.a-mean-blog.com/ko/blog/단편강좌/_/mongoDB-Atlas-가입-방법-무료-mongo-DB-클라우드-서비스 글을 참고하여 DB를 만들어 보시고 사용해 보세요
장재영 2019.07.11
코드 항목에 "// Contacts - destroy // 6"에  app.deleteOne("/contacts/:id", function(req, res)에서 "TypeError: app.deleteOne is not a function"라고 나옵니다. "Contact.remove" 이 부분도 아래 설명부분 코드랑 틀리고. 
I
Ian H 2019.07.11
@장재영,
제보해주신 부분 수정하였습니다. 알려주셔서 감사합니다^^
J
Jake Lyu 2020.03.19
안녕하세요 <a href="#" onclick="confirm('Do you want to delete this?')?this.parentElement.submit():null;">Delete</a>
?this.parentElement.submit():null; 이 부분 어떤 기능을 하는지 자세히 설명좀 부탁드립니다.  감사합니다.~
I
Ian H 2020.03.19
@Jake Lyu,
{조건}?{조건이_참일 경우_할일}:{조건이_거짓일_경우_할일}; 은 '삼항방정식'이라고 부르는 식입니다. 
confirm('Do you want to delete this?')?this.parentElement.submit():null;의 경우, confirm('Do you want to delete this?')이 Okay/Cancel를 띄우고 Okay를 클릭하면 true를 return, Cancel을 클릭하면 false를 return하게 됩니다. 그러므로 Okay를 누른경우 this.parentElement.submit()를 실행하여 from을 submit하게 되고, Cancel을 클릭한 경우 null을 실행하여 아무것도 하지 않습니다.
더 자세한 설명이 필요하시면 댓글남겨주세요^^ 감사합니다!
J
Jake Lyu 2020.03.20
@Ian H,
너무 자세하고 친절한 설명 감사드립니다. 프로그래머분들 글 보면 본인 수준에서 너무 기초적인 걸 감안하지 않고 작성하는 경우가 많은데, 이안님 포스팅 보면서 참 누구나 쉽게 따라할 수 있도록 세세히 설명된 것에 놀랐습니다. ㅋㅋ 항상 감사합니다. 
I
Ian H 2020.03.22
@Jake Lyu,
원글은 예전에 네이버 블로그에 작성했던 글인데요, 제가 배울때 썼던 글이라서 그래요 ㅋㅋ 그때 제 수준에서 쓴거죠 ㅋㅋ
이현종 2020.03.26
안녕하세요! 좋은글 보면서 열심히 공부하고있습니다. node공부 한달차되가는 학생입니다. 다름이 아니라 사소한 질문하나 드리고 싶은데요. edit.ejs에서 div닫는태그와 form닫는태그의 순서가 바뀐거같은데 이유가 따로있나요??  그리고 method-override모듈은 진짜 막막했던 methd문제를 확 풀어준거 같아요!!!!(편안) 감사합니다!!
이현종 2020.03.26
그리고 혹시 후반부에 jQuery부분도 다루시는지 궁금합니다
I
Ian H 2020.03.26
@이현종,
안녕하세요^^ method-override 필수죠 ㅋㅋ div와 form 태그 순서는 저의 실수입니다 ㅠㅠ 나중에 시간날 때 꼭 고치도록 하겠습니다. 요즘은 좀 많이 바빠서 ㅠㅠ 제보주셔서 감사합니다!
김진영 2020.06.04
안녕하세요! 강의 잘 보고있습니다. 질문이 있는데 DB에서 검색할 때 _id로 찾는데 _id는 name. email, phone 중 어떤 값을 비교하는건가요? 그리고 왜 그냥 id가 아니고 _(언더바)가 id 앞에 붙는건가요??
I
Ian H 2020.06.04
@김진영,
안녕하세요! _id는 mongodb에서 자동으로 생성되는 값입니다. 그래서 앞에 _가 붙는 거구요.  즉 contact를 생성하면 contact._id에는 랜덤한 값의 아이디가 자동으로 생성됩니다. index.ejs, show.ejs, edit.ejs view에서는 이 값을 backend로 넘겨주게 되구요, 이 값을 사용해서 하나의 contact를 db에서 불러와 원하는 작업을 하게 됩니다!
u
utoru80 2020.07.30
@Ian H,
index.ejs, show.ejs, edit.ejs view에서는 이 값을 backend로 넘겨주게 되구요,  이부분이요.  몽고디비에 자동 생성되는  _id 값 과 일치하는 데이터를 가지고 오잖아요. index.ejs, show.ejs, edit.ejs view에서 는 _id 와 똑같은값을 url 로 받잖아요 그럼 url 에서는 그 몽고디비  _id 값과 같은것을 어디서 알아와가지고선 url에 입력 한거에요? 사람이 url에 입력하는게 아니고 자동생성되는거 같은데요.
I
Ian H 2020.07.30
@utoru80,
Create route을 통해 DB에서 _id가 생성되고, Index route을 통해 _id list가 DB에서 불려져와서 사용자의 브라우저에 노출이 됩니다. Index에서 게시물을 클릭하면 Show Route으로 _id가 전달이 되는 식이죠.
즉 Index(색인) 는 말 그대로 DB의 데이터의 리스트를 보여주는데, 가장 중요한 목적이 DB의 데이터를 특정할 수 있는 정보(여기서는 _id)를 사용자에게 전달하는 것입니다.
참고로 이 정보가 꼭 _id일 필요는 없습니다. 웹사이트 사용자 리스트를 보여준다면, 사용자의 username은 DB에 unique해야 하므로 username이 사용자를 특정할 수 있는 정보가 됩니다. 그러므로 _id가 아닌, username을 사용해서 사용자를 특정할 수도 있죠. 
u
utoru80 2020.07.31
@Ian H,
아 데이터객체가  create라우터로 최초에 생성된후 index 라우터로 리다이렉트한후에 index.ejs 에 데이터객체 공유해주면  그 index.ejs에서 get방식 url로 공유해준 _id 를 넣었네요. 이제 이해가 되네요. 감사합니다.
I
Ian H 2020.08.03
@utoru80,
정확합니다 👍
u
utoru80 2020.07.30
show 부분에서요 에러가 없다면 검색 결과를 받아 views/contacts/show.ejs를 render합니다. 라고 나와있는데요. 왜코드에서는 views제거하고 contacts/show 만 적었나요?? 어디를 바도 view가 기본경로로 지정된거 없어보이는데요
I
Ian H 2020.07.30
@utoru80,
안녕하세요, 이런 관찰력과 비판적인 사고는 프로그래머에게 아주 중요하죠 ㅋㅋ 칭찬합니다!
질문에 대한 답을 드리자면 Express 프레임워크가 기본적으로 views 폴더를 template 저장공간으로 지정했기 때문입니다.
https://expressjs.com/en/4x/api.html#app.set 에 가시면 표가 보이고, views항목에 가면 default로 process.cwd() + '/views'가 되어 있는 것을 볼 수 있습니다.
app.set('views', /myViewFolder') 명령어로 이 기본값을 변경할 수 있습니다.
u
utoru80 2020.07.31
@Ian H,
정말 자세하게 아시네요. 향상 감사합니다.
I
Ian H 2020.08.03
@utoru80,
내용을 전부 강의에 넣을 수 없어서 아쉽습니다 ㅠㅠ
김도환 2020.08.14
안녕하세요.  index에서 show화면으로 가기위해 등록된 이름을 누르면 다음과 같이 에러가 발생합니다. Cannot GET /contact/5f364c71913178444cebdccb
참고로 mongoDB는 atlas로 사용을 할 수가 없어서 현재 로컬에 설치해서 사용중입니다.  MongoDB compass에서 데이터를 확인해봤는데 id는 일치합니다. _id:objectId("5f364c71913178444cebdccb") name:"kim" email:"[email protected]" phone:"123-4545" __v:0
I
Ian H 2020.08.18
@김도환,
Cannot 'METHOD+주소' 에러는 아예 해당 route이 존재하지 않을 때 발생하는 에러입니다.
만약 제 코드를 그대로 사용하셨다면 contact의 get route는 '/contacts/아이디' (contacts를 복수형으로 마지막에 s를 붙여야 합니다) 형태로 아마 contact를 단수형으로 쓰셔서 그런 것 같습니다.
김도환 2020.08.20
@Ian H,
감사합니다! 재밌게 학습하고있습니다.
I
Ian H 2020.08.20
@김도환,
재밌게 공부하신다니 제가 다 기분이 좋네요^^ 감사합니다!
2020.12.24
좋은 강의 잘 보고 있습니다! 대댓글로 달아주신 답변들을 쭉 정독하는 것도 참 도움이 많이 되네요
2020.12.24
    <%- include('../partials/head') %> 와     <%- include('../partials/nav') %> 의 역할은 render(페이지를 동적으로) 외의 부분을 각 경로에서 가져와서 정적으로 표시하는 역할인가요?
I
Ian H 2020.12.28
@규,
include 또한 오브젝트를 전달하여 동적으로 페이지를 생성합니다. 그리고 include 되는 페이지들 역시 ejs파일이므로 render가 되어야 합니다. 
이주형 2021.09.29
안녕하세요, db에서 불러온 값들을 어떤 방식으로 정렬하는지가 궁금합니다. 저는 사용하신 부트스트랩 말고 table class를 사용했는데요, 여기서 가나다 순이나 전화번호 숫자 오름차 순 등으로 주소록을 정렬시키고 싶은데, 이게 models의 Contact.js에서 함수를 추가해줘서 해야할지, route의 contacts.js에서 건드려줘야하는건지 어렵습니다
I
Ian H 2021.09.29
@이주형,
안녕하세요^^
DB에서 찾은 결과를 이름순으로 정렬하려면 contacts.js의 코드를 변경하시면 됩니다.
<변경 전> app.get('/contacts', function(req, res){   Contact.find({}, function(err, contacts){     if(err) return res.json(err);     res.render('contacts/index', {contacts:contacts});   }); });
<변경 후> app.get('/contacts', function(req, res){   Contact.find({})     .sort({name:1})     .exec(function(err, contacts){       if(err) return res.json(err);       res.render('contacts/index', {contacts:contacts});     }); });
이것과 관련된 설명은 https://www.a-mean-blog.com/ko/blog/Node-JS-첫걸음/게시판-만들기/게시판-회원가입 의 routes/users.js 코드 설명 부분에서 나옵니다!
댓글쓰기

이 글에 댓글을 다시려면 SNS 계정으로 로그인하세요. 자세히 알아보기

UP