<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Thanh Long Dev]]></title><description><![CDATA[Nơi chia sẻ kiến thức về lập trình và cuộc sống]]></description><link>https://www.thanhlongdev.com/</link><image><url>https://www.thanhlongdev.com/favicon.png</url><title>Thanh Long Dev</title><link>https://www.thanhlongdev.com/</link></image><generator>Ghost 4.48</generator><lastBuildDate>Fri, 08 May 2026 20:46:42 GMT</lastBuildDate><atom:link href="https://www.thanhlongdev.com/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Sử Dụng AI Một Cách Thông Minh Có Trí Tuệ Để Không Bị Phụ Thuộc & Lạm Dụng]]></title><description><![CDATA[<h2 id="t%E1%BA%A1i-sao-n%C3%AAn-s%E1%BB%AD-d%E1%BB%A5ng-ai-th%C3%B4ng-minh-kh%C3%B4ng-ph%E1%BB%A5-thu%E1%BB%99c-v%C3%A0-kh%C3%B4ng-l%E1%BA%A1m-d%E1%BB%A5ng">T&#x1EA1;i sao n&#xEA;n s&#x1EED; d&#x1EE5;ng AI th&#xF4;ng minh, kh&#xF4;ng ph&#x1EE5; thu&#x1ED9;c v&#xE0; kh&#xF4;ng l&#x1EA1;m d&#x1EE5;ng? </h2><p>Kh&#xE1;m ph&#xE1; c&#xE1;ch t&#x1ED1;i &#x1B0;u h&</p>]]></description><link>https://www.thanhlongdev.com/su-dung-ai-thong-minh-co-tri-tue-khong-bi-phu-thuoc-va-lam-dung/</link><guid isPermaLink="false">6905dbd5b48c7700017d08c1</guid><category><![CDATA[Vừa Code Vừa Xàm]]></category><dc:creator><![CDATA[Đặng Thanh Long]]></dc:creator><pubDate>Sat, 01 Nov 2025 10:41:23 GMT</pubDate><media:content url="https://digitalpress.fra1.cdn.digitaloceanspaces.com/4tg23ij/2025/11/2025-11-01-17.39.23.jpg" medium="image"/><content:encoded><![CDATA[<h2 id="t%E1%BA%A1i-sao-n%C3%AAn-s%E1%BB%AD-d%E1%BB%A5ng-ai-th%C3%B4ng-minh-kh%C3%B4ng-ph%E1%BB%A5-thu%E1%BB%99c-v%C3%A0-kh%C3%B4ng-l%E1%BA%A1m-d%E1%BB%A5ng">T&#x1EA1;i sao n&#xEA;n s&#x1EED; d&#x1EE5;ng AI th&#xF4;ng minh, kh&#xF4;ng ph&#x1EE5; thu&#x1ED9;c v&#xE0; kh&#xF4;ng l&#x1EA1;m d&#x1EE5;ng? </h2><img src="https://digitalpress.fra1.cdn.digitaloceanspaces.com/4tg23ij/2025/11/2025-11-01-17.39.23.jpg" alt="S&#x1EED; D&#x1EE5;ng AI M&#x1ED9;t C&#xE1;ch Th&#xF4;ng Minh C&#xF3; Tr&#xED; Tu&#x1EC7; &#x110;&#x1EC3; Kh&#xF4;ng B&#x1ECB; Ph&#x1EE5; Thu&#x1ED9;c &amp; L&#x1EA1;m D&#x1EE5;ng"><p>Kh&#xE1;m ph&#xE1; c&#xE1;ch t&#x1ED1;i &#x1B0;u h&#xF3;a tr&#x1EA3;i nghi&#x1EC7;m AI v&#x1EDB;i c&#xE1;c t&#xED;nh n&#x103;ng th&#xF4;ng minh.<br></p><p><strong>S&#x1EED; d&#x1EE5;ng AI th&#xF4;ng minh</strong> kh&#xF4;ng ch&#x1EC9; l&#xE0; xu h&#x1B0;&#x1EDB;ng m&#xE0; c&#xF2;n l&#xE0; b&#x1B0;&#x1EDB;c ti&#x1EBF;n c&#x1EA7;n thi&#x1EBF;t trong th&#x1EBF; k&#x1EF7; 21. AI gi&#xFA;p t&#x1ED1;i &#x1B0;u h&#xF3;a c&#xF4;ng vi&#x1EC7;c, t&#x1EEB; qu&#x1EA3;n l&#xFD; th&#x1EDD;i gian &#x111;&#x1EBF;n h&#x1ED7; tr&#x1EE3; h&#x1ECD;c t&#x1EAD;p v&#xE0; l&#xE0;m vi&#x1EC7;c. Tuy nhi&#xEA;n, vi&#x1EC7;c s&#x1EED; d&#x1EE5;ng AI c&#x1EA7;n m&#x1ED9;t c&#xE1;ch th&#xF4;ng minh &#x111;&#x1EC3; tr&#xE1;nh ph&#x1EE5; thu&#x1ED9;c v&#xE0; l&#x1EA1;m d&#x1EE5;ng. Trong b&#xE0;i vi&#x1EBF;t n&#xE0;y, ch&#xFA;ng ta s&#x1EBD; kh&#xE1;m ph&#xE1; c&#xE1;ch t&#x1EAD;n d&#x1EE5;ng AI m&#x1ED9;t c&#xE1;ch hi&#x1EC7;u qu&#x1EA3; m&#xE0; kh&#xF4;ng l&#xE0;m m&#x1EA5;t &#x111;i kh&#x1EA3; n&#x103;ng t&#x1B0; duy v&#xE0; s&#xE1;ng t&#x1EA1;o c&#x1EE7;a con ng&#x1B0;&#x1EDD;i.</p><h2 id="1-ai-l%C3%A0-g%C3%AC-t%E1%BA%A1i-sao-c%E1%BA%A7n-s%E1%BB%AD-d%E1%BB%A5ng-ai-th%C3%B4ng-minh">1. AI l&#xE0; g&#xEC;? T&#x1EA1;i sao c&#x1EA7;n s&#x1EED; d&#x1EE5;ng AI th&#xF4;ng minh?</h2><p><strong>S&#x1EED; d&#x1EE5;ng AI th&#xF4;ng minh</strong> kh&#xF4;ng ch&#x1EC9; l&#xE0; m&#x1ED9;t xu h&#x1B0;&#x1EDB;ng m&#xE0; c&#xF2;n l&#xE0; m&#x1ED9;t b&#x1B0;&#x1EDB;c ti&#x1EBF;n c&#x1EA7;n thi&#x1EBF;t trong th&#x1EBF; k&#x1EF7; 21. AI (Tr&#xED; tu&#x1EC7; nh&#xE2;n t&#x1EA1;o) l&#xE0; c&#xF4;ng ngh&#x1EC7; m&#xF4; ph&#x1ECF;ng kh&#x1EA3; n&#x103;ng t&#x1B0; duy v&#xE0; h&#x1ECD;c h&#x1ECF;i c&#x1EE7;a con ng&#x1B0;&#x1EDD;i, gi&#xFA;p m&#xE1;y t&#xED;nh th&#x1EF1;c hi&#x1EC7;n c&#xE1;c t&#xE1;c v&#x1EE5; ph&#x1EE9;c t&#x1EA1;p. Khi s&#x1EED; d&#x1EE5;ng AI m&#x1ED9;t c&#xE1;ch th&#xF4;ng minh, ch&#xFA;ng ta kh&#xF4;ng ch&#x1EC9; t&#x1ED1;i &#x1B0;u h&#xF3;a c&#xF4;ng vi&#x1EC7;c m&#xE0; c&#xF2;n ph&#xE1;t tri&#x1EC3;n kh&#x1EA3; n&#x103;ng t&#x1B0; duy v&#xE0; s&#xE1;ng t&#x1EA1;o c&#x1EE7;a ch&#xED;nh m&#xEC;nh.</p><p>AI c&#xF3; th&#x1EC3; gi&#xFA;p ch&#xFA;ng ta trong nhi&#x1EC1;u l&#x129;nh v&#x1EF1;c nh&#x1B0;:</p><ul><li>Qu&#x1EA3;n l&#xFD; th&#x1EDD;i gian: AI gi&#xFA;p l&#xEA;n k&#x1EBF; ho&#x1EA1;ch c&#xF4;ng vi&#x1EC7;c hi&#x1EC7;u qu&#x1EA3;, s&#x1EAF;p x&#x1EBF;p th&#x1EDD;i gian v&#xE0; &#x1B0;u ti&#xEA;n c&#xE1;c nhi&#x1EC7;m v&#x1EE5; quan tr&#x1ECD;ng.</li><li>H&#x1ED7; tr&#x1EE3; h&#x1ECD;c t&#x1EAD;p: AI cung c&#x1EA5;p c&#xE1;c c&#xF4;ng c&#x1EE5; h&#x1ECD;c t&#x1EAD;p c&#xE1; nh&#xE2;n h&#xF3;a, gi&#xFA;p h&#x1ECD;c sinh v&#xE0; sinh vi&#xEA;n n&#x1EAF;m b&#x1EAF;t ki&#x1EBF;n th&#x1EE9;c nhanh ch&#xF3;ng v&#xE0; hi&#x1EC7;u qu&#x1EA3;.</li><li>T&#x1ED1;i &#x1B0;u h&#xF3;a l&#xE0;m vi&#x1EC7;c: AI t&#x1EF1; &#x111;&#x1ED9;ng h&#xF3;a c&#xE1;c quy tr&#xEC;nh, gi&#xFA;p t&#x103;ng n&#x103;ng su&#x1EA5;t v&#xE0; gi&#x1EA3;m thi&#x1EC3;u sai s&#xF3;t trong c&#xF4;ng vi&#x1EC7;c.</li></ul><h2 id="2-t%E1%BA%A1i-sao-n%C3%AAn-s%E1%BB%AD-d%E1%BB%A5ng-ai-th%C3%B4ng-minh-kh%C3%B4ng-ph%E1%BB%A5-thu%E1%BB%99c-v%C3%A0-kh%C3%B4ng-l%E1%BA%A1m-d%E1%BB%A5ng">2. T&#x1EA1;i sao n&#xEA;n s&#x1EED; d&#x1EE5;ng AI th&#xF4;ng minh, kh&#xF4;ng ph&#x1EE5; thu&#x1ED9;c v&#xE0; kh&#xF4;ng l&#x1EA1;m d&#x1EE5;ng?</h2><p><strong>S&#x1EED; d&#x1EE5;ng AI th&#xF4;ng minh</strong> kh&#xF4;ng ch&#x1EC9; gi&#xFA;p t&#x1ED1;i &#x1B0;u h&#xF3;a c&#xF4;ng vi&#x1EC7;c m&#xE0; c&#xF2;n gi&#xFA;p ch&#xFA;ng ta ph&#xE1;t tri&#x1EC3;n t&#x1B0; duy v&#xE0; kh&#x1EA3; n&#x103;ng s&#xE1;ng t&#x1EA1;o. Tuy nhi&#xEA;n, n&#x1EBF;u s&#x1EED; d&#x1EE5;ng AI m&#x1ED9;t c&#xE1;ch ph&#x1EE5; thu&#x1ED9;c v&#xE0; l&#x1EA1;m d&#x1EE5;ng, ch&#xFA;ng ta c&#xF3; th&#x1EC3; m&#x1EA5;t &#x111;i kh&#x1EA3; n&#x103;ng t&#x1B0; duy &#x111;&#x1ED9;c l&#x1EAD;p v&#xE0; s&#xE1;ng t&#x1EA1;o. D&#x1B0;&#x1EDB;i &#x111;&#xE2;y l&#xE0; m&#x1ED9;t s&#x1ED1; l&#xFD; do t&#x1EA1;i sao n&#xEA;n s&#x1EED; d&#x1EE5;ng AI m&#x1ED9;t c&#xE1;ch th&#xF4;ng minh:</p><h3 id="21-ai-gi%C3%BAp-t%E1%BB%91i-%C6%B0u-h%C3%B3a-c%C3%B4ng-vi%E1%BB%87c">2.1. AI gi&#xFA;p t&#x1ED1;i &#x1B0;u h&#xF3;a c&#xF4;ng vi&#x1EC7;c</h3><p><strong>S&#x1EED; d&#x1EE5;ng AI th&#xF4;ng minh</strong> gi&#xFA;p t&#x1ED1;i &#x1B0;u h&#xF3;a c&#xF4;ng vi&#x1EC7;c m&#x1ED9;t c&#xE1;ch hi&#x1EC7;u qu&#x1EA3;. AI c&#xF3; th&#x1EC3; t&#x1EF1; &#x111;&#x1ED9;ng h&#xF3;a c&#xE1;c quy tr&#xEC;nh, gi&#xFA;p gi&#x1EA3;m thi&#x1EC3;u th&#x1EDD;i gian v&#xE0; c&#xF4;ng s&#x1EE9;c c&#x1EA7;n thi&#x1EBF;t cho c&#xE1;c nhi&#x1EC7;m v&#x1EE5; l&#x1EB7;p &#x111;i l&#x1EB7;p l&#x1EA1;i. &#x110;i&#x1EC1;u n&#xE0;y kh&#xF4;ng ch&#x1EC9; gi&#xFA;p t&#x103;ng n&#x103;ng su&#x1EA5;t m&#xE0; c&#xF2;n gi&#x1EA3;m thi&#x1EC3;u sai s&#xF3;t trong c&#xF4;ng vi&#x1EC7;c.</p><h3 id="22-ai-h%E1%BB%97-tr%E1%BB%A3-h%E1%BB%8Dc-t%E1%BA%ADp-v%C3%A0-ph%C3%A1t-tri%E1%BB%83n-c%C3%A1-nh%C3%A2n">2.2. AI h&#x1ED7; tr&#x1EE3; h&#x1ECD;c t&#x1EAD;p v&#xE0; ph&#xE1;t tri&#x1EC3;n c&#xE1; nh&#xE2;n</h3><p>AI cung c&#x1EA5;p c&#xE1;c c&#xF4;ng c&#x1EE5; h&#x1ECD;c t&#x1EAD;p c&#xE1; nh&#xE2;n h&#xF3;a, gi&#xFA;p h&#x1ECD;c sinh v&#xE0; sinh vi&#xEA;n n&#x1EAF;m b&#x1EAF;t ki&#x1EBF;n th&#x1EE9;c nhanh ch&#xF3;ng v&#xE0; hi&#x1EC7;u qu&#x1EA3;. Vi&#x1EC7;c s&#x1EED; d&#x1EE5;ng AI th&#xF4;ng minh kh&#xF4;ng ch&#x1EC9; gi&#xFA;p h&#x1ECD;c t&#x1EAD;p m&#xE0; c&#xF2;n gi&#xFA;p ph&#xE1;t tri&#x1EC3;n k&#x1EF9; n&#x103;ng t&#x1B0; duy v&#xE0; gi&#x1EA3;i quy&#x1EBF;t v&#x1EA5;n &#x111;&#x1EC1;.</p><h3 id="23-ai-gi%C3%BAp-t%C4%83ng-kh%E1%BA%A3-n%C4%83ng-s%C3%A1ng-t%E1%BA%A1o">2.3. AI gi&#xFA;p t&#x103;ng kh&#x1EA3; n&#x103;ng s&#xE1;ng t&#x1EA1;o</h3><p>Thay v&#xEC; ph&#x1EE5; thu&#x1ED9;c v&#xE0;o AI &#x111;&#x1EC3; th&#x1EF1;c hi&#x1EC7;n t&#x1EA5;t c&#x1EA3; c&#xE1;c c&#xF4;ng vi&#x1EC7;c, ch&#xFA;ng ta n&#xEA;n s&#x1EED; d&#x1EE5;ng AI nh&#x1B0; m&#x1ED9;t c&#xF4;ng c&#x1EE5; h&#x1ED7; tr&#x1EE3; &#x111;&#x1EC3; t&#x103;ng c&#x1B0;&#x1EDD;ng kh&#x1EA3; n&#x103;ng s&#xE1;ng t&#x1EA1;o. AI c&#xF3; th&#x1EC3; gi&#xFA;p ch&#xFA;ng ta kh&#xE1;m ph&#xE1; c&#xE1;c &#xFD; t&#x1B0;&#x1EDF;ng m&#x1EDB;i, nh&#x1B0;ng cu&#x1ED1;i c&#xF9;ng, vi&#x1EC7;c th&#x1EF1;c hi&#x1EC7;n v&#xE0; ph&#xE1;t tri&#x1EC3;n &#xFD; t&#x1B0;&#x1EDF;ng &#x111;&#xF3; v&#x1EAB;n ph&#x1EE5; thu&#x1ED9;c v&#xE0;o con ng&#x1B0;&#x1EDD;i.</p><h2 id="3-c%C3%A1ch-s%E1%BB%AD-d%E1%BB%A5ng-ai-th%C3%B4ng-minh-kh%C3%B4ng-ph%E1%BB%A5-thu%E1%BB%99c-v%C3%A0-kh%C3%B4ng-l%E1%BA%A1m-d%E1%BB%A5ng">3. C&#xE1;ch s&#x1EED; d&#x1EE5;ng AI th&#xF4;ng minh, kh&#xF4;ng ph&#x1EE5; thu&#x1ED9;c v&#xE0; kh&#xF4;ng l&#x1EA1;m d&#x1EE5;ng</h2><p><strong>S&#x1EED; d&#x1EE5;ng AI th&#xF4;ng minh</strong> l&#xE0; m&#x1ED9;t b&#x1B0;&#x1EDB;c ti&#x1EBF;n c&#x1EA7;n thi&#x1EBF;t trong th&#x1EBF; k&#x1EF7; 21. Tuy nhi&#xEA;n, &#x111;&#x1EC3; t&#x1EAD;n d&#x1EE5;ng t&#x1ED1;i &#x111;a l&#x1EE3;i &#xED;ch c&#x1EE7;a AI, ch&#xFA;ng ta c&#x1EA7;n s&#x1EED; d&#x1EE5;ng n&#xF3; m&#x1ED9;t c&#xE1;ch th&#xF4;ng minh, kh&#xF4;ng ph&#x1EE5; thu&#x1ED9;c v&#xE0; kh&#xF4;ng l&#x1EA1;m d&#x1EE5;ng. D&#x1B0;&#x1EDB;i &#x111;&#xE2;y l&#xE0; m&#x1ED9;t s&#x1ED1; c&#xE1;ch &#x111;&#x1EC3; s&#x1EED; d&#x1EE5;ng AI m&#x1ED9;t c&#xE1;ch hi&#x1EC7;u qu&#x1EA3;:</p><h3 id="31-s%E1%BB%AD-d%E1%BB%A5ng-ai-nh%C6%B0-c%C3%B4ng-c%E1%BB%A5-h%E1%BB%97-tr%E1%BB%A3-kh%C3%B4ng-ph%E1%BA%A3i-thay-th%E1%BA%BF">3.1. S&#x1EED; d&#x1EE5;ng AI nh&#x1B0; c&#xF4;ng c&#x1EE5; h&#x1ED7; tr&#x1EE3;, kh&#xF4;ng ph&#x1EA3;i thay th&#x1EBF;</h3><p>AI l&#xE0; m&#x1ED9;t c&#xF4;ng c&#x1EE5; h&#x1ED7; tr&#x1EE3;, gi&#xFA;p ch&#xFA;ng ta th&#x1EF1;c hi&#x1EC7;n c&#xE1;c c&#xF4;ng vi&#x1EC7;c m&#x1ED9;t c&#xE1;ch hi&#x1EC7;u qu&#x1EA3;. Thay v&#xEC; ph&#x1EE5; thu&#x1ED9;c ho&#xE0;n to&#xE0;n v&#xE0;o AI, ch&#xFA;ng ta n&#xEA;n s&#x1EED; d&#x1EE5;ng n&#xF3; nh&#x1B0; m&#x1ED9;t c&#xF4;ng c&#x1EE5; &#x111;&#x1EC3; t&#x103;ng c&#x1B0;&#x1EDD;ng kh&#x1EA3; n&#x103;ng t&#x1B0; duy v&#xE0; s&#xE1;ng t&#x1EA1;o c&#x1EE7;a ch&#xED;nh m&#xEC;nh.</p><h3 id="32-h%E1%BB%8Dc-c%C3%A1ch-s%E1%BB%AD-d%E1%BB%A5ng-ai-%C4%91%E1%BB%83-ph%C3%A1t-tri%E1%BB%83n-b%E1%BA%A3n-th%C3%A2n">3.2. H&#x1ECD;c c&#xE1;ch s&#x1EED; d&#x1EE5;ng AI &#x111;&#x1EC3; ph&#xE1;t tri&#x1EC3;n b&#x1EA3;n th&#xE2;n</h3><p>Thay v&#xEC; s&#x1EED; d&#x1EE5;ng AI &#x111;&#x1EC3; th&#x1EF1;c hi&#x1EC7;n t&#x1EA5;t c&#x1EA3; c&#xE1;c c&#xF4;ng vi&#x1EC7;c, ch&#xFA;ng ta n&#xEA;n s&#x1EED; d&#x1EE5;ng n&#xF3; &#x111;&#x1EC3; h&#x1ECD;c h&#x1ECF;i v&#xE0; ph&#xE1;t tri&#x1EC3;n b&#x1EA3;n th&#xE2;n. AI c&#xF3; th&#x1EC3; cung c&#x1EA5;p th&#xF4;ng tin v&#xE0; g&#x1EE3;i &#xFD;, nh&#x1B0;ng cu&#x1ED1;i c&#xF9;ng, vi&#x1EC7;c quy&#x1EBF;t &#x111;&#x1ECB;nh v&#xE0; th&#x1EF1;c hi&#x1EC7;n v&#x1EAB;n ph&#x1EE5; thu&#x1ED9;c v&#xE0;o con ng&#x1B0;&#x1EDD;i.</p><h3 id="33-%C4%91%E1%BA%B7t-gi%E1%BB%9Bi-h%E1%BA%A1n-s%E1%BB%AD-d%E1%BB%A5ng-ai">3.3. &#x110;&#x1EB7;t gi&#x1EDB;i h&#x1EA1;n s&#x1EED; d&#x1EE5;ng AI</h3><p>&#x110;&#x1EC3; tr&#xE1;nh l&#x1EA1;m d&#x1EE5;ng AI, ch&#xFA;ng ta n&#xEA;n &#x111;&#x1EB7;t gi&#x1EDB;i h&#x1EA1;n v&#x1EC1; th&#x1EDD;i gian s&#x1EED; d&#x1EE5;ng AI m&#x1ED7;i ng&#xE0;y. &#x110;i&#x1EC1;u n&#xE0;y kh&#xF4;ng ch&#x1EC9; gi&#xFA;p ch&#xFA;ng ta tr&#xE1;nh ph&#x1EE5; thu&#x1ED9;c m&#xE0; c&#xF2;n gi&#xFA;p ch&#xFA;ng ta duy tr&#xEC; kh&#x1EA3; n&#x103;ng t&#x1B0; duy &#x111;&#x1ED9;c l&#x1EAD;p v&#xE0; s&#xE1;ng t&#x1EA1;o.</p><h2 id="4-ai-th%C3%B4ng-minh-c%C3%B3-th%E1%BB%83-l%C3%A0m-g%C3%AC-cho-b%E1%BA%A1n">4. AI th&#xF4;ng minh c&#xF3; th&#x1EC3; l&#xE0;m g&#xEC; cho b&#x1EA1;n?</h2><p><strong>S&#x1EED; d&#x1EE5;ng AI th&#xF4;ng minh</strong> gi&#xFA;p ch&#xFA;ng ta t&#x1ED1;i &#x1B0;u h&#xF3;a c&#xF4;ng vi&#x1EC7;c, h&#x1ECD;c t&#x1EAD;p v&#xE0; ph&#xE1;t tri&#x1EC3;n b&#x1EA3;n th&#xE2;n. AI c&#xF3; th&#x1EC3; l&#xE0;m g&#xEC; cho b&#x1EA1;n? D&#x1B0;&#x1EDB;i &#x111;&#xE2;y l&#xE0; m&#x1ED9;t s&#x1ED1; c&#xE1;ch AI c&#xF3; th&#x1EC3; h&#x1ED7; tr&#x1EE3; b&#x1EA1;n trong cu&#x1ED9;c s&#x1ED1;ng h&#xE0;ng ng&#xE0;y:</p><ul><li>Qu&#x1EA3;n l&#xFD; th&#x1EDD;i gian: AI gi&#xFA;p l&#xEA;n k&#x1EBF; ho&#x1EA1;ch c&#xF4;ng vi&#x1EC7;c hi&#x1EC7;u qu&#x1EA3;, s&#x1EAF;p x&#x1EBF;p th&#x1EDD;i gian v&#xE0; &#x1B0;u ti&#xEA;n c&#xE1;c nhi&#x1EC7;m v&#x1EE5; quan tr&#x1ECD;ng.</li><li>H&#x1ED7; tr&#x1EE3; h&#x1ECD;c t&#x1EAD;p: AI cung c&#x1EA5;p c&#xE1;c c&#xF4;ng c&#x1EE5; h&#x1ECD;c t&#x1EAD;p c&#xE1; nh&#xE2;n h&#xF3;a, gi&#xFA;p h&#x1ECD;c sinh v&#xE0; sinh vi&#xEA;n n&#x1EAF;m b&#x1EAF;t ki&#x1EBF;n th&#x1EE9;c nhanh ch&#xF3;ng v&#xE0; hi&#x1EC7;u qu&#x1EA3;.</li><li>T&#x1ED1;i &#x1B0;u h&#xF3;a l&#xE0;m vi&#x1EC7;c: AI t&#x1EF1; &#x111;&#x1ED9;ng h&#xF3;a c&#xE1;c quy tr&#xEC;nh, gi&#xFA;p t&#x103;ng n&#x103;ng su&#x1EA5;t v&#xE0; gi&#x1EA3;m thi&#x1EC3;u sai s&#xF3;t trong c&#xF4;ng vi&#x1EC7;c.</li></ul><p>&#x110;&#x1EC3; s&#x1EED; d&#x1EE5;ng AI m&#x1ED9;t c&#xE1;ch hi&#x1EC7;u qu&#x1EA3;, ch&#xFA;ng ta c&#x1EA7;n hi&#x1EC3;u r&#xF5; v&#x1EC1; AI v&#xE0; c&#xE1;ch n&#xF3; ho&#x1EA1;t &#x111;&#x1ED9;ng. AI kh&#xF4;ng ph&#x1EA3;i l&#xE0; m&#x1ED9;t c&#xF4;ng c&#x1EE5; ho&#xE0;n h&#x1EA3;o, nh&#x1B0;ng n&#xF3; c&#xF3; th&#x1EC3; gi&#xFA;p ch&#xFA;ng ta th&#x1EF1;c hi&#x1EC7;n c&#xE1;c c&#xF4;ng vi&#x1EC7;c m&#x1ED9;t c&#xE1;ch nhanh ch&#xF3;ng v&#xE0; hi&#x1EC7;u qu&#x1EA3; h&#x1A1;n. Tuy nhi&#xEA;n, &#x111;&#x1EC3; tr&#xE1;nh ph&#x1EE5; thu&#x1ED9;c v&#xE0; l&#x1EA1;m d&#x1EE5;ng AI, ch&#xFA;ng ta c&#x1EA7;n s&#x1EED; d&#x1EE5;ng n&#xF3; m&#x1ED9;t c&#xE1;ch th&#xF4;ng minh.</p><h2 id="5-t%E1%BA%A1i-sao-n%C3%AAn-s%E1%BB%AD-d%E1%BB%A5ng-ai-th%C3%B4ng-minh">5. T&#x1EA1;i sao n&#xEA;n s&#x1EED; d&#x1EE5;ng AI th&#xF4;ng minh?</h2><p><strong>S&#x1EED; d&#x1EE5;ng AI th&#xF4;ng minh</strong> l&#xE0; m&#x1ED9;t b&#x1B0;&#x1EDB;c ti&#x1EBF;n c&#x1EA7;n thi&#x1EBF;t trong th&#x1EBF; k&#x1EF7; 21. AI kh&#xF4;ng ch&#x1EC9; gi&#xFA;p t&#x1ED1;i &#x1B0;u h&#xF3;a c&#xF4;ng vi&#x1EC7;c m&#xE0; c&#xF2;n gi&#xFA;p ch&#xFA;ng ta ph&#xE1;t tri&#x1EC3;n kh&#x1EA3; n&#x103;ng t&#x1B0; duy v&#xE0; s&#xE1;ng t&#x1EA1;o. Tuy nhi&#xEA;n, &#x111;&#x1EC3; t&#x1EAD;n d&#x1EE5;ng t&#x1ED1;i &#x111;a l&#x1EE3;i &#xED;ch c&#x1EE7;a AI, ch&#xFA;ng ta c&#x1EA7;n s&#x1EED; d&#x1EE5;ng n&#xF3; m&#x1ED9;t c&#xE1;ch th&#xF4;ng minh, kh&#xF4;ng ph&#x1EE5; thu&#x1ED9;c v&#xE0; kh&#xF4;ng l&#x1EA1;m d&#x1EE5;ng. &#x110;i&#x1EC1;u n&#xE0;y kh&#xF4;ng ch&#x1EC9; gi&#xFA;p ch&#xFA;ng ta ti&#x1EBF;t ki&#x1EC7;m th&#x1EDD;i gian v&#xE0; c&#xF4;ng s&#x1EE9;c m&#xE0; c&#xF2;n gi&#xFA;p ch&#xFA;ng ta ph&#xE1;t tri&#x1EC3;n b&#x1EA3;n th&#xE2;n v&#xE0; h&#x1ECD;c h&#x1ECF;i th&#xEA;m nhi&#x1EC1;u &#x111;i&#x1EC1;u m&#x1EDB;i.</p><p>Khi s&#x1EED; d&#x1EE5;ng AI m&#x1ED9;t c&#xE1;ch th&#xF4;ng minh, ch&#xFA;ng ta kh&#xF4;ng ch&#x1EC9; c&#xF3; th&#x1EC3; t&#x1ED1;i &#x1B0;u h&#xF3;a c&#xF4;ng vi&#x1EC7;c m&#xE0; c&#xF2;n c&#xF3; th&#x1EC3; ph&#xE1;t tri&#x1EC3;n kh&#x1EA3; n&#x103;ng t&#x1B0; duy v&#xE0; s&#xE1;ng t&#x1EA1;o c&#x1EE7;a ch&#xED;nh m&#xEC;nh. AI l&#xE0; m&#x1ED9;t c&#xF4;ng c&#x1EE5; h&#x1ED7; tr&#x1EE3;, gi&#xFA;p ch&#xFA;ng ta th&#x1EF1;c hi&#x1EC7;n c&#xE1;c c&#xF4;ng vi&#x1EC7;c m&#x1ED9;t c&#xE1;ch hi&#x1EC7;u qu&#x1EA3;. Tuy nhi&#xEA;n, &#x111;&#x1EC3; tr&#xE1;nh ph&#x1EE5; thu&#x1ED9;c v&#xE0; l&#x1EA1;m d&#x1EE5;ng AI, ch&#xFA;ng ta c&#x1EA7;n s&#x1EED; d&#x1EE5;ng n&#xF3; m&#x1ED9;t c&#xE1;ch th&#xF4;ng minh.</p><p>Tr&#xEA;n &#x111;&#xE2;y l&#xE0; b&#xE0;i vi&#x1EBF;t v&#x1EC1; <strong>s&#x1EED; d&#x1EE5;ng AI th&#xF4;ng minh</strong> kh&#xF4;ng ph&#x1EE5; thu&#x1ED9;c v&#xE0; kh&#xF4;ng l&#x1EA1;m d&#x1EE5;ng. N&#x1EBF;u b&#x1EA1;n &#x111;ang t&#xEC;m ki&#x1EBF;m m&#x1ED9;t c&#xE1;ch &#x111;&#x1EC3; t&#x1ED1;i &#x1B0;u h&#xF3;a c&#xF4;ng vi&#x1EC7;c v&#xE0; ph&#xE1;t tri&#x1EC3;n b&#x1EA3;n th&#xE2;n, th&#xEC; vi&#x1EC7;c s&#x1EED; d&#x1EE5;ng AI m&#x1ED9;t c&#xE1;ch th&#xF4;ng minh l&#xE0; m&#x1ED9;t l&#x1EF1;a ch&#x1ECD;n tuy&#x1EC7;t v&#x1EDD;i. H&#xE3;y b&#x1EAF;t &#x111;&#x1EA7;u s&#x1EED; d&#x1EE5;ng AI ngay h&#xF4;m nay &#x111;&#x1EC3; t&#x1EAD;n h&#x1B0;&#x1EDF;ng nh&#x1EEF;ng l&#x1EE3;i &#xED;ch m&#xE0; n&#xF3; mang l&#x1EA1;i.</p><p><strong>S&#x1EED; d&#x1EE5;ng AI th&#xF4;ng minh</strong> kh&#xF4;ng ch&#x1EC9; gi&#xFA;p t&#x1ED1;i &#x1B0;u h&#xF3;a c&#xF4;ng vi&#x1EC7;c m&#xE0; c&#xF2;n gi&#xFA;p ch&#xFA;ng ta ph&#xE1;t tri&#x1EC3;n kh&#x1EA3; n&#x103;ng t&#x1B0; duy v&#xE0; s&#xE1;ng t&#x1EA1;o. AI l&#xE0; m&#x1ED9;t c&#xF4;ng c&#x1EE5; h&#x1ED7; tr&#x1EE3;, gi&#xFA;p ch&#xFA;ng ta th&#x1EF1;c hi&#x1EC7;n c&#xE1;c c&#xF4;ng vi&#x1EC7;c m&#x1ED9;t c&#xE1;ch hi&#x1EC7;u qu&#x1EA3;. Tuy nhi&#xEA;n, &#x111;&#x1EC3; tr&#xE1;nh ph&#x1EE5; thu&#x1ED9;c v&#xE0; l&#x1EA1;m d&#x1EE5;ng AI, ch&#xFA;ng ta c&#x1EA7;n s&#x1EED; d&#x1EE5;ng n&#xF3; m&#x1ED9;t c&#xE1;ch th&#xF4;ng minh. H&#xE3;y b&#x1EAF;t &#x111;&#x1EA7;u s&#x1EED; d&#x1EE5;ng AI ngay h&#xF4;m nay &#x111;&#x1EC3; t&#x1EAD;n h&#x1B0;&#x1EDF;ng nh&#x1EEF;ng l&#x1EE3;i &#xED;ch m&#xE0; n&#xF3; mang l&#x1EA1;i.</p><p>Nh&#x1B0; v&#x1EAD;y, b&#xE0;i vi&#x1EBF;t &#x111;&#xE3; cung c&#x1EA5;p cho b&#x1EA1;n nh&#x1EEF;ng th&#xF4;ng tin chi ti&#x1EBF;t v&#x1EC1; <strong>s&#x1EED; d&#x1EE5;ng AI th&#xF4;ng minh</strong> kh&#xF4;ng ph&#x1EE5; thu&#x1ED9;c v&#xE0; kh&#xF4;ng l&#x1EA1;m d&#x1EE5;ng. Hy v&#x1ECD;ng r&#x1EB1;ng, th&#xF4;ng qua b&#xE0;i vi&#x1EBF;t n&#xE0;y, b&#x1EA1;n &#x111;&#xE3; c&#xF3; th&#xEA;m nh&#x1EEF;ng hi&#x1EC3;u bi&#x1EBF;t v&#x1EC1; AI v&#xE0; c&#xE1;ch s&#x1EED; d&#x1EE5;ng n&#xF3; m&#x1ED9;t c&#xE1;ch hi&#x1EC7;u qu&#x1EA3;.</p><p>C&#x1EA3;m &#x1A1;n b&#x1EA1;n &#x111;&#xE3; theo d&#xF5;i b&#xE0;i vi&#x1EBF;t c&#x1EE7;a ch&#xFA;ng t&#xF4;i. N&#x1EBF;u b&#x1EA1;n c&#xF3; b&#x1EA5;t k&#x1EF3; c&#xE2;u h&#x1ECF;i n&#xE0;o v&#x1EC1; AI ho&#x1EB7;c mu&#x1ED1;n t&#xEC;m hi&#x1EC3;u th&#xEA;m v&#x1EC1; c&#xE1;ch s&#x1EED; d&#x1EE5;ng AI m&#x1ED9;t c&#xE1;ch th&#xF4;ng minh, h&#xE3;y &#x111;&#x1EC3; l&#x1EA1;i b&#xEC;nh lu&#x1EAD;n d&#x1B0;&#x1EDB;i &#x111;&#xE2;y. Ch&#xFA;c b&#x1EA1;n th&#xE0;nh c&#xF4;ng trong vi&#x1EC7;c s&#x1EED; d&#x1EE5;ng AI v&#xE0; t&#x1EAD;n h&#x1B0;&#x1EDF;ng nh&#x1EEF;ng l&#x1EE3;i &#xED;ch m&#xE0; n&#xF3; mang l&#x1EA1;i!</p><!--kg-card-begin: html--><iframe src="https://www.facebook.com/plugins/like.php?href=https%3A%2F%2Fwww.thanhlongdev.com%2Fsu-dung-ai-thong-minh-co-tri-tue-khong-bi-phu-thuoc-va-lam-dung%2F&amp;width=450&amp;layout=standard&amp;action=like&amp;size=large&amp;share=true&amp;height=35&amp;appId=2794898430534168" width="450" height="35" style="border:none;overflow:hidden" scrolling="no" frameborder="0" allowtransparency="true" allow="encrypted-media"></iframe><!--kg-card-end: html--><!--kg-card-begin: html--><div class="fb-comments" data-href="https://www.thanhlongdev.com/su-dung-ai-thong-minh-co-tri-tue-khong-bi-phu-thuoc-va-lam-dung/" data-width="100%" data-numposts="10"></div><!--kg-card-end: html-->]]></content:encoded></item><item><title><![CDATA[Xây Dựng App Reminder Pay Với Cron Jobs, Nodemailer Và NodeJS]]></title><description><![CDATA[<!--kg-card-begin: markdown--><h1 id="giithiuchung">Gi&#x1EDB;i Thi&#x1EC7;u Chung</h1>
<p>H&#xF4;m nay m&#xEC;nh s&#x1EBD; h&#x1B0;&#x1EDB;ng d&#x1EAB;n c&#xE1;c b&#x1EA1;n x&#xE2;y d&#x1EF1;ng m&#x1ED9;t &#x1EE9;ng d&#x1EE5;ng nh&#x1EAF;c nh&#x1EDF; v&#x1EDB;</p>]]></description><link>https://www.thanhlongdev.com/xay-dung-app-reminder-pay-voi-cron-job-nodemailer/</link><guid isPermaLink="false">60194c2750d0c40001ccb94d</guid><category><![CDATA[Lập Trình Web]]></category><dc:creator><![CDATA[Đặng Thanh Long]]></dc:creator><pubDate>Tue, 02 Feb 2021 13:37:45 GMT</pubDate><media:content url="https://digitalpress.fra1.cdn.digitaloceanspaces.com/4tg23ij/2021/02/banner-2-1.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h1 id="giithiuchung">Gi&#x1EDB;i Thi&#x1EC7;u Chung</h1>
<img src="https://digitalpress.fra1.cdn.digitaloceanspaces.com/4tg23ij/2021/02/banner-2-1.png" alt="X&#xE2;y D&#x1EF1;ng App Reminder Pay V&#x1EDB;i Cron Jobs, Nodemailer V&#xE0; NodeJS"><p>H&#xF4;m nay m&#xEC;nh s&#x1EBD; h&#x1B0;&#x1EDB;ng d&#x1EAB;n c&#xE1;c b&#x1EA1;n x&#xE2;y d&#x1EF1;ng m&#x1ED9;t &#x1EE9;ng d&#x1EE5;ng nh&#x1EAF;c nh&#x1EDF; v&#x1EDB;i cron jon, nodemailer v&#xE0; express.</p>
<h1 id="mcchcabivit">M&#x1EE5;c &#x110;&#xED;ch C&#x1EE7;a B&#xE0;i Vi&#x1EBF;t</h1>
<p>Th&#xEC; h&#xF4;m nay m&#xEC;nh s&#x1EBD; thay &#x111;&#x1ED5;i m&#x1ED9;t ch&#xFA;t thay v&#xEC; vi&#x1EBF;t m&#x1ED9;t blog &#x111;&#x1EC3; h&#x1B0;&#x1EDB;ng d&#x1EAB;n c&#xE1;c b&#x1EA1;n th&#xEC; b&#xE2;y gi&#x1EDD; m&#xEC;nh s&#x1EBD; quay video &#x111;&#x1EC3; cho c&#xE1;c b&#x1EA1;n hi&#x1EC3;u k&#x129; h&#x1A1;n.<br>
M&#x1EE5;c &#x111;&#xED;ch c&#x1EE7;a m&#xEC;nh l&#xE0; &#x111;&#x1EC3; cho c&#xE1;c b&#x1EA1;n bi&#x1EBF;t cron jobs l&#xE0; g&#xEC;, g&#x1EED;i mail ra l&#xE0;m sao. Tr&#xEA;n cloud heroku th&#xEC; ch&#xFA;ng s&#x1EED; d&#x1EE5;ng g&#xEC; &#x111;&#x1EC3; th&#x1EF1;c hi&#x1EC7;n vi&#x1EC7;c g&#x1EED;i mail.</p>
<p>Cu&#x1ED1;i c&#xF9;ng m&#xEC;nh mong c&#xE1;c b&#x1EA1;n xem c&#xE1;c project th&#x1EAD;t k&#x129;, kh&#xF4;ng l&#x1B0;&#x1EE3;t b&#x1ECF; &lt;3 &lt;3</p>
<h1 id="btuthino">B&#x1EAF;t &#x110;&#x1EA7;u Th&#xF4;i N&#xE0;o</h1>
<h2 id="1thitlpproject">1. Thi&#x1EBF;t L&#x1EAD;p Project</h2>
<iframe width="560" height="315" src="https://www.youtube.com/embed/YE3h4iibsvc?start=1" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
<h2 id="2payindexcreatereminderdeleteroutes">2. Pay Index/Create/Reminder/Delete Routes</h2>
<iframe width="560" height="315" src="https://www.youtube.com/embed/SiRTrsDGhjA?start=426" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
<h2 id="3stylescssproject">3. Styles CSS Project</h2>
<iframe width="560" height="315" src="https://www.youtube.com/embed/zhDC1vXE00U" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
<h2 id="4deployprojectvktthcdn">4. Deploy Project V&#xE0; K&#x1EBF;t Th&#xFA;c D&#x1EF1; &#xC1;n</h2>
<iframe width="560" height="315" src="https://www.youtube.com/embed/dompKM5Jvag?start=420" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
<p><em><strong>Link demo prject cho m&#x1ECD;i ng&#x1B0;&#x1EDD;i m&#xE0; m&#xEC;nh &#x111;&#xE3; deploy l&#xEA;n heroku:</strong></em> <a href="https://reminder-pay.herokuapp.com/">t&#x1EA1;i &#x111;&#xE2;y nha</a><br>
<strong>V&#x1EAD;y l&#xE0; xong r&#x1ED3;i nha &lt;3 &lt;3 &lt;3</strong></p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h1 id="likt">L&#x1EDD;i K&#x1EBF;t</h1>
<p>V&#x1EAD;y l&#xE0; xong b&#xE0;i X&#xE2;y D&#x1EF1;ng App Reminder Pay V&#x1EDB;i Cron Jobs, Nodemailer V&#xE0; NodeJS. M&#xEC;nh mong mu&#x1ED1;n b&#xE0;i n&#xE0;y s&#x1EBD; gi&#xFA;p c&#xE1;c b&#x1EA1;n hi&#x1EC3;u r&#xF5; h&#x1A1;n v&#x1EC1; cron jobs l&#xE0; g&#xEC;, g&#x1EED;i mail b&#x1EB1;ng nodemailer b&#x1EB1;ng c&#xE1;ch n&#xE0;o v&#xE0; cu&#x1ED1;i c&#xF9;ng l&#xE0;m c&#xE1;ch n&#xE0;o &#x111;&#x1EC3; deploy m&#x1ED9;t project l&#xEA;n heroku.<br>
<strong>C&#xE1;c b&#x1EA1;n nh&#x1EDB; like v&#xE0; theo d&#xF5;i fanpage <a href="https://www.facebook.com/thanhlongdev/">Thanh Long Dev</a> &#x111;&#x1EC3; nh&#x1EAD;n nh&#x1EEF;ng th&#xF4;ng b&#xE1;o v&#x1EC1; b&#xE0;i vi&#x1EBF;t m&#x1EDB;i nh&#x1EA5;t nha.</strong><br>
<em><strong>N&#x1EBF;u c&#xE1;c b&#x1EA1;n c&#x1EA3;m th&#x1EA5;y b&#xE0;i vi&#x1EBF;t c&#x1EE7;a m&#xEC;nh hay th&#xEC; c&#xE1;c b&#x1EA1;n c&#xF3; th&#x1EC3; &#x1EE7;ng h&#x1ED9; m&#xEC;nh &#x111;&#x1EC3; m&#xEC;nh c&#xF3; th&#xEA;m &#x111;&#x1ED9;ng l&#x1EF1;c &#x111;&#x1EC3; ra nh&#x1EEF;ng b&#xE0;i topic hay v&#xE0; ch&#x1EA5;t l&#x1B0;&#x1EE3;ng h&#x1A1;n &#x1EE7;ng h&#x1ED9; m&#xEC;nh <a href="https://vrdonate.vn/thanhlongdev">t&#x1EA1;i &#x111;&#xE2;y nha.</a></strong></em><br>
<strong>Ch&#xFA;c C&#xE1;c B&#x1EA1;n Th&#xE0;nh C&#xF4;ng!!</strong></p>
<!--kg-card-end: markdown--><!--kg-card-begin: html--><iframe src="https://www.facebook.com/plugins/like.php?href=https%3A%2F%2Fwww.thanhlongdev.com%2Fxay-dung-app-reminder-pay-voi-cron-job-nodemailer%2F&amp;width=450&amp;layout=standard&amp;action=like&amp;size=large&amp;share=true&amp;height=35&amp;appId=2794898430534168" width="450" height="35" style="border:none;overflow:hidden" scrolling="no" frameborder="0" allowtransparency="true" allow="encrypted-media"></iframe><!--kg-card-end: html--><!--kg-card-begin: html--><div class="fb-comments" data-href="https://www.thanhlongdev.com/xay-dung-app-reminder-pay-voi-cron-job-nodemailer/" data-width="100%" data-numposts="10"></div><!--kg-card-end: html-->]]></content:encoded></item><item><title><![CDATA[Xây Dựng Ứng Dụng Calculator Với Javascript]]></title><description><![CDATA[<!--kg-card-begin: markdown--><h1 id="giithiuchung">Gi&#x1EDB;i Thi&#x1EC7;u Chung</h1>
<p>H&#xF4;m nay m&#xEC;nh s&#x1EBD; h&#x1B0;&#x1EDB;ng d&#x1EAB;n c&#xE1;c b&#x1EA1;n x&#xE2;y d&#x1EF1;ng &#x1EE9;ng d&#x1EE5;ng calculator v&#x1EDB;i html, css v&#xE0; js.<br>
<em>C&</em></p>]]></description><link>https://www.thanhlongdev.com/xay-dung-calculator-with-javascript/</link><guid isPermaLink="false">5f826217ad14b40001ef07e9</guid><category><![CDATA[Lập Trình Web]]></category><dc:creator><![CDATA[Đặng Thanh Long]]></dc:creator><pubDate>Sun, 08 Nov 2020 01:46:32 GMT</pubDate><media:content url="https://digitalpress.fra1.cdn.digitaloceanspaces.com/4tg23ij/2020/11/banner.gif" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h1 id="giithiuchung">Gi&#x1EDB;i Thi&#x1EC7;u Chung</h1>
<img src="https://digitalpress.fra1.cdn.digitaloceanspaces.com/4tg23ij/2020/11/banner.gif" alt="X&#xE2;y D&#x1EF1;ng &#x1EE8;ng D&#x1EE5;ng Calculator V&#x1EDB;i Javascript"><p>H&#xF4;m nay m&#xEC;nh s&#x1EBD; h&#x1B0;&#x1EDB;ng d&#x1EAB;n c&#xE1;c b&#x1EA1;n x&#xE2;y d&#x1EF1;ng &#x1EE9;ng d&#x1EE5;ng calculator v&#x1EDB;i html, css v&#xE0; js.<br>
<em>C&#xE1;c ch&#x1EE9;c n&#x103;ng ch&#xED;nh:</em></p>
<ul>
<li><strong>C&#xE1;c ph&#xE9;p t&#xED;nh c&#x1A1; b&#x1EA3;n c&#x1ED9;ng, tr&#x1EEB;, nh&#xE2;n, chia.</strong></li>
<li><strong>Dark &amp; light mode</strong></li>
<li><strong>Xem l&#x1EA1;i l&#x1ECB;ch s&#x1EED; c&#xE1;c ph&#xE9;p t&#xED;nh.</strong></li>
</ul>
<h1 id="mcchbivit">M&#x1EE5;c &#x110;&#xED;ch B&#xE0;i Vi&#x1EBF;t</h1>
<p>&#x110;&#xE2;y kh&#xF4;ng ph&#x1EA3;i l&#xE0; m&#x1ED9;t &#x1EE9;ng d&#x1EE5;ng g&#xEC; qu&#xE1; m&#x1EDB;i m&#x1EBB; c&#x1EA3; nh&#x1B0;ng khi v&#xE0;o tay m&#xEC;nh th&#xEC; s&#x1EBD; c&#xF3; c&#xE1;i m&#x1EDB;i ri&#xEA;ng kkkk.<br>
Nh&#x1B0;ng m&#xEC;nh v&#x1EAB;n mu&#x1ED1;n chia s&#x1EBB; &#x111;&#x1EC3; gi&#xFA;p c&#xE1;c b&#x1EA1;n beginner n&#x1EAF;m k&#x129; h&#x1A1;n c&#xE1;c ki&#x1EBF;n th&#x1EE9;c v&#x1EC1; javascript c&#x169;ng nh&#x1B0; c&#x1EA3;m th&#x1EA5;y h&#x1EE9;ng th&#xFA; h&#x1A1;n khi v&#x1EEB;a &#x111;&#x1B0;&#x1EE3;c h&#x1ECD;c v&#xE0; l&#xE0;m nh&#x1EEF;ng <strong>pet project</strong>.</p>
<h1 id="btuthino">B&#x1EAF;t &#x110;&#x1EA7;u Th&#xF4;i N&#xE0;o</h1>
<h2 id="lntng">L&#xEA;n &#xDD; T&#x1B0;&#x1EDF;ng</h2>
<p>&#xDD; t&#x1B0;&#x1EDF;ng cho project n&#xE0;y c&#x169;ng kh&#xF4;ng c&#xF3; g&#xEC; qu&#xE1; ph&#x1EE9;c t&#x1EA1;p, c&#xE1;c b&#x1EA1;n tham kh&#x1EA3;o h&#xEC;nh &#x1EA3;nh &#x1EDF; d&#x1B0;&#x1EDB;i nha.<br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1604031031/12_kxkks4.png" alt="X&#xE2;y D&#x1EF1;ng &#x1EE8;ng D&#x1EE5;ng Calculator V&#x1EDB;i Javascript"></p>
<h2 id="cutrcthmcchodn">C&#x1EA5;u Tr&#xFA;c Th&#x1B0; M&#x1EE5;c Cho D&#x1EF1; &#xC1;n</h2>
<p>C&#x1EA5;u tr&#xFA;c th&#x1B0; m&#x1EE5;c cho project n&#xE0;y c&#x169;ng &#x111;&#x1A1;n gi&#x1EA3;n th&#xF4;i hihihi<br>
V&#xED; d&#x1EE5;: M&#xEC;nh s&#x1EBD; t&#x1EA1;o m&#x1ED9;t folder project v&#x1EDB;i t&#xEA;n l&#xE0; <strong>Calculator with js</strong>. Trong folder &#x111;&#xF3; c&#xE1;c b&#x1EA1;n t&#x1EA1;o cho m&#xEC;nh m&#x1ED9;t file <strong>index.html</strong>, 1 folder <code>css &amp; js</code> &#x111;&#x1EC3; ch&#x1EE9;a l&#x1EA7;n l&#x1B0;&#x1EE3;t c&#xE1;c file &#x111;&#xF3; l&#xE0; <strong>style.css v&#xE0; script.js</strong><br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1604031493/1_nwq8wy.png" alt="X&#xE2;y D&#x1EF1;ng &#x1EE8;ng D&#x1EE5;ng Calculator V&#x1EDB;i Javascript"></p>
<h2 id="btucodethi">B&#x1EAF;t &#x110;&#x1EA7;u Code Th&#xF4;i</h2>
<h3 id="1chcnngtnhtoncbn">1. Ch&#x1EE9;c N&#x103;ng T&#xED;nh To&#xE1;n C&#x1A1; B&#x1EA3;n</h3>
<h6 id="11codehtml">1.1 Code HTML</h6>
<p>Trong ph&#x1EA7;n html n&#xE0;y ta s&#x1EBD; t&#x1EA1;o m&#x1ED9;t <code>.container-grid</code> &#x111;&#x1EC3; bao b&#x1ECD;c to&#xE0;n b&#x1ED9; calculator ti&#x1EBF;p theo l&#xE0; m&#x1ED9;t <code>.result</code> d&#xF9;ng &#x111;&#x1EC3; hi&#x1EC3;n th&#x1ECB; k&#x1EBF;t qu&#x1EA3; t&#xED;nh to&#xE1;n v&#xE0; cu&#x1ED1;i c&#xF9;ng l&#xE0; c&#xE1;c s&#x1ED1; v&#xE0; ph&#xE9;p t&#xED;nh c&#x1EA7;n c&#xF3; &#x111;&#x1EC3; t&#xED;nh to&#xE1;n.<br>
B&#x1EA1;n t&#x1EA1;o cho m&#xEC;nh c&#xE1;c event <strong>onclick</strong> d&#xF9;ng &#x111;&#x1EC3; th&#x1EF1;c hi&#x1EC7;n c&#xE1;c ch&#x1EE9;c n&#x103;ng t&#xED;nh to&#xE1;n.<br>
C&#xE1;c b&#x1EA1;n tham kh&#x1EA3;o code &#x1EDF; d&#x1B0;&#x1EDB;i nha m&#x1EE5;c &#x111;&#xED;ch m&#xE0; m&#xEC;nh &#x111;&#x1B0;a &#x1EA3;nh l&#xEA;n &#x111;&#xE2;y &#x111;&#x1EC3; c&#xE1;c b&#x1EA1;n t&#x1EF1; code theo ch&#x1EDB; kh&#xF4;ng ph&#x1EA3;i l&#xE0; copy n&#xF3; gi&#xFA;p &#xED;ch r&#x1EA5;t nhi&#x1EC1;u trong qu&#xE1; tr&#xEC;nh h&#x1ECD;c.<br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1604035693/2_oyu1vi.png" alt="X&#xE2;y D&#x1EF1;ng &#x1EE8;ng D&#x1EE5;ng Calculator V&#x1EDB;i Javascript"></p>
<h6 id="12codejavascript">1.2 Code Javascript</h6>
<p>&#x110;&#xE2;y l&#xE0; ph&#x1EA7;n m&#xE0; c&#xF3; th&#x1EC3; n&#xF3;i l&#xE0; quan tr&#x1ECD;ng nh&#x1EA5;t, n&#x1EBF;u m&#xE0; b&#xEC;nh th&#x1B0;&#x1EDD;ng th&#xEC; <strong>html -&gt; css -&gt; js</strong> nh&#x1B0;ng h&#xF4;m nay m&#xEC;nh thay &#x111;&#x1ED5;i m&#x1ED9;t t&#xED; th&#xEC; m&#xEC;nh s&#x1EBD; code js tr&#x1B0;&#x1EDB;c.<br>
M&#xEC;nh s&#x1EBD; code xong c&#xE1;c ch&#x1EE9;c n&#x103;ng t&#xED;nh to&#xE1;n c&#x1A1; b&#x1EA3;n r&#x1ED3;i m&#x1EDB;i css cho n&#xF3; nha.<br>
Tr&#x1B0;&#x1EDB;c ti&#xEA;n c&#xE1;c b&#x1EA1;n <strong>import file js</strong> v&#xE0;o trong file <strong>index.html</strong> tr&#x1B0;&#x1EDB;c c&#xE1;i &#x111;&#xE3;:<br>
<code>&lt;script src=&quot;js/script.js&quot;&gt;&lt;/script&gt;</code><br>
Trong ph&#x1EA7;n n&#xE0;y s&#x1EBD; g&#x1ED3;m c&#xE1;c ch&#x1EE9;c n&#x103;ng chi ti&#x1EBF;t nh&#x1B0; sau:<br>
<strong>Hi&#x1EC3;n th&#x1ECB; ch&#x1EEF; s&#x1ED1; v&#xE0; k&#x1EBF;t qu&#x1EA3; ph&#xE9;p to&#xE1;n</strong><br>
<strong>DEL (x&#xF3;a c&#xE1;c s&#x1ED1; cu&#x1ED1;i c&#xF9;ng) v&#xE0; AC (x&#xF3;a to&#xE0;n b&#x1ED9;)</strong><br>
<strong>Th&#x1EF1;c hi&#x1EC7;n c&#xE1;c ph&#xE9;p t&#xED;nh</strong></p>
<ul>
<li>C&#xE1;c b&#x1EA1;n khai b&#xE1;o hai bi&#x1EBF;n &#x111;&#x1EC3; &#x111;&#x1ECB;nh ngh&#x129;a c&#xE1;c ph&#xE9;p t&#xED;nh v&#xE0; k&#x1EBF;t qu&#x1EA3;, ti&#x1EBF;p theo c&#xE1;c b&#x1EA1;n ch&#x1EC9; c&#x1EA7;n l&#x1EB7;p qua c&#xE1;c ph&#xE9;p t&#xED;nh r&#x1ED3;i add event click cho n&#xF3; l&#xE0; &#x111;&#x1B0;&#x1EE3;c. Khi click th&#xEC; s&#x1EBD; hi&#x1EC3;n th&#x1ECB; ra tr&#xEA;n ph&#x1EA7;n k&#x1EBF;t qu&#x1EA3;.</li>
<li>&#x110;&#x1EC3; m&#xE0; th&#x1EF1;c hi&#x1EC7;n &#x111;&#x1B0;&#x1EE3;c c&#xE1;c ph&#xE9;p t&#xED;nh th&#xEC; ta s&#x1EBD; s&#x1EED; d&#x1EE5;ng h&#xE0;m <code>eval</code> c&#xE1;c b&#x1EA1;n c&#xF3; th&#x1EC3; tham kh&#x1EA3;o th&#xEA;m v&#x1EC1; eval <a href="https://freetuts.net/javascript-function/eval.html">t&#x1EA1;i &#x111;&#xE2;y</a>.</li>
<li>Ti&#x1EBF;p &#x111;&#x1EBF;n l&#xE0; AC (x&#xF3;a to&#xE0;n b&#x1ED9;) khi click v&#xE0;o bi&#x1EC3;u th&#x1EE9;c &#x111;&#x1EA5;y th&#xEC; s&#x1EBD; xu&#x1EA5;t hi&#x1EC7;n m&#x1ED9;t empty string, c&#xF2;n khi click v&#xE0;o bi&#x1EC3;u th&#x1EE9;c DEL (x&#xF3;a c&#xE1;c s&#x1ED1; cu&#x1ED1;i c&#xF9;ng) b&#x1EB1;ng c&#xE1;ch s&#x1EED; d&#x1EE5;ng h&#xE0;m <code>substring()</code> c&#xE1;c b&#x1EA1;n tham kh&#x1EA3;o t&#x1EA5;m h&#xEC;nh &#x1EDF; d&#x1B0;&#x1EDB;i &#x111;&#x1EC3; hi&#x1EC3;u r&#xF5; h&#x1A1;n nha.<br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1604073165/substring_mubfv2.png" alt="X&#xE2;y D&#x1EF1;ng &#x1EE8;ng D&#x1EE5;ng Calculator V&#x1EDB;i Javascript"><br>
<strong>C&#xF2;n d&#x1B0;&#x1EDB;i &#x111;&#xE2;y l&#xE0; code JS:</strong><br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1604070088/2_zzzcnu.png" alt="X&#xE2;y D&#x1EF1;ng &#x1EE8;ng D&#x1EE5;ng Calculator V&#x1EDB;i Javascript"><br>
<strong>V&#xE0; &#x111;&#xE2;y l&#xE0; k&#x1EBF;t qu&#x1EA3; khi ch&#xFA;ng ta th&#x1EF1;c hi&#x1EC7;n c&#xE1;c ph&#xE9;p t&#xED;nh m&#xE0; ch&#x1B0;a css cho n&#xF3;:</strong><br>
<img src="https://media.giphy.com/media/qSAuxaekN8NT5TBFYF/giphy.gif" alt="X&#xE2;y D&#x1EF1;ng &#x1EE8;ng D&#x1EE5;ng Calculator V&#x1EDB;i Javascript"></li>
</ul>
<h6 id="13codecss">1.3 Code CSS</h6>
<p>Nh&#x1B0; c&#xE1;c b&#x1EA1;n &#x111;&#xE3; th&#x1EA5;y &#x1EDF; tr&#xEA;n khi ch&#xFA;ng ta ch&#x1B0;a css cho n&#xF3; th&#xEC; nh&#xEC;n kh&#xE1; l&#xE0; c&#x1EE7; chu&#x1ED1;i &#x111;&#xFA;ng kh&#xF4;ng n&#xE0;o, v&#x1EAD;y b&#xE2;y gi&#x1EDD; ch&#xFA;ng ta b&#x1EAF;t &#x111;&#x1EA7;u css th&#xF4;i n&#xE0;o.<br>
&#x110;&#x1EA7;u ti&#xEA;n c&#xE1;c b&#x1EA1;n c&#x1EA7;n import cho m&#xEC;nh file css v&#xE0;o tr&#x1B0;&#x1EDB;c &#x111;&#xE3; nha:<br>
<code>&lt;link rel=&quot;stylesheet&quot; href=&quot;css/style.css&quot; /&gt;</code><br>
B&#xE2;y gi&#x1EDD; c&#xE1;i m&#xE0; quan tr&#x1ECD;ng nh&#x1EA5;t &#x1EDF; &#x111;&#xE2;y l&#xE0; vi&#x1EC7;c chia layout nh&#x1B0; n&#xE0;o cho h&#x1EE3;p l&#xFD;. Th&#xEC; m&#xEC;nh s&#x1EBD; s&#x1EED; d&#x1EE5;ng <code>CSS Grid</code> &#x111;&#x1EC3; chia layout cho n&#xF3; (m&#xEC;nh c&#xF3; vi&#x1EBF;t m&#x1ED9;t b&#xE0;i v&#x1EC1; grid <a href="https://www.thanhlongdev.com/xay-dung-layout-don-gian-css-grid/">t&#x1EA1;i &#x111;&#xE2;y</a>  c&#xE1;c b&#x1EA1;n tham kh&#x1EA3;o nha.)<br>
<strong>M&#xEC;nh s&#x1EBD; chia layout nh&#x1B0; sau c&#xE1;c b&#x1EA1;n xem &#x1EA3;nh &#x1EDF; d&#x1B0;&#x1EDB;i nha:</strong><br>
V&#x1EDB;i <code>.container-grid</code> m&#xEC;nh chia l&#xE0;m 2 h&#xE0;ng v&#x1EDB;i k&#xED;ch th&#x1B0;&#x1EDB;c t&#x1B0;&#x1A1;ng &#x1EE9;ng. Trong &#x111;&#xF3; <code>.calculate </code> m&#xEC;nh s&#x1EBD; chia ra l&#xE0;m 2 c&#x1ED9;t v&#x1EDB;i m&#x1ED7;i c&#x1ED9;t l&#x1EA7;n l&#x1B0;&#x1EE3;t l&#xE0; <em>3 c&#x1ED9;t / 4 h&#xE0;ng v&#xE0; 2 c&#x1ED9;t / 4 h&#xE0;ng</em><br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1604166553/1_rnfckv.png" alt="X&#xE2;y D&#x1EF1;ng &#x1EE8;ng D&#x1EE5;ng Calculator V&#x1EDB;i Javascript"><br>
<strong>V&#xE0; d&#x1B0;&#x1EDB;i &#x111;&#xE2;y l&#xE0; to&#xE0;n b&#x1ED9; code CSS</strong><br>
C&#xE1;c b&#x1EA1;n c&#xF3; th&#x1EC3; tham kh&#x1EA3;o v&#xE0; c&#x169;ng nh&#x1B0; t&#x1EF1; m&#xEC;nh code t&#xF9;y theo kh&#x1EA3; n&#x103;ng s&#xE1;ng t&#x1EA1;o c&#x1EE7;a m&#xEC;nh nha.<br>
Nh&#x1B0; c&#xE1;c b&#x1EA1;n &#x111;&#xE3; th&#x1EA5;y &#x1EDF; d&#x1B0;&#x1EDB;i th&#xEC; m&#xEC;nh c&#xF3; khai b&#xE1;o m&#x1ED9;t s&#x1ED1; thu&#x1ED9;c t&#xED;nh nh&#x1B0;: m&#xE0;u font, m&#xE0;u n&#x1EC1;n,... trong html v&#x1EDB;i m&#x1EE5;c &#x111;&#xED;ch d&#x1EC5; d&#xE0;ng t&#xE1;i s&#x1EED; d&#x1EE5;ng v&#xE0; thay &#x111;&#x1ED5;i bonus th&#xEA;m th&#xEC; khi vi&#x1EBF;t nh&#x1B0; th&#x1EBF; th&#xEC; khi code ch&#x1EE9;c n&#x103;ng dark &amp; light mode s&#x1EBD; d&#x1EC5; d&#xE0;ng h&#x1A1;n.<br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1604191750/12_ca8gdb.png" alt="X&#xE2;y D&#x1EF1;ng &#x1EE8;ng D&#x1EE5;ng Calculator V&#x1EDB;i Javascript"><br>
<em><strong>C&#xF2;n &#x111;&#xE2;y l&#xE0; k&#x1EBF;t qu&#x1EA3; khi ch&#xFA;ng ta &#x111;&#xE3; ho&#xE0;n th&#xE0;nh xong ch&#x1EE9;c n&#x103;ng t&#xED;nh to&#xE1;n c&#x1A1; b&#x1EA3;n, nh&#xEC;n c&#x169;ng ra g&#xEC; ph&#x1EBF;t &#x111;&#x1EA5;y hihi =)))</strong></em><br>
<img src="https://media.giphy.com/media/gYrppZ5dDrldUOG1pX/giphy.gif" alt="X&#xE2;y D&#x1EF1;ng &#x1EE8;ng D&#x1EE5;ng Calculator V&#x1EDB;i Javascript"></p>
<h3 id="2chcnngdarklightmode">2. Ch&#x1EE9;c N&#x103;ng Dark &amp; Light Mode</h3>
<h6 id="21codehtml">2.1 Code HTML</h6>
<p>Trong code html n&#xE0;y c&#xE1;c b&#x1EA1;n th&#xEA;m cho m&#xEC;nh m&#x1ED9;t <code>data-attribute</code> v&#x1EDB;i t&#xEA;n <strong>data-theme</strong> v&#xE0; value l&#xE0; <strong>light</strong> v&#xE0;o b&#xEA;n trong th&#x1EBB; m&#x1EDF; <code>&lt;html&gt;</code>.<br>
Ti&#x1EBF;p theo ph&#xED;a d&#x1B0;&#x1EDB;i <code>.grid-container</code> b&#x1EA1;n th&#xEA;m cho m&#xEC;nh m&#x1ED9;t class l&#xE0; <code>heading</code>. B&#xEA;n trong heading s&#x1EBD; l&#xE0; n&#x1A1;i ch&#x1EE9;a c&#xE1;c icon nh&#x1B0; m&#xEC;nh &#x111;&#xE3; l&#xEA;n &#xFD; t&#x1B0;&#x1EDF;ng t&#x1EEB; tr&#x1B0;&#x1EDB;c.<br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1604195665/2_hkwqfo.png" alt="X&#xE2;y D&#x1EF1;ng &#x1EE8;ng D&#x1EE5;ng Calculator V&#x1EDB;i Javascript"></p>
<h6 id="22codecss">2.2 Code CSS</h6>
<p>&#x110;&#x1EC3; m&#xE0; c&#xF3; th&#x1EC3; chia &#x111;&#x1B0;&#x1EE3;c layout cho <code>heading</code> th&#xEC; trong class <code>grid-container</code> c&#xE1;c b&#x1EA1;n th&#xEA;m cho m&#xEC;nh m&#x1ED9;t h&#xE0;ng n&#x1EEF;a v&#xE0;o thu&#x1ED9;c t&#xED;nh <strong>grid-template-rows</strong><br>
<code>grid-template-rows: .5fr 1fr 5fr;</code><br>
Ti&#x1EBF;p theo m&#xEC;nh ch&#x1EC9; c&#x1EA7;n th&#xEA;m m&#x1ED9;t s&#x1ED1; thu&#x1ED9;c t&#xED;nh nh&#x1B0;: m&#xE0;u n&#x1EC1;n, m&#xE0;u ch&#x1EEF; v&#xE0;o th&#x1EBB; <strong>attribute selector</strong> &#x111;&#xF3; l&#xE0; <code>html[data-theme=&apos;dark&apos;]</code> &#x111;&#x1EC3; c&#xF3; th&#x1EC3; l&#xE0;m thay &#x111;&#x1ED5;i &#x111;&#x1B0;&#x1EE3;c ch&#x1EBF; &#x111;&#x1ED9; dark &amp; light cho c&#xE1;c element. V&#xE0; d&#x1B0;&#x1EDB;i &#x111;&#xE2;y l&#xE0; code css cho ch&#x1EE9; n&#x103;ng n&#xE0;y c&#xE1;c b&#x1EA1;n tham kh&#x1EA3;o nha.<br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1604502997/2_pxyspo.png" alt="X&#xE2;y D&#x1EF1;ng &#x1EE8;ng D&#x1EE5;ng Calculator V&#x1EDB;i Javascript"><br>
<strong>Giao di&#x1EC7;n c&#x1EE7;a ch&#x1EE9;c n&#x103;ng dark &amp; light mode</strong><br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1604503762/2_gcbh5f.png" alt="X&#xE2;y D&#x1EF1;ng &#x1EE8;ng D&#x1EE5;ng Calculator V&#x1EDB;i Javascript"></p>
<h6 id="23codejavascript">2.3 Code Javascript</h6>
<p>Trong ph&#x1EA7;n n&#xE0;y c&#xE1;c b&#x1EA1;n ch&#x1EC9; c&#x1EA7;n b&#x1EAF;t s&#x1EF1; ki&#x1EC7;n <strong>checked</strong> th&#xEC; n&#xF3; s&#x1EBD; <strong>setAttribute</strong> t&#x1B0;&#x1A1;ng &#x1EE9;ng l&#xE0; &#x111;&#x1B0;&#x1EE3;c.<br>
M&#xEC;nh s&#x1EBD; gi&#x1EA3;i th&#xED;ch r&#xF5; h&#x1A1;n m&#x1ED9;t ch&#xFA;t &#x111;&#xF3; l&#xE0; m&#xEC;nh s&#x1EBD; g&#x1ECD;i h&#xE0;m checkbox r&#x1ED3;i add event change cho n&#xF3;. Data-attribute m&#x1EB7;c &#x111;&#x1ECB;nh l&#xE0; <strong>light</strong> khi checked th&#xEC; s&#x1EBD; change th&#xE0;nh <strong>dark</strong>, documentElement &#x1EDF; &#x111;&#xE2;y n&#xF3; s&#x1EBD; tr&#x1EA3; l&#xE0; l&#xE0; <code>&lt;html&gt;</code> element.<br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1604587364/12_ov6skc.png" alt="X&#xE2;y D&#x1EF1;ng &#x1EE8;ng D&#x1EE5;ng Calculator V&#x1EDB;i Javascript"><br>
<strong>V&#xE0; &#x111;&#xE2;y l&#xE0; k&#x1EBF;t qu&#x1EA3; khi ch&#xFA;ng ta ho&#xE0;n th&#xE0;nh ch&#x1EE9;c n&#x103;ng dark &amp; light mode</strong><br>
<img src="https://media.giphy.com/media/tD0CVX8xBcPGxzmv1P/giphy.gif" alt="X&#xE2;y D&#x1EF1;ng &#x1EE8;ng D&#x1EE5;ng Calculator V&#x1EDB;i Javascript"></p>
<h3 id="3chcnngxemlilchstnhton">3. Ch&#x1EE9;c N&#x103;ng Xem L&#x1EA1;i L&#x1ECB;ch S&#x1EED; T&#xED;nh To&#xE1;n</h3>
<h6 id="31codehtml">3.1 Code HTML</h6>
<p>Trong class <code>heading</code> c&#xE1;c b&#x1EA1;n th&#xEA;m cho m&#xEC;nh m&#x1ED9;t &#x111;o&#x1EA1;n code nh&#x1ECF; &#x111;&#x1EC3; ch&#x1EE9;a icon history v&#xE0; k&#x1EBF;t qu&#x1EA3; l&#x1B0;u history.</p>
<pre><code>            &lt;span&gt;
                &lt;i class=&quot;fas fa-history&quot;&gt;
                    &lt;div id=&quot;history&quot;&gt;&lt;/div&gt;
                &lt;/i&gt;
            &lt;/span&gt;
</code></pre>
<h6 id="32codejavascript">3.2 Code Javascript</h6>
<p>M&#xEC;nh s&#x1EBD; s&#x1EED; d&#x1EE5;ng object v&#xE0; array &#x111;&#x1EC3; l&#xE0;m c&#xF4;ng &#x111;o&#x1EA1;n l&#x1B0;u tr&#x1EEF; l&#x1ECB;ch s&#x1EED; t&#xED;nh to&#xE1;n nay, th&#xEC; ch&#x1EAF;c c&#xE1;c b&#x1EA1;n c&#x169;ng &#x111;&#xE3; h&#xEC;nh dung ra &#x111;&#x1B0;&#x1EE3;c l&#xE0; m&#xEC;nh s&#x1EBD; l&#xE0;m nh&#x1B0; n&#xE0;o r&#x1ED3;i nh&#x1EDD;.<br>
M&#xEC;nh s&#x1EBD; n&#xF3;i s&#x1A1; qua m&#x1ED9;t ch&#xFA;t nha, tr&#x1B0;&#x1EDB;c h&#x1EBF;t m&#xEC;nh s&#x1EBD; t&#x1EA1;o m&#x1ED9;t array empty &#x111;&#x1EC3; l&#x1B0;u c&#xE1;c bi&#x1EC3;u th&#x1EE9;c v&#xE0; k&#x1EBF;t qu&#x1EA3; t&#xED;nh to&#xE1;n. Sau &#x111;&#xF3; ta ch&#x1EC9; get v&#xE0; render ra view l&#xE0; &#x111;&#x1B0;&#x1EE3;c r&#x1ED3;i, c&#xE1;c b&#x1EA1;n xem &#x1EA3;nh &#x1EDF; d&#x1B0;&#x1EDB;i m&#xEC;nh c&#xF3; gi&#x1EA3;i th&#xED;ch chi ti&#x1EBF;t h&#x1A1;n &#xED;.<br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1604794244/12_kcoi0e_yipwzv.png" width="700" alt="X&#xE2;y D&#x1EF1;ng &#x1EE8;ng D&#x1EE5;ng Calculator V&#x1EDB;i Javascript"><br>
<strong>Ch&#xFA;ng ta c&#xF9;ng xem th&#x1EED; n&#xF3; &#x111;&#xE3; l&#x1B0;u &#x111;&#x1B0;&#x1EE3;c l&#x1ECB;ch s&#x1EED; ch&#x1B0;a nha hihi</strong><br>
<img src="https://media.giphy.com/media/h9IqhMg2DaRWSqEVVP/giphy.gif" alt="X&#xE2;y D&#x1EF1;ng &#x1EE8;ng D&#x1EE5;ng Calculator V&#x1EDB;i Javascript"></p>
<h6 id="33codecss">3.3 Code CSS</h6>
<p>Nh&#x1B0; c&#xE1;c b&#x1EA1;n &#x111;&#xE3; th&#x1EA5;y &#x1EDF; tr&#xEA;n khi ta l&#x1B0;u l&#x1ECB;ch s&#x1EED; th&#xEC; b&#x1ECB; v&#x1EE1; layout ngay v&#x1EAD;y b&#xE2;y gi&#x1EDD; ch&#xFA;ng ta l&#xE0;m nh&#x1B0; n&#xE0;o nh&#x1EDD;?<br>
Oke m&#xEC;nh &#x111;&#xE3; c&#xF3; b&#xE2;y gi&#x1EDD; ta ch&#x1EC9; c&#x1EA7;n &#x1EA9;n l&#x1ECB;ch s&#x1EED; &#x111;&#xF3; &#x111;i v&#xE0; ch&#x1EC9; khi n&#xE0;o click v&#xE0;o icon history th&#xEC; m&#x1EDB;i hi&#x1EC3;n th&#x1ECB;.</p>
<pre><code>#history {
    display: none;
    position: absolute;
    z-index: 9999;
    background: #5d4196;
    color: #fff;
    font-size: 1rem;
    font-weight: 400;
    padding: .5rem;
    margin-top: .5rem;

}

// class hi&#x1EC3;n th&#x1ECB; history
.indexHistory {
    display: block !important;
}
</code></pre>
<p><strong>D&#x1B0;&#x1EDB;i &#x111;&#xE2;y l&#xE0; code js &#x111;&#x1EC3; khi click v&#xE0;o icon th&#xEC; s&#x1EBD; add class &#x111;&#x1EC3; hi&#x1EC3;n th&#x1ECB; l&#x1ECB;ch s&#x1EED;</strong></p>
<pre><code>// Index History
let indexHistory = document.getElementsByClassName(&quot;fa-history&quot;)
indexHistory[0].addEventListener(&quot;click&quot;, function () {
    logHistory.classList.toggle(&quot;indexHistory&quot;)
})
</code></pre>
<p><strong>V&#xE0; d&#x1B0;&#x1EDB;i l&#xE0; k&#x1EBF;t qu&#x1EA3; khi ch&#xFA;ng &#x111;&#xE3; ho&#xE0;n th&#xE0;nh l&#x1B0;u tr&#x1EEF; l&#x1ECB;ch s&#x1EED; &lt;3</strong><br>
<img src="https://media.giphy.com/media/i0W3kKMqf0ppktdFrg/giphy.gif" alt="X&#xE2;y D&#x1EF1;ng &#x1EE8;ng D&#x1EE5;ng Calculator V&#x1EDB;i Javascript"><br>
<em><strong>V&#x1EAD;y l&#xE0; xong r&#x1ED3;i nha</strong></em>, c&#xE1;c b&#x1EA1;n tham kh&#x1EA3;o code m&#xE0; m&#xEC;nh &#x111;&#xE3; push l&#xEA;n github <a href="https://github.com/long1211/Calculator-with-JS">t&#x1EA1;i &#x111;&#xE2;y</a> nha.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h1 id="likt">L&#x1EDD;i K&#x1EBF;t</h1>
<p>V&#x1EAD;y l&#xE0; xong b&#xE0;i X&#xE2;y D&#x1EF1;ng &#x1EE8;ng D&#x1EE5;ng Calculator V&#x1EDB;i Javascript. M&#xEC;nh mong mu&#x1ED1;n b&#xE0;i n&#xE0;y s&#x1EBD; gi&#xFA;p c&#xE1;c b&#x1EA1;n beginer hi&#x1EC3;u, n&#x1EAF;m r&#xF5; h&#x1A1;n v&#xE0; c&#xF3; c&#x1EA3;m gi&#xE1;c th&#xFA; v&#x1ECB; h&#x1A1;n khi h&#x1ECD;c js.<br>
<strong>C&#xE1;c b&#x1EA1;n nh&#x1EDB; like v&#xE0; theo d&#xF5;i fanpage <a href="https://www.facebook.com/thanhlongdev/">Thanh Long Dev</a> &#x111;&#x1EC3; nh&#x1EAD;n nh&#x1EEF;ng th&#xF4;ng b&#xE1;o v&#x1EC1; b&#xE0;i vi&#x1EBF;t m&#x1EDB;i nh&#x1EA5;t nha.</strong><br>
<em><strong>N&#x1EBF;u c&#xE1;c b&#x1EA1;n c&#x1EA3;m th&#x1EA5;y b&#xE0;i vi&#x1EBF;t c&#x1EE7;a m&#xEC;nh hay th&#xEC; c&#xE1;c b&#x1EA1;n c&#xF3; th&#x1EC3; &#x1EE7;ng h&#x1ED9; m&#xEC;nh &#x111;&#x1EC3; m&#xEC;nh c&#xF3; th&#xEA;m &#x111;&#x1ED9;ng l&#x1EF1;c &#x111;&#x1EC3; ra nh&#x1EEF;ng b&#xE0;i topic hay v&#xE0; ch&#x1EA5;t l&#x1B0;&#x1EE3;ng h&#x1A1;n &#x1EE7;ng h&#x1ED9; m&#xEC;nh <a href="https://vrdonate.vn/thanhlongdev">t&#x1EA1;i &#x111;&#xE2;y nha.</a></strong></em><br>
<strong>Ch&#xFA;c C&#xE1;c B&#x1EA1;n Th&#xE0;nh C&#xF4;ng!!</strong></p>
<!--kg-card-end: markdown--><!--kg-card-begin: html--><iframe src="https://www.facebook.com/plugins/like.php?href=https%3A%2F%2Fwww.thanhlongdev.com%2Fxay-dung-calculator-with-javascript%2F&amp;width=450&amp;layout=standard&amp;action=like&amp;size=large&amp;share=true&amp;height=35&amp;appId=2794898430534168" width="450" height="35" style="border:none;overflow:hidden" scrolling="no" frameborder="0" allowtransparency="true" allow="encrypted-media"></iframe><!--kg-card-end: html--><!--kg-card-begin: html--><div class="fb-comments" data-href="https://www.thanhlongdev.com/xay-dung-calculator-with-javascript/" data-width="100%" data-numposts="10"></div><!--kg-card-end: html-->]]></content:encoded></item><item><title><![CDATA[Xây Dựng Layout Đơn Giản Với CSS Grid]]></title><description><![CDATA[<!--kg-card-begin: markdown--><h1 id="giithiuchung">Gi&#x1EDB;i Thi&#x1EC7;u Chung</h1>
<p>H&#xF4;m nay m&#xEC;nh s&#x1EBD; h&#x1B0;&#x1EDB;ng d&#x1EAB;n t&#x1EA5;t c&#x1EA3; m&#x1ECD;i ng&#x1B0;&#x1EDD;i x&#xE2;y d&#x1EF1;ng m&#x1ED9;t trang lading page v&#x1EDB;i</p>]]></description><link>https://www.thanhlongdev.com/xay-dung-layout-don-gian-css-grid/</link><guid isPermaLink="false">5f6b6e88c2da9e00010a3d36</guid><category><![CDATA[Lập Trình Web]]></category><dc:creator><![CDATA[Đặng Thanh Long]]></dc:creator><pubDate>Sat, 10 Oct 2020 11:58:34 GMT</pubDate><media:content url="https://digitalpress.fra1.cdn.digitaloceanspaces.com/4tg23ij/2020/10/css-grid.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h1 id="giithiuchung">Gi&#x1EDB;i Thi&#x1EC7;u Chung</h1>
<img src="https://digitalpress.fra1.cdn.digitaloceanspaces.com/4tg23ij/2020/10/css-grid.jpg" alt="X&#xE2;y D&#x1EF1;ng Layout &#x110;&#x1A1;n Gi&#x1EA3;n V&#x1EDB;i CSS Grid"><p>H&#xF4;m nay m&#xEC;nh s&#x1EBD; h&#x1B0;&#x1EDB;ng d&#x1EAB;n t&#x1EA5;t c&#x1EA3; m&#x1ECD;i ng&#x1B0;&#x1EDD;i x&#xE2;y d&#x1EF1;ng m&#x1ED9;t trang lading page v&#x1EDB;i grid css.<br>
Th&#xEC; m&#xEC;nh s&#x1EBD; convert UI trang home c&#x1EE7;a blog thanhlongdev v&#x1EDB;i grid css bao g&#x1ED3;m giao di&#x1EC7;n desktop v&#xE0; mobile.</p>
<h1 id="mcchbivit">M&#x1EE5;c &#x110;&#xED;ch B&#xE0;i Vi&#x1EBF;t</h1>
<p>&#x110;&#xE2;y kh&#xF4;ng ph&#x1EA3;i l&#xE0; ch&#x1EE7; &#x111;&#x1EC1; g&#xEC; qu&#xE1; xa l&#x1EA1; v&#xE0; m&#x1EDB;i m&#x1EBB; v&#x1EDB;i c&#xE1;c anh em front end dev.<br>
Nh&#x1B0;ng m&#xEC;nh v&#x1EAB;n mu&#x1ED1;n chia s&#x1EBB; &#x111;&#x1EC3; gi&#xFA;p c&#xE1;c b&#x1EA1;n beginner n&#x1EAF;m k&#x129; h&#x1A1;n c&#xE1;c ki&#x1EBF;n th&#x1EE9;c v&#x1EC1; c&#xE1;ch d&#x1EF1;ng m&#x1ED9;t layout v&#xE0; chia component ra l&#xE0;m sao cho n&#xF3; h&#x1EE3;p l&#xFD;, m&#xE0; kh&#xF4;ng c&#x1EA7;n s&#x1EED; d&#x1EE5;ng b&#x1EA5;t k&#xEC; framework n&#xE0;o c&#x1EA3; th&#xF4;ng qua vi&#x1EC7;c x&#xE2;y d&#x1EF1;ng m&#x1ED9;t project th&#x1EF1;c t&#x1EBF;.<br>
M&#xEC;nh ch&#x1EC9; mong mu&#x1ED1;n l&#xE0; c&#xE1;c b&#x1EA1;n &#x111;&#x1ECD;c b&#xE0;i c&#x1EE7;a m&#xEC;nh th&#x1EAD;t k&#x129; v&#xE0; r&#xF5; r&#xE0;ng.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h1 id="btuthino">B&#x1EAF;t &#x110;&#x1EA7;u Th&#xF4;i N&#xE0;o</h1>
<h2 id="lntng">L&#xEA;n &#xDD; T&#x1B0;&#x1EDF;ng</h2>
<p>&#xDD; t&#x1B0;&#x1EDF;ng &#x111;&#x1EC3; m&#xE0; convert UI trang home c&#x1EE7;a <strong>thanhlongdev</strong> c&#x169;ng &#x111;&#x1A1;n gi&#x1EA3;n th&#xF4;i. M&#xEC;nh s&#x1EBD; chia l&#xE0;m 3 ph&#x1EA7;n nha header, main v&#xE0; footer &#x111;&#x1EC3; code nha.<br>
Ch&#xFA;ng ta s&#x1EBD; code t&#x1EEB; giao di&#x1EC7;n desktop &#x111;&#x1EBF;n mobile. Trong &#x111;&#xF3;, ph&#x1EA7;n main c&#x1EE7;a giao di&#x1EC7;n desktop ta s&#x1EBD; chia c&#xE1;c topic theo t&#x1EEB;ng c&#x1ED9;t m&#xE0; template &#x111;&#xE3; &#x111;&#x1ECB;nh ngh&#x129;a s&#x1EB5;n, c&#xF2;n mobile th&#xEC; ta s&#x1EBD; c&#xE1;c b&#xE0;i topic &#x111;&#x1EC1;u m&#x1ED9;t c&#x1ED9;t c&#x1EA3;.</p>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1601573465/screencapture-thanhlongdev-2020-10-02-00_03_42_hezz3o.png" width="700" alt="X&#xE2;y D&#x1EF1;ng Layout &#x110;&#x1A1;n Gi&#x1EA3;n V&#x1EDB;i CSS Grid">
<h2 id="cutrcthmcchodn">C&#x1EA5;u Tr&#xFA;c Th&#x1B0; M&#x1EE5;c Cho D&#x1EF1; &#xC1;n</h2>
<p>C&#x1EA5;u tr&#xFA;c th&#x1B0; m&#x1EE5;c cho project n&#xE0;y c&#x169;ng &#x111;&#x1A1;n gi&#x1EA3;n th&#xF4;i ch&#x1EA3; c&#xF3; g&#xEC; ph&#x1EE9;c t&#x1EA1;p c&#x1EA3; hihihi<br>
V&#xED; d&#x1EE5;: M&#xEC;nh s&#x1EBD; t&#x1EA1;o m&#x1ED9;t folder project v&#x1EDB;i t&#xEA;n l&#xE0; <strong>Layout With Grid</strong>. Trong folder &#x111;&#xF3; c&#xE1;c b&#x1EA1;n t&#x1EA1;o cho m&#xEC;nh m&#x1ED9;t file <strong>index.html</strong> v&#xE0; 1 folder <code>css</code> &#x111;&#x1EC3; ch&#x1EE9;a 2 file &#x111;&#xF3; l&#xE0; <strong>style.css, reponsive.css</strong></p>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1601635832/12_zdr0w5.png" alt="X&#xE2;y D&#x1EF1;ng Layout &#x110;&#x1A1;n Gi&#x1EA3;n V&#x1EDB;i CSS Grid">
<h2 id="btucodethi">B&#x1EAF;t &#x110;&#x1EA7;u Code Th&#xF4;i</h2>
<h3 id="phnheader">Ph&#x1EA7;n Header</h3>
<p>Trong ph&#x1EA7;n header n&#xE0;y ch&#xFA;ng ta s&#x1EBD; s&#x1EED; d&#x1EE5;ng css grid &#x111;&#x1EC3; chia layout v&#xE0; r&#xF5; h&#x1A1;n n&#x1EEF;a &#x111;&#xF3; l&#xE0; thu&#x1ED9;c t&#xED;nh <code>grid-template-columns</code> &#x111;&#x1EC3; c&#xF3; th&#x1EC3; chia layout cho n&#xF3;.<br>
<code>grid-template-columns</code> s&#x1EBD; t&#x1B0;&#x1A1;ng &#x1EE9;ng v&#x1EDB;i s&#x1ED1; c&#x1ED9;t, c&#xE1;c gi&#xE1; tr&#x1ECB; s&#x1EBD; t&#x1B0;&#x1A1;ng &#x1EE9;ng v&#x1EDB;i chi&#x1EC1;u r&#x1ED9;ng c&#x1EE7;a c&#xE1;c c&#x1ED9;t l&#x1EA7;n l&#x1B0;&#x1EE3;t t&#x1EEB; tr&#xE1;i sang ph&#x1EA3;i.<br>
C&#xF2;n <code>grid-template-rows</code> s&#x1EBD; t&#x1B0;&#x1A1;ng &#x1EE9;ng s&#x1ED1; h&#xE0;ng, c&#xE1;c gi&#xE1; tr&#x1ECB; s&#x1EBD; t&#x1B0;&#x1A1;ng &#x1EE9;ng v&#x1EDB;i chi&#x1EC1;u cao c&#x1EE7;a c&#xE1;c h&#xE0;ng l&#x1EA7;n l&#x1B0;&#x1EE3;t t&#x1EEB; tr&#xEA;n xu&#x1ED1;ng d&#x1B0;&#x1EDB;i.<br>
Ch&#xFA;ng ta s&#x1EBD; ph&#xE2;n t&#xED;ch v&#xE0; chia t&#xE1;ch t&#x1EEB;ng component m&#x1ED9;t &#x111;&#x1EC3; vi&#x1EC7;c code d&#x1EC5; d&#xE0;ng h&#x1A1;n nha</p>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1602130502/12_kcoi0e_wwzdii.png" width="700" alt="X&#xE2;y D&#x1EF1;ng Layout &#x110;&#x1A1;n Gi&#x1EA3;n V&#x1EDB;i CSS Grid">
<p>Nh&#x1B0; c&#xE1;c b&#x1EA1;n th&#x1EA5;y &#x1EDF; tr&#xEA;n th&#xEC; <code>fr</code> &#x111;&#x1B0;&#x1EE3;c vi&#x1EBF;t t&#x1EAF;t c&#x1EE7;a &quot;fraction&quot; (ph&#xE2;n s&#x1ED1;) l&#xE0; g&#xEC;??<br>
Th&#xEC; n&#xF3; c&#x169;ng l&#xE0; m&#x1ED9;t &#x111;&#x1A1;n v&#x1ECB; k&#xED;ch th&#x1B0;&#x1EDB;c t&#x1B0;&#x1A1;ng t&#x1EF1; nh&#x1B0; px, rem, em nh&#x1B0;ng n&#xF3; &#x111;&#x1B0;&#x1EE3;c thi&#x1EBF;t k&#x1EBF; d&#xE0;nh ri&#xEA;ng cho grid. <code>1fr</code> t&#x1B0;&#x1A1;ng &#x1EE9;ng v&#x1EDB;i m&#x1ED9;t ph&#x1EA7;n trong kh&#xF4;ng gian tr&#x1ED1;ng c&#x1EE7;a grid container.<br>
<strong>Code HTML</strong><br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1602116768/12_vsr7ky.png" width="700" alt="X&#xE2;y D&#x1EF1;ng Layout &#x110;&#x1A1;n Gi&#x1EA3;n V&#x1EDB;i CSS Grid"><br>
L&#xFD; do t&#x1EA1;i sao m&#xEC;nh kh&#xF4;ng copy code v&#xE0;o &#x111;&#xE2;y cho c&#xE1;c b&#x1EA1;n d&#x1EC5; d&#xE0;ng code h&#x1A1;n, b&#x1EDF;i v&#xEC; m&#xEC;nh mong mu&#x1ED1;n c&#xE1;c b&#x1EA1;n nh&#xEC;n v&#xE0;o &#x111;&#x1EA5;y r&#x1ED3;i l&#xE0;m theo tr&#xE1;nh tr&#x1B0;&#x1EDD;ng h&#x1EE3;p copy,... M&#x1EE5;c &#x111;&#xED;ch ch&#x1EC9; mu&#x1ED1;n t&#x1ED1;t cho c&#xE1;c b&#x1EA1;n th&#xF4;i hihihi.<br>
<strong>V&#xE0; &#x111;&#xE2;y l&#xE0; header khi m&#xEC;nh code xong ph&#x1EA7;n html cho n&#xF3;. Nh&#xEC;n c&#x1EE7; chu&#x1ED1;i l&#x1EAF;m c&#xE1;c &#xF4;ng &#x1EA1; =)))</strong><br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1602125140/screencapture-127-0-0-1-5500-index-html-2020-10-08-09_27_04_p7h2ev.png" alt="X&#xE2;y D&#x1EF1;ng Layout &#x110;&#x1A1;n Gi&#x1EA3;n V&#x1EDB;i CSS Grid"><br>
<strong>Code CSS</strong><br>
Trong ph&#x1EA7;n CSS n&#xE0;y m&#xEC;nh s&#x1EBD; s&#x1EED; d&#x1EE5;ng grid &#x111;&#x1EC3; chia layout cho navbar v&#xE0; banner. Ch&#xFA;ng ta s&#x1EBD; &#x111;i t&#x1EEB;ng ph&#x1EA7;n nha tr&#x1B0;&#x1EDB;c ti&#xEA;n l&#xE0; navbar r&#x1ED3;i ti&#x1EBF;p &#x111;&#x1EBF;n l&#xE0; banner.<br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1602138133/12_kcoi0e_iypiq3.png" width="700" alt="X&#xE2;y D&#x1EF1;ng Layout &#x110;&#x1A1;n Gi&#x1EA3;n V&#x1EDB;i CSS Grid"><br>
<code>Repeat</code> &#x111;&#x1B0;&#x1EE3;c s&#x1EED; d&#x1EE5;ng khi grid c&#xF3; nhi&#x1EC1;u h&#xE0;ng v&#xE0; c&#x1ED9;t gi&#x1ED1;ng nhau th&#xEC; ch&#xFA;ng ta n&#xEA;n s&#x1EED; d&#x1EE5;ng &#x111;&#x1EC3; khai b&#xE1;o nhanh h&#x1A1;n.<br>
<code>Justify-items</code> s&#x1EBD; c&#x103;n ch&#x1EC9;nh n&#x1ED9;i dung theo tr&#x1EE5;c ho&#xE0;nh (tr&#x1EE5;c x), c&#xF2;n <code>align-items</code> s&#x1EBD; c&#x103;n ch&#x1EC9;nh n&#x1ED9;i dung b&#xEA;n trong grid theo tr&#x1EE5;c tung (tr&#x1EE5;c y).</p>
<pre><code>* {
    padding: 0;
    margin: 0;
    box-sizing: border-box;
    font-family: &apos;Open Sans&apos;, sans-serif;
}

li { list-style: none; }

a { text-decoration: none; }

/* header */
header {
    background: #0a0b0c;
    padding: 0 5vw;
    color: #fff;
}

/* Navbar */
nav {
    margin: 0 auto; // C&#xF3; ch&#x1EE9;c n&#x103;ng c&#x103;n gi&#x1EEF;a khi s&#x1EED; d&#x1EE5;ng chung v&#x1EDB;i width
    max-width: 1040px; // Set width khi v&#x1B0;&#x1EE3;t qu&#xE1; 1040 th&#xEC; s&#x1EBD; bay v&#xE0;o gi&#x1EEF;a
    width: 100%;
    display: grid;
    grid-template-columns: 1fr 1fr;
}

.menu {
    padding-top: .5rem;
    display: grid;
    grid-template-columns: repeat(4, .2fr);
    justify-items: center;
    overflow-x: auto;
    overflow-y: hidden;
    white-space: nowrap;
}

/* Nav right */
.site-nav-right {
    display: grid;
    grid-template-columns: 12fr 1fr;
    padding: 10px 0;
    height: 64px;
    justify-items: right;
}

/* Banner */
.banner-header {
    display: grid;
    justify-items: center;
    align-items: center;
    padding: 6vw 3vw;
    min-height: 200px;
    max-height: 340px;
}

.banner-header .site-description {
    text-align: center;
    font-weight: 500;
    padding: 5px 0;
    font-size: 1.2rem;
    line-height: 1.4em;
    opacity: .8;
}
</code></pre>
<p>Style css c&#xE1;c chi ti&#x1EBF;t trong ph&#x1EA7;n header m&#xE0; c&#xE1;c b&#x1EA1;n c&#xF3; th&#x1EC3; t&#x1EF1; css theo s&#x1EE9;c s&#xE1;ng t&#x1EA1;o c&#x1EE7;a m&#xEC;nh nha.<br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1602139282/12_dxbvb8.png" alt="X&#xE2;y D&#x1EF1;ng Layout &#x110;&#x1A1;n Gi&#x1EA3;n V&#x1EDB;i CSS Grid"><br>
<strong>V&#xE0; &#x111;&#xE2;y l&#xE0; k&#x1EBF;t qu&#x1EA3; khi ch&#xFA;ng ta &#x111;&#xE3; ho&#xE0;n th&#xE0;nh xong ph&#x1EA7;n header &lt;3</strong><br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1602140816/Untitled-2_mzwfar.png" width="700" alt="X&#xE2;y D&#x1EF1;ng Layout &#x110;&#x1A1;n Gi&#x1EA3;n V&#x1EDB;i CSS Grid"></p>
<h3 id="phnmain">Ph&#x1EA7;n Main</h3>
<p>Trong ph&#x1EA7;n n&#xE0;y m&#xEC;nh s&#x1EBD; chia layout gi&#x1ED1;ng nh&#x1B0; &#xFD; t&#x1B0;&#x1EDF;ng m&#xE0; m&#xEC;nh &#x111;&#xE3; n&#xF3;i &#x1EDF; tr&#xEA;n. M&#xEC;nh s&#x1EBD; bao b&#x1ECD;c &#x1EDF; ngo&#xE0;i m&#x1ED9;t <code>class=&quot;posts&quot;</code> b&#xEA;n trong &#x111;&#xF3; l&#xE0; nh&#x1EEF;ng <strong>class</strong> d&#xF9;ng &#x111;&#x1EC3; chia b&#x1ED1; c&#x1EE5;c t&#x1EEB;ng ph&#x1EA7;n m&#x1ED9;t v&#xE0; ng&#x103;n c&#xE1;ch nhau b&#x1EB1;ng th&#x1EBB; <code>&lt;hr&gt;</code>, b&#xEA;n trong l&#xE0; th&#x1EBB; <strong>article</strong> d&#xF9;ng &#x111;&#x1EC3; ch&#x1EE9;a c&#xE1;c b&#xE0;i topic c&#xE1;c b&#x1EA1;n xem &#x1EA3;nh &#x1EDF; d&#x1B0;&#x1EDB;i &#x111;&#x1EC3; c&#xF3; th&#x1EC3; r&#xF5; h&#x1A1;n nha.<br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1602169667/screencapture-thanhlongdev-2020-10-02-00_03_42_hezz3o_kudhrw.png" width="700" alt="X&#xE2;y D&#x1EF1;ng Layout &#x110;&#x1A1;n Gi&#x1EA3;n V&#x1EDB;i CSS Grid"><br>
<strong>Code HTML</strong><br>
D&#x1B0;&#x1EDB;i &#x111;&#xE2;y l&#xE0; t&#x1ED5;ng qu&#xE1;t nh&#x1EEF;ng class ch&#xED;nh trong ph&#x1EA7;n main.<br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1602220451/12_ghifs7.png" alt="X&#xE2;y D&#x1EF1;ng Layout &#x110;&#x1A1;n Gi&#x1EA3;n V&#x1EDB;i CSS Grid"><br>
C&#xF2;n d&#x1B0;&#x1EDB;i &#x111;&#xE2;y l&#xE0; nh&#x1EEF;ng class chi ti&#x1EBF;t trong th&#x1EBB; <strong>article</strong> bao g&#x1ED3;m: &#x1EA3;nh b&#xEC;a, ti&#xEA;u &#x111;&#x1EC1;, m&#xF4; t&#x1EA3;, t&#xE1;c gi&#x1EA3;, th&#x1EBB; tag,... V&#xE0; c&#xF3; m&#x1ED9;t l&#x1B0;u &#xFD; n&#x1EEF;a &#x111;&#xF3; l&#xE0; nh&#x1EEF;ng b&#xE0;i topic &#x111;&#x1EC1;u c&#xF3; th&#x1EC3; &#x111;&#x1B0;&#x1EE3;c click v&#xE0;o &#x111;&#x1EC3; xem chi ti&#x1EBF;t n&#xEA;n c&#x1EA7;n &#x111;&#x1EB7;t trong th&#x1EBB; <strong>li&#xEA;n k&#x1EBF;t a</strong>.</p>
<pre><code>     &lt;article class=&quot;post-wrapper&quot;&gt;
                    &lt;a href=&quot;#&quot;&gt;
                        &lt;img class=&quot;img-post&quot;
                            src=&quot;https://digitalpress.fra1.cdn.digitaloceanspaces.com/4tg23ij/2020/09/33.png &quot; alt=&quot;&quot;&gt;
                    &lt;/a&gt;
                    &lt;div class=&quot;content-post&quot;&gt;
                        &lt;a href=&quot;#&quot;&gt;
                            &lt;div class=&quot;tag-post&quot;&gt;L&#x1EAD;p Tr&#xEC;nh Web&lt;/div&gt;
                            &lt;h2 class=&quot;title-post&quot;&gt;H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Books Store V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB - Ph&#x1EA7;n 4 &lt;/h2&gt;
                            &lt;p class=&quot;desc-post&quot;&gt;
                                Ch&#x1EE9;c N&#x103;ng Hi&#x1EC3;n Th&#x1ECB; Chi Ti&#x1EBF;t, C&#x1EAD;p Nh&#x1EAD;t V&#xE0; X&#xF3;a Books &#x110;&#x1ECB;nh Ngh&#x129;a V&#xE0; Controller Router Hi&#x1EC3;n
                                Th&#x1ECB; Chi Ti&#x1EBF;t Trong Books M&#xEC;nh s&#x1EBD; n&#xF3;i s&#x1A1; qua m&#x1ED9;t ch&#xFA;t v&#x1EC1;
                            &lt;/p&gt;
                        &lt;/a&gt;
                        &lt;div class=&quot;author-post&quot;&gt;
                            &lt;a href=&quot;#&quot;&gt;
                                &lt;img class=&quot;avatar-author&quot;
                                    src=&quot;https://digitalpress.fra1.cdn.digitaloceanspaces.com/4tg23ij/2020/05/IMG_20200331_120727-1.jpg&quot;
                                    alt=&quot;&quot; /&gt;
                            &lt;/a&gt;
                            &lt;div class=&quot;content-author&quot;&gt;
                                &lt;div&gt;
                                    &lt;a href=&quot;&quot;&gt;&#x110;&#x1EB7;ng Thanh Long&lt;/a&gt;
                                &lt;/div&gt;
                                &lt;span class=&quot;post-card-byline-date&quot;&gt;&lt;time datetime=&quot;2020-09-12&quot;&gt;12 Th09 2020&lt;/time&gt;
                                    &lt;span class=&quot;bull&quot;&gt;&#x2022;&lt;/span&gt; 13 min read&lt;/span&gt;
                            &lt;/div&gt;
                        &lt;/div&gt;
                    &lt;/div&gt;
                &lt;/article&gt;
</code></pre>
<p><strong>Code CSS</strong><br>
Nh&#x1EEF;ng class <code>&quot;posts-columns-1&quot;, posts-columns-3 v&#xE0; posts-columns-2</code> th&#xEC; s&#x1EBD; t&#x1B0;&#x1A1;ng &#x1EE9;ng l&#x1EA7;n l&#x1B0;&#x1EE3;t v&#x1EDB;i c&#xE1;c c&#x1ED9;t nh&#x1B0; sau <strong>grid-template-columns: 1fr; grid-template-columns: repeat(3, 1fr); grid-template-columns: repeat(2, 1fr).</strong><br>
<code>Grid-column-gap</code> l&#xE0; kho&#x1EA3;ng c&#xE1;ch gi&#x1EEF;a c&#xE1;c c&#x1ED9;t v&#xE0; ng&#x1B0;&#x1EE3;c l&#x1EA1;i <code>grid-row-gap</code> s&#x1EBD; l&#xE0; kho&#x1EA3;ng c&#xE1;ch gi&#x1EEF;a c&#xE1;c h&#xE0;ng v&#x1EDB;i nhau.</p>
<pre><code>/* Main */
main {
    padding: 0 5vw;
}

.margin-main {
    margin: 2.5rem 0 6rem;
}

.posts {
    max-width: 1040px;
    width: 100%;
    margin: 0 auto;
}

.posts-columns-1 {
    display: grid;
    grid-template-columns: 1fr;
}

.posts-columns-3 {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    grid-column-gap: 2rem;
}

.posts-columns-2 {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    grid-column-gap: 2rem;
}
</code></pre>
<p>Style css c&#xE1;c th&#xE0;nh ph&#x1EA7;n chi ti&#x1EBF;t trong th&#x1EBB; article, c&#xF3; m&#x1ED9;t v&#x1EA5;n &#x111;&#x1EC1; nh&#x1ECF; &#x111;&#xF3; l&#xE0; &#x1EA3;nh b&#xEC;a v&#xE0; n&#x1ED9;i dung trong th&#x1EBB; <strong>class=&quot;post-wrapper&quot;</strong> &#x111;&#x1B0;&#x1EE3;c bao b&#x1ECD;c b&#x1EDF;i class=&quot;<strong>posts-columns-1&quot;</strong> ph&#x1EA3;i n&#x1EB1;m ngang h&#xE0;ng v&#x1EDB;i nhau v&#x1EAD;y b&#xE2;y gi&#x1EDD; ta ph&#x1EA3;i l&#xE0;m sao nh&#x1EDD;. Th&#xEC; &#x111;&#x1A1;n gi&#x1EA3;n th&#xF4;i trong <strong>class=&quot;post-wrapper&quot;</strong> ch&#xFA;ng ta s&#x1EBD; s&#x1EED; d&#x1EE5;ng grid v&#xE0; thu&#x1ED9;c t&#xED;nh <code>grid-template-columns</code> &#x111;&#x1EC3; l&#xE0;m &#x111;i&#x1EC1;u &#x111;&#xF3; hihihi.<br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1602259344/Untitled-2_huy2d4.png" width="700" alt="X&#xE2;y D&#x1EF1;ng Layout &#x110;&#x1A1;n Gi&#x1EA3;n V&#x1EDB;i CSS Grid"></p>
<p><strong>V&#xE0; &#x111;&#xE2;y l&#xE0; k&#x1EBF;t qu&#x1EA3; khi ch&#xFA;ng ta &#x111;&#xE3; ho&#xE0;n th&#xE0;nh xong ph&#x1EA7;n main nh&#xEC;n c&#x169;ng ra g&#xEC; ph&#x1EBF;t nh&#x1EDD; =)))</strong><br>
<img src="https://media.giphy.com/media/SKBC1cQ4CT90Y1xRou/giphy.gif" alt="X&#xE2;y D&#x1EF1;ng Layout &#x110;&#x1A1;n Gi&#x1EA3;n V&#x1EDB;i CSS Grid"></p>
<h3 id="phnfooter">Ph&#x1EA7;n Footer</h3>
<p>Ph&#x1EA7;n n&#xE0;y th&#xEC; kh&#xE1; l&#xE0; &#x111;&#x1A1;n gi&#x1EA3;n kh&#xF4;ng c&#xF3; g&#xEC; ph&#x1EE9;c t&#x1EA1;p c&#x1EA3; n&#xEA;n m&#xEC;nh s&#x1EBD; &#x111;i nhanh ph&#x1EA7;n n&#xE0;y nha. Tr&#x1B0;&#x1EDB;c ti&#xEA;n c&#xE1;c b&#x1EA1;n t&#x1EA1;o cho m&#xEC;nh m&#x1ED9;t th&#x1EBB; <strong>footer</strong> b&#xEA;n trong s&#x1EBD; ch&#x1EE9;a hai th&#x1EBB; div t&#x1B0;&#x1A1;ng &#x1EE9;ng v&#x1EDB;i hai n&#x1ED9;i dung trong footer, b&#xE2;y gi&#x1EDD; ta ch&#x1EC9; c&#x1EA7;n s&#x1EED; d&#x1EE5;ng <strong>grid</strong> v&#xE0; m&#x1ED9;t s&#x1ED1; thu&#x1ED9;c t&#xED;nh c&#x1EE7;a n&#xF3; l&#xE0; c&#xF3; th&#x1EC3; c&#xE2;n &#x111;&#x1B0;&#x1EE3;c footer r&#x1ED3;i hihi.<br>
<strong>Code HTML</strong></p>
<pre><code> &lt;!-- Footer --&gt;
    &lt;footer class=&quot;site-footer&quot;&gt;
        &lt;div class=&quot;site-footer-content posts&quot;&gt;
            &lt;section class=&quot;copyright&quot;&gt;
               &lt;a href=&quot;https://www.thanhlongdev.com&quot;&gt;Thanh Long Dev&lt;/a&gt; &#xA9; 2020
            &lt;/section&gt;
            &lt;div class=&quot;site-footer-nav&quot;&gt;
                &lt;a href=&quot;https://www.thanhlongdev.com&quot;&gt;Latest Posts&lt;/a&gt;
                &lt;a href=&quot;https://www.facebook.com/thanhlongdev/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Facebook&lt;/a&gt;
            &lt;/div&gt;
        &lt;/div&gt;
    &lt;/footer&gt;
</code></pre>
<p><strong>Code CSS</strong><br>
Ph&#x1EA7;n css n&#xE0;y ch&#x1EAF;c m&#xEC;nh h&#x1ED5;ng c&#x1EA7;n gi&#x1EA3;i th&#xED;ch g&#xEC; nh&#x1EDD; c&#xE1;c b&#x1EA1;n nh&#xEC;n v&#xE0;o ch&#x1EAF;c c&#x169;ng hi&#x1EC3;u &#x111;&#x1B0;&#x1EE3;c m&#xEC;nh &#x111;ang l&#xE0;m g&#xEC; r&#x1ED3;i.<br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1602263486/Untitled-2_xyjebl.png" alt="X&#xE2;y D&#x1EF1;ng Layout &#x110;&#x1A1;n Gi&#x1EA3;n V&#x1EDB;i CSS Grid"><br>
<strong>&#x110;&#xE2;y l&#xE0; k&#x1EBF;t qu&#x1EA3; khi ch&#xFA;ng ta &#x111;&#xE3; ho&#xE0;n th&#xE0;nh xong ph&#x1EA7;n footer:</strong><br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1602263918/12_rro2uz.png" width="700" alt="X&#xE2;y D&#x1EF1;ng Layout &#x110;&#x1A1;n Gi&#x1EA3;n V&#x1EDB;i CSS Grid"><br>
<em><strong>V&#xE0; &#x111;&#xE2;y l&#xE0; giao di&#x1EC7;n desktop khi ch&#xFA;ng ta &#x111;&#xE3; d&#x1EF1;ng xong layout &lt;3 &lt;3 &lt;3</strong></em><br>
<img src="https://media.giphy.com/media/MIzJLFwKNHUgzt37FL/giphy.gif" alt="X&#xE2;y D&#x1EF1;ng Layout &#x110;&#x1A1;n Gi&#x1EA3;n V&#x1EDB;i CSS Grid"></p>
<h3 id="reponsivelayoutgrid">Reponsive Layout Grid</h3>
<img src="https://media.giphy.com/media/ejIscsyDUvRQPhZ9IR/giphy.gif" alt="X&#xE2;y D&#x1EF1;ng Layout &#x110;&#x1A1;n Gi&#x1EA3;n V&#x1EDB;i CSS Grid">
<p><strong>&#x1EA2;nh &#x1EDF; tr&#xEA;n l&#xE0; giao di&#x1EC7;n mobile &amp; tablet khi m&#xEC;nh ch&#x1B0;a reponsive nha, nh&#xEC;n kinh vl kkkkk</strong><br>
C&#xE1;c b&#x1EA1;n t&#x1EA1;o cho m&#xEC;nh file reponsive nh&#x1EDB; l&#xE0; ph&#x1EA3;i import v&#xE0;o file <code>index.html</code> nha. N&#x1EBF;u m&#xE0; mu&#x1ED1;n reponsive th&#xEC; c&#xE1;c b&#x1EA1;n s&#x1EED; d&#x1EE5;ng thu&#x1ED9;c t&#xED;nh <strong>media query</strong> nha.<br>
&#x1EDE; &#x111;&#xE2;y m&#xEC;nh c&#xF3; so&#x1EA1;n s&#x1EB5;n c&#xE1;c media ph&#xF9; h&#x1EE3;p v&#x1EDB;i t&#x1EEB;ng lo&#x1EA1;i k&#xED;ch th&#x1B0;&#x1EDB;c v&#x1EDB;i nhau r&#x1ED3;i nha, c&#xE1;c b&#x1EA1;n ch&#x1EC9; c&#x1EA7;n copy paste r&#x1ED3;i sau &#x111;&#xF3; code th&#xF4;i nha.</p>
<pre><code>@media(min-width: 1366px){
// code here
}
@media(min-width:1200px) and (max-width:1365px){
// code here
}
@media(min-width:992px) and (max-width:1199px){
 // code here
}
@media(min-width:768px) and (max-width:992px){
  // code here
}
/* --------Tablet-------- */
@media (min-width:480px) and (max-width:768px){
 // code here
}
/* ---------Mobile-------- */
@media only screen and (min-width:240px) and (max-width:480px){
// code here
}
</code></pre>
<h4 id="reponsivegiaodinmobile">Reponsive Giao Di&#x1EC7;n Mobile</h4>
<p>B&#xE2;y gi&#x1EDD; ch&#xFA;ng s&#x1EBD; reponsive t&#x1EEB; tr&#xEA;n xu&#x1ED1;ng d&#x1B0;&#x1EDB;i t&#x1EEB; ngo&#xE0;i v&#xE0;o trong, t&#x1EEB; trong ra ngo&#xE0;i t&#x1EEB; header &#x111;&#x1EBF;n footer =))))</p>
<ul>
<li>Th&#x1EE9; nh&#x1EA5;t trong ph&#x1EA7;n heder b&#x1EA1;n &#x1EA9;n cho m&#xEC;nh th&#x1EB1;ng nav-right.</li>
<li>Th&#x1EE9; hai trong ph&#x1EA7;n main m&#xEC;nh mu&#x1ED1;n c&#xE1;c b&#xE0;i topic ch&#x1EC9; hi&#x1EC3;n th&#x1ECB; m&#x1ED9;t c&#x1ED9;t duy nh&#x1EA5;t.</li>
<li>Th&#x1EE9; ba ph&#x1EA7;n footer m&#xEC;nh s&#x1EBD; canh ch&#x1EC9;nh cho n&#xF3; &#x1EDF; gi&#x1EEF;a.<br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1602325501/12_lmmlia.png" width="700" alt="X&#xE2;y D&#x1EF1;ng Layout &#x110;&#x1A1;n Gi&#x1EA3;n V&#x1EDB;i CSS Grid"></li>
</ul>
<h4 id="reponsivegiaodintablet">Reponsive Giao Di&#x1EC7;n Tablet</h4>
<p>Trong ph&#x1EA7;n n&#xE0;y th&#xEC; c&#x169;ng kh&#xE1; &#x111;&#x1A1;n gi&#x1EA3;n, ch&#xFA;ng ta ch&#x1EC9; c&#x1EA7;n reponsive ph&#x1EA7;n main l&#xE0; xong r&#x1ED3;i.</p>
<ul>
<li>Ph&#x1EA7;n main c&#x1EE7;a tablet n&#xE0;y m&#xEC;nh mu&#x1ED1;n c&#xE1;c b&#xE0;i topic ch&#x1EC9; hi&#x1EC3;n th&#x1ECB; m&#x1ED9;t c&#x1ED9;t duy nh&#x1EA5;t gi&#x1ED1;ng nh&#x1B0; ph&#x1EA7;n main trong mobile v&#x1EAD;y.<br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1602326261/12_m8u4l2.png" alt="X&#xE2;y D&#x1EF1;ng Layout &#x110;&#x1A1;n Gi&#x1EA3;n V&#x1EDB;i CSS Grid"><br>
<strong>V&#xE0; &#x111;&#xE2;y l&#xE0; giao di&#x1EC7;n Mobile &amp; Tablet m&#xE0; m&#xEC;nh &#x111;&#xE3; reponsive nha:</strong><br>
<img src="https://media.giphy.com/media/pVMpuqFJyAQIX5GMcv/giphy.gif" alt="X&#xE2;y D&#x1EF1;ng Layout &#x110;&#x1A1;n Gi&#x1EA3;n V&#x1EDB;i CSS Grid"><br>
<strong>&#xD4;i Vui Qu&#xE1; Cu&#x1ED1;i C&#xF9;ng C&#x169;ng Xong R&#x1ED3;i hihihi</strong><br>
C&#xE1;c b&#x1EA1;n tham kh&#x1EA3;o trang homepage thanhlongdev m&#xE0; m&#xEC;nh &#x111;&#xE3; deploy l&#xEA;n firebase <a href="https://layout-css-grid-1d25a.web.app/">t&#x1EA1;i &#x111;&#xE2;y nha</a></li>
</ul>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h1 id="likt">L&#x1EDD;i K&#x1EBF;t</h1>
<p>V&#x1EAD;y l&#xE0; xong b&#xE0;i X&#xE2;y D&#x1EF1;ng Layout &#x110;&#x1A1;n Gi&#x1EA3;n V&#x1EDB;i CSS Grid. M&#xEC;nh mong mu&#x1ED1;n sau khi c&#xE1;c b&#x1EA1;n ho&#xE0;n th&#xE0;nh xong project n&#xE0;y s&#x1EBD; hi&#x1EC3;u v&#xE0; n&#x1EAF;m r&#xF5; h&#x1A1;n v&#x1EC1; grid, flex v&#xE0; c&#xE1;ch ph&#xE2;n t&#xED;ch t&#x1EEB;ng component. C&#xE1;c b&#x1EA1;n c&#xF3; th&#x1EC3; d&#x1EF1;a v&#xE0;o project n&#xE0;y &#x111;&#x1EC3; c&#xF3; th&#x1EC3; ph&#xE1;t tri&#x1EC3;n v&#xE0; scale project n&#xE0;y l&#x1EDB;n h&#x1A1;n n&#x1EEF;a nha.<br>
<strong>C&#xE1;c b&#x1EA1;n nh&#x1EDB; like v&#xE0; theo d&#xF5;i fanpage <a href="https://www.facebook.com/thanhlongdev/">Thanh Long Dev</a> &#x111;&#x1EC3; nh&#x1EAD;n nh&#x1EEF;ng th&#xF4;ng b&#xE1;o v&#x1EC1; b&#xE0;i vi&#x1EBF;t m&#x1EDB;i nh&#x1EA5;t nha.</strong><br>
<em><strong>N&#x1EBF;u c&#xE1;c b&#x1EA1;n c&#x1EA3;m th&#x1EA5;y b&#xE0;i vi&#x1EBF;t c&#x1EE7;a m&#xEC;nh hay th&#xEC; c&#xE1;c b&#x1EA1;n c&#xF3; th&#x1EC3; &#x1EE7;ng h&#x1ED9; m&#xEC;nh &#x111;&#x1EC3; m&#xEC;nh c&#xF3; th&#xEA;m &#x111;&#x1ED9;ng l&#x1EF1;c &#x111;&#x1EC3; ra nh&#x1EEF;ng b&#xE0;i topic hay v&#xE0; ch&#x1EA5;t l&#x1B0;&#x1EE3;ng h&#x1A1;n &#x1EE7;ng h&#x1ED9; m&#xEC;nh <a href="https://vrdonate.vn/thanhlongdev">t&#x1EA1;i &#x111;&#xE2;y nha.</a></strong></em><br>
<strong>Ch&#xFA;c C&#xE1;c B&#x1EA1;n Th&#xE0;nh C&#xF4;ng!!</strong></p>
<!--kg-card-end: markdown--><!--kg-card-begin: html--><iframe src="https://www.facebook.com/plugins/like.php?href=https%3A%2F%2Fwww.thanhlongdev.com%2Fxay-dung-layout-don-gian-css-grid%2F&amp;width=450&amp;layout=standard&amp;action=like&amp;size=large&amp;share=true&amp;height=35&amp;appId=2794898430534168" width="450" height="35" style="border:none;overflow:hidden" scrolling="no" frameborder="0" allowtransparency="true" allow="encrypted-media"></iframe><!--kg-card-end: html--><!--kg-card-begin: html--><div class="fb-comments" data-href="https://www.thanhlongdev.com/xay-dung-layout-don-gian-css-grid/" data-width="100%" data-numposts="10"></div><!--kg-card-end: html-->]]></content:encoded></item><item><title><![CDATA[Hướng Dẫn Xây Dựng Books Store Với NodeJS, Express và MongoDB - Phần 4]]></title><description><![CDATA[<!--kg-card-begin: markdown--><h2 id="chcnnghinthchititcpnhtvxabooks">Ch&#x1EE9;c N&#x103;ng Hi&#x1EC3;n Th&#x1ECB; Chi Ti&#x1EBF;t, C&#x1EAD;p Nh&#x1EAD;t V&#xE0; X&#xF3;a Books</h2>
<h3 id="nhnghavcontrollerrouterhinthchitittrongbooks">&#x110;&#x1ECB;nh Ngh&#x129;a V&#xE0; Controller Router Hi&#x1EC3;n Th&#x1ECB; Chi Ti&#x1EBF;t Trong Books</h3>
<p>M&#xEC;</p>]]></description><link>https://www.thanhlongdev.com/huong-dan-xay-dung-books-store-voi-nodejs-express-va-mongodb-phan4/</link><guid isPermaLink="false">5f4f0ae9ae21b200015abc6e</guid><category><![CDATA[Lập Trình Web]]></category><dc:creator><![CDATA[Đặng Thanh Long]]></dc:creator><pubDate>Fri, 11 Sep 2020 19:13:08 GMT</pubDate><media:content url="https://digitalpress.fra1.cdn.digitaloceanspaces.com/4tg23ij/2020/09/33.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h2 id="chcnnghinthchititcpnhtvxabooks">Ch&#x1EE9;c N&#x103;ng Hi&#x1EC3;n Th&#x1ECB; Chi Ti&#x1EBF;t, C&#x1EAD;p Nh&#x1EAD;t V&#xE0; X&#xF3;a Books</h2>
<h3 id="nhnghavcontrollerrouterhinthchitittrongbooks">&#x110;&#x1ECB;nh Ngh&#x129;a V&#xE0; Controller Router Hi&#x1EC3;n Th&#x1ECB; Chi Ti&#x1EBF;t Trong Books</h3>
<img src="https://digitalpress.fra1.cdn.digitaloceanspaces.com/4tg23ij/2020/09/33.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Books Store V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB - Ph&#x1EA7;n 4"><p>M&#xEC;nh s&#x1EBD; n&#xF3;i s&#x1A1; qua m&#x1ED9;t ch&#xFA;t v&#x1EC1; nguy&#xEA;n l&#xED; ho&#x1EA1;t &#x111;&#x1ED9;ng c&#x1EE7;a th&#xE8;n n&#xE0;y t&#xED; nha ^^.<br>
&#x110;&#x1EC3; hi&#x1EC3;n th&#x1ECB; chi ti&#x1EBF;t(show detail) books th&#xEC; ch&#x1EC9; c&#xF3; c&#xE1;ch l&#xE0; l&#x1EA5;y id c&#x1EE7;a books &#x111;&#xF3; r&#x1ED3;i render ra c&#xE1;c fields nh&#x1B0;: title, desc, author,...<br>
<strong>B&#x1EAF;t &#x111;&#x1EA7;u code th&#xF4;i n&#xE0;o</strong><br>
Nh&#x1B0; c&#xE1;c b&#x1EA1;n &#x111;&#xE3; bi&#x1EBF;t th&#xEC; trong ph&#x1EA7;n 2 m&#xEC;nh &#x111;&#xE3; l&#xE0;m ch&#x1EE9;c n&#x103;ng t&#x1EA1;o books trong &#x111;&#xF3; m&#xEC;nh &#x111;&#xE3; c&#xF3; t&#x1EA1;o m&#x1ED9;t th&#x1EBB; li&#xEA;n k&#x1EBF;t a tr&#x1B0;&#x1EDB;c r&#x1ED3;i. M&#x1EE5;c &#x111;&#xED;ch l&#xE0; khi click v&#xE0;o &#x111;&#x1EA5;y th&#xEC; s&#x1EBD; show detail books.<br>
Khi c&#xE1;c b&#x1EA1;n v&#xE0;o trong <code>views</code> c&#xF3; file <strong>books/index.pug</strong> th&#xEC; s&#x1EBD; th&#x1EA5;y m&#x1ED9;t th&#x1EBB; a &#x111;&#x1B0;&#x1EE3;c t&#x1EA1;o s&#x1EB5;n r&#x1ED3;i.</p>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1599274022/12_aarmcm.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Books Store V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB - Ph&#x1EA7;n 4">
<p>C&#x169;ng trong file <code>books.routes.js</code> ta s&#x1EBD; t&#x1EA1;o m&#x1ED9;t router <strong>router.get(&apos;/:id,...)</strong>, trong router n&#xE0;y s&#x1EBD; l&#xE0; n&#x1A1;i m&#xE0; ch&#xFA;ng ta d&#xF9;ng &#x111;&#x1EC3; show detail b&#x1EB1;ng c&#xE1;ch s&#x1EED; d&#x1EE5;ng id c&#x1EE7;a ch&#xFA;ng.<br>
Tr&#x1B0;&#x1EDB;c ti&#xEA;n ta s&#x1EBD; d&#x1EF1;a v&#xE0;o id c&#x1EE7;a books &#x111;&#x1EC3; l&#x1EA5;y data c&#x1EE7;a books r&#x1ED3;i render data &#x111;&#xF3; ra th&#xF4;i. Populate n&#xE0;y gi&#xFA;p ch&#xFA;ng ta t&#xEC;m &#x111;&#x1B0;&#x1EE3;c t&#xEA;n t&#xE1;c gi&#x1EA3; th&#xEC; c&#x1EA7;n ph&#x1EA3;i truy v&#x1EA5;n v&#xE0;o document c&#x1EE7;a ch&#xFA;ng, c&#xE1;c b&#x1EA1;n t&#xEC;m hi&#x1EC3;u th&#xEA;m <a href="https://mongoosejs.com/docs/api.html#query_Query-populate">t&#x1EA1;i &#x111;&#xE2;y nha</a> v&#xE0; <a href="https://mongoosejs.com/docs/populate.html#population">&#x111;&#xE2;y n&#x1EEF;a nha</a></p>
<pre><code>// Show Details Books
router.get(&apos;/:id&apos;, async (req, res, next) =&gt; {
    try {
       // find data m&#x1ED9;t books d&#x1EF1;a v&#xE0;o id
        const book = await Book.findById(req.params.id).populate(&apos;author&apos;).exec();
        res.render(&apos;books/show&apos;, {
            book: book
        })
    } catch {
        res.redirect(&apos;/&apos;)
    }
})
</code></pre>
<p><strong>M&#xEC;nh s&#x1EBD; log ra data books khi click v&#xE0;o books &#x111;&#x1EC3; show detail &#x111;&#x1EC3; cho c&#xE1;c b&#x1EA1;n d&#x1EC5; hi&#x1EC3;u nha</strong></p>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1599325131/12_b7avta.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Books Store V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB - Ph&#x1EA7;n 4">
<h3 id="giaodinhinthchitittrongbooks">Giao Di&#x1EC7;n Hi&#x1EC3;n Th&#x1ECB; Chi Ti&#x1EBF;t Trong Books</h3>
<p>Trong views b&#x1EA1;n t&#x1EA1;o cho m&#xEC;nh th&#x1B0; m&#x1EE5;c l&#xE0; <strong>books</strong> s&#x1EBD; bao g&#x1ED3;m 4 file <code>index.pug</code>, <code>new.pug</code>, <code>show.pug</code>, <code>edit.pug</code>.<br>
Tr&#x1B0;&#x1EDB;c ti&#xEA;n c&#xE1;c b&#x1EA1;n nh&#x1EDB; extends layout v&#xE0;o nha sau &#x111;&#xF3; ch&#xFA;ng ta c&#x1EA7;n hi&#x1EC3;n th&#x1ECB; nh&#x1EEF;ng th&#xF4;ng tin c&#x1EA7;n thi&#x1EBF;t c&#x1EE7;a m&#x1ED9;t books nh&#x1B0;: Cover image, title, author,... Khi ch&#xFA;ng ta findById c&#x1EE7;a books th&#xEC; n&#xF3; ch&#x1EC9; find m&#x1ED9;t books c&#xF3; id m&#xE0; n&#xF3; &#x111;ang t&#xEC;m n&#xEA;n kh&#xF4;ng c&#x1EA7;n ph&#x1EA3;i l&#x1EB7;p qua r&#x1ED3;i hi&#x1EC3;n th&#x1ECB; data. C&#xE1;c b&#x1EA1;n &#x111;&#x1EC3; &#xFD; &#x1EDF; d&#x1B0;&#x1EDB;i th&#xEC; s&#x1EBD; th&#x1EA5;y m&#x1ED9;t th&#x1EBB; a v&#x1EDB;i t&#xEA;n l&#xE0; view author &#x111;&#x1EC3; khi click v&#xE0;o &#x111;&#x1EA5;y n&#xF3; s&#x1EBD; &#x111;&#x1B0;a ch&#xFA;ng ta &#x111;&#x1EBF;n trang show detail c&#x1EE7;a author m&#xE0; &#x111;&#xE3; t&#x1EA1;o books &#x111;&#x1EA5;y.</p>
<p>&#x1EDE; &#x111;&#xE2;y c&#xE1;c b&#x1EA1;n t&#x1EA1;o h&#x1EB3;n lu&#xF4;n cho m&#xEC;nh m&#x1ED9;t th&#x1EBB; div &#x111;&#x1EC3; bao b&#x1ECD;c nh&#x1EEF;ng ch&#x1EE9;c n&#x103;ng nh&#x1B0;: view author, delete, edit books. C&#xE1;c b&#x1EA1;n c&#x169;ng bi&#x1EBF;t m&#x1EE5;c &#x111;&#xED;ch c&#x1EE7;a n&#xF3; l&#xE0; l&#xE0;m g&#xEC; r&#x1ED3;i &#x111;&#x1EA5;y, t&#x1EA1;o lu&#xF4;n cho r&#x1ED3;i t&#xED; n&#x1EEF;a l&#xE0;m m&#x1EA5;y ph&#x1EA7;n d&#x1B0;&#x1EDB;i &#x111;&#x1EE1; t&#x1ED1;n th&#x1EDD;i gian =)))</p>
<p><strong>books/show.pug</strong></p>
<pre><code>extends ../layouts/layout
block content
   .container

       ul
          li
            a(href=&quot;&quot;) 
              img(src=book.ImageUrl, width=&quot;250&quot; height=&quot;280&quot;)
          li Title:&amp;nbsp;
            = book.title
          li Author:&amp;nbsp;
            = book.author.name  
          li Description:&amp;nbsp;
            = book.description
          li PageCount:&amp;nbsp;
            = book.pageCount
          li publishDate:&amp;nbsp;
            = book.publishDate.toDateString()
       div    
          a(href=&apos;/books/&apos; + book.id +&apos;/edit&apos;) Edit
          form(method=&quot;POST&quot; action=&quot;/books/&quot; + book.id + &quot;?_method=DELETE&quot;)
               button(type=&apos;submit&apos;) Delete            
          a(href=&apos;/authors/&apos; + book.author.id) View Author      
</code></pre>
<p><strong>V&#xE0; &#x111;&#xE2;y l&#xE0; k&#x1EBF;t qu&#x1EA3; khi ch&#xFA;ng ta show detail books nha:</strong></p>
<img src="https://media.giphy.com/media/PnrQsIoVkdC9G39ZC3/giphy.gif" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Books Store V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB - Ph&#x1EA7;n 4">
<h3 id="nhngharoutercpnhttrongbooks">&#x110;&#x1ECB;nh Ngh&#x129;a Router C&#x1EAD;p Nh&#x1EAD;t Trong Books</h3>
<p>Th&#xEC; th&#xE8;n c&#x1EAD;p nh&#x1EAD;t n&#xE0;y c&#xE1;ch l&#xE0;m n&#xF3; c&#x169;ng t&#x1EF1;a t&#x1EF1;a nh&#x1B0; t&#x1EA1;o books th&#xF4;i ch&#x1EC9; kh&#xE1;c l&#xE0; thay v&#xEC; s&#x1EBD; t&#x1EA1;o m&#x1ED9;t c&#xE1;i m&#x1EDB;i th&#xEC; ta s&#x1EBD; l&#x1EA5;y id c&#x1EE7;a books &#x111;&#x1EA5;y &#x111;&#x1EC3; m&#xE0; edit l&#x1EA1;i th&#xF4;ng tin m&#xE0; m&#xEC;nh &#x111;&#xE3; t&#x1EA1;o.<br>
&#x110;&#x1EC3; m&#xE0; show detail &#x111;&#x1B0;&#x1EE3;c ch&#xFA;ng ta ph&#x1EA3;i d&#x1EF1;a v&#xE0;o id c&#x1EE7;a author, th&#xEC; update books c&#x169;ng t&#x1B0;&#x1A1;ng t&#x1EF1; v&#x1EAD;y th&#xF4;i nha.<br>
<strong>B&#x1EAF;t &#x111;&#x1EA7;u code th&#xF4;i n&#xE0;o</strong><br>
Nh&#x1B0; c&#xE1;c b&#x1EA1;n &#x111;&#xE3; th&#x1EA5;y &#x1EDF; tr&#xEA;n khi m&#xEC;nh show detail books th&#xEC; trong ph&#x1EA7;n hi&#x1EC3;n th&#x1ECB; chi ti&#x1EBF;t m&#xEC;nh &#x111;&#xE3; t&#x1EA1;o m&#x1ED9;t th&#x1EBB; li&#xEA;n k&#x1EBF;t a v&#x1EDB;i t&#xEA;n l&#xE0; edit &#x111;&#x1EC3; khi click v&#xE0;o &#x111;&#x1EA5;y s&#x1EBD; chuy&#x1EC3;n &#x111;&#x1EBF;n m&#x1ED9;t trang edit books.</p>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1599449214/12_c6yykr.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Books Store V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB - Ph&#x1EA7;n 4">
<p>Trong th&#x1B0; m&#x1EE5;c <strong>routes</strong> c&#xF3; file <code>books.routes.js</code> c&#xE1;c b&#x1EA1;n t&#x1EA1;o cho m&#xEC;nh hai router update &#x111;&#xF3; l&#xE0; <code>router.get(&apos;/:id/edit&apos;,...)</code> &#x111;&#x1EC3; render ra views v&#xE0; <code>router.put(&apos;/:id&apos;,...)</code>  &#x111;&#x1EC3; c&#x1EAD;p nh&#x1EAD;t books nha. Tr&#x1B0;&#x1EDB;c m&#x1EAF;t c&#xE1;c b&#x1EA1;n ch&#x1EC9; c&#x1EA7;n t&#x1EA1;o v&#xE0; render ra views tr&#x1B0;&#x1EDB;c cho m&#xEC;nh l&#xE0; &#x111;&#x1B0;&#x1EE3;c.</p>
<pre><code>// Get Update Books
router.get(&apos;/:id/edit&apos;, async (req, res, next) =&gt; {
    try {
        const book = await Book.findById(req.params.id) // find m&#x1ED9;t book trong DB d&#x1EF1;a v&#xE0;o id c&#x1EE7;a book &#x111;&#xF3;
        const authors = await Author.find() // find data author trong DB
        
       // Truy&#x1EC1;n data authors, book v&#xE0;o views &#x111;&#x1EC3; c&#xF3; th&#x1EC3; &#x111;&#x1ECB;nh ngh&#x129;a v&#xE0; render &#x111;&#x1B0;&#x1EE3;c n&#xF3; ra trong view
        res.render(&apos;books/edit&apos;, {
            authors: authors, 
            book: book
        })
    } catch {
        res.redirect(&apos;/books&apos;)
    }
})

// Update Books
router.put(&apos;/:id&apos;, async (req, res, next) =&gt; {
  
})
</code></pre>
<h3 id="giaodincpnhttrongbooks">Giao Di&#x1EC7;n C&#x1EAD;p Nh&#x1EAD;t Trong Books</h3>
<p>Trong views b&#x1EA1;n t&#x1EA1;o cho m&#xEC;nh th&#x1B0; m&#x1EE5;c l&#xE0; <strong>books</strong> s&#x1EBD; bao g&#x1ED3;m 4 file <code>index.pug</code>, <code>new.pug</code>, <code>show.pug</code>, <code>edit.pug</code>.<br>
&#x1EDE; &#x111;&#xE2;y th&#xEC; n&#xF3;i th&#x1EAD;t th&#xEC; n&#xF3; ch&#x1EA3; kh&#xE1;c g&#xEC; t&#x1EA1;o books c&#x1EA3; ch&#x1EC9; kh&#xE1;c l&#xE0; action trong form n&#xF3; s&#x1EBD; thay &#x111;&#x1ED5;i &#x111;&#x1EC3; ph&#xF9; h&#x1EE3;p v&#x1EDB;i ch&#x1EE9;c n&#x103;ng m&#xEC;nh &#x111;ang s&#x1EED; d&#x1EE5;ng th&#xF4;i nha.<br>
<strong>L&#x1B0;u &#xFD;:</strong> C&#xE1;c b&#x1EA1;n &#x111;&#x1EC3; &#xFD; th&#xEC; s&#x1EBD; th&#x1EA5;y c&#xE1;c fields t&#x1EA1;o v&#xE0; c&#x1EAD;p nh&#x1EAD;t books n&#xF3; gi&#x1ED1;ng nhau &#x111;&#xFA;ng kh&#xF4;ng n&#xE0;o, b&#xE2;y gi&#x1EDD; c&#xE1;c b&#x1EA1;n t&#x1EA1;o m&#x1ED9;t file s&#x1EBD; ch&#x1EE9;a c&#xE1;c fields &#x111;&#xF3; &#x111;&#x1EC3; khi c&#x1EA7;n b&#x1EA1;n c&#xF3; th&#x1EC3; t&#xE1;i s&#x1EED; d&#x1EE5;ng l&#x1EA1;i &#x111;&#x1B0;&#x1EE3;c nha.<br>
<strong>books/edit.pug</strong></p>
<pre><code>extends ../layouts/layout
block content
   .container  

      h2 Edit Books
      form( action=&quot;/books/&quot; + book.id + &quot;?_method=PUT&quot; method=&quot;POST&quot;  enctype=&quot;multipart/form-data&quot;)
        div
          div
            label(for=&quot;name&quot; ) Title
            input(placeholder=&quot;Title&quot;, type=&quot;text&quot; name=&quot;title&quot; value=book.title )
          div   
            label(for=&quot;author&quot;) Author
            select(name=&quot;author&quot;)
              each author in authors 
                if author.id === book.author
                  option(selected label=author.name, value=author.id)
                else
                  option( label=author.name, value=author.id)
        div
          div
            label(for=&quot;publish date&quot;) Publish Date
            input(type=&quot;date&quot; name=&quot;publishDate&quot; 
                        value= book.publishDate == null ? &apos;&apos; :
                        book.publishDate.toISOString().split(&apos;T&apos;)[0])

          div
            label(for=&quot;page count&quot;) Page Count 
            input(placeholder=&quot;Page Count&quot;,type=&quot;number&quot; name=&quot;pageCount&quot; min=&quot;1&quot; value= book.pageCount )                
        div
          div
            label(for=&quot;coverImg&quot;) Image Cover
            input(type=&quot;file&quot; name=&quot;ImageUrl&quot; required)                
      
          div
          label(for=&quot;description&quot;) Description
          textarea(name=&quot;description&quot;, book.description )    
        div
            a(href=&quot;/books&quot;) Cancel
            button(type=&quot;submit&quot;) Update
</code></pre>
<p><strong>V&#xE0; &#x111;&#xE2;y l&#xE0; giao di&#x1EC7;n &#x111;&#x1EC3; c&#x1EAD;p nh&#x1EAD;t books:</strong></p>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1599449401/12_zsdjfd.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Books Store V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB - Ph&#x1EA7;n 4">
<h3 id="controllercpnhttrongbooks">Controller C&#x1EAD;p Nh&#x1EAD;t Trong Books</h3>
<p>&#x110;&#x1EC3; c&#xF3; th&#x1EC3; c&#x1EAD;p nh&#x1EAD;t &#x111;&#x1B0;&#x1EE3;c books v&#xE0; s&#x1EED; d&#x1EE5;ng &#x111;&#x1B0;&#x1EE3;c ph&#x1B0;&#x1A1;ng th&#x1EE9;c <em>PUT</em> ta c&#x1EA7;n s&#x1EED; d&#x1EE5;ng m&#x1ED9;t middleware &#x111;&#xF3; l&#xE0; <strong>method override</strong>.<br>
Trong <code>views</code> c&#xF3; file <strong>books/edit.pug</strong> c&#xE1;c b&#x1EA1;n th&#xEA;m cho m&#xEC;nh &#x111;o&#x1EA1;n m&#xE3; n&#xE0;y <code>&quot;?_method=PUT&quot;</code> v&#xE0;o trong action c&#x1EE7;a form c&#xE1;i n&#xE0;y m&#xEC;nh &#x111;&#xE3; th&#xEA;m v&#xE0;o ph&#x1EA7;n action ph&#xED;a tr&#xEA;n r&#x1ED3;i nha</p>
<p>Trong file <code>books.routes.js</code> ta c&#xF3; <strong>router.put(&apos;/:id&apos;,...)</strong> d&#xF9;ng &#x111;&#x1EC3; update books. &#x1EDE; &#x111;&#xE2;y m&#xEC;nh s&#x1EBD; h&#xF4;ng gi&#x1EA3;i th&#xED;ch d&#xE0;i d&#xF2;ng n&#x1EEF;a nha b&#x1EDF;i v&#xEC; t&#x1EA1;o books nh&#x1B0; n&#xE0;o th&#xEC; c&#x1EAD;p books nh&#x1B0; v&#x1EAD;y th&#xF4;i :))</p>
<pre><code>// Update Books
router.put(&apos;/:id&apos;, upload.single(&apos;ImageUrl&apos;), async (req, res, next) =&gt; {
    const result = await cloudinary.v2.uploader.upload(req.file.path)
    const authors = await Author.find()
    let book
    try {
        book = await Book.findById(req.params.id) // find m&#x1ED9;t book d&#x1EF1;a v&#xE0;o id v&#xE0; edit l&#x1EA1;i book
            book.title = req.body.title,
            book.author = req.body.author,
            book.publishDate = new Date(req.body.publishDate),
            book.pageCount = req.body.pageCount,
            book.description = req.body.description,
            book.ImageUrl = result.secure_url
        await book.save()

        res.redirect(&apos;/books&apos;)

    } catch {
        res.render(&apos;books/edit&apos;, {
            authors: authors,
            book: book,
            errorMessage: &apos;Error Updating Book&apos;
        })
    }
})
</code></pre>
<p>N&#x1EBF;u m&#xE0; c&#xF3; l&#x1ED7;i khi c&#x1EAD;p nh&#x1EAD;t books th&#xEC; trong <strong>books/edit.pug</strong> c&#xE1;c b&#x1EA1;n th&#xEA;m d&#xF2;ng code &#x1EDF; d&#x1B0;&#x1EDB;i v&#xE0;o ph&#xED;a sau th&#x1EBB; <em>h2 Edit Books</em> &#x111;&#x1EC3; hi&#x1EC3;n th&#x1ECB; th&#xF4;ng b&#xE1;o l&#x1ED7;i nha.</p>
<pre><code>    if locals.errorMessage
        = errorMessage
</code></pre>
<p><strong>V&#xE0; &#x111;&#xE2;y l&#xE0; k&#x1EBF;t qu&#x1EA3; khi ch&#xFA;ng ta c&#x1EAD;p nh&#x1EAD;t books:</strong></p>
<img src="https://media.giphy.com/media/LmxDhC96m6MQ0eI8ZM/giphy.gif" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Books Store V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB - Ph&#x1EA7;n 4">
<h3 id="nhnghavcontrollerrouterxatrongbooks">&#x110;&#x1ECB;nh Ngh&#x129;a V&#xE0; Controller Router X&#xF3;a Trong Books</h3>
<p>Nh&#x1B0; c&#xE1;c b&#x1EA1;n &#x111;&#xE3; th&#x1EA5;y &#x1EDF; tr&#xEA;n khi m&#xEC;nh show detail th&#xEC; trong ph&#x1EA7;n hi&#x1EC3;n th&#x1ECB; chi ti&#x1EBF;t m&#xEC;nh &#x111;&#xE3; t&#x1EA1;o m&#x1ED9;t form c&#xF3; ch&#x1EE9;a m&#x1ED9;t button &#x111;&#x1EC3; x&#xF3;a books</p>
<p>C&#x169;ng trong file <code>books.routes.js</code> ta c&#xF3; <strong>router.delete(&apos;/:id&apos;,...)</strong> d&#xF9;ng &#x111;&#x1EC3; x&#xF3;a books. X&#xF3;a book v&#x1EDB;i x&#xF3;a author theo nguy&#xEA;n l&#xED; n&#xF3; c&#x169;ng kh&#xF4;ng kh&#xE1;c g&#xEC; nhau n&#xEA;n m&#xEC;nh s&#x1EBD; kh&#xF4;ng gi&#x1EA3;i th&#xED;ch th&#xEA;m n&#x1EEF;a. N&#xF3; ch&#x1EC9; kh&#xE1;c &#x1EDF; ch&#x1ED7; l&#xE0; khi x&#xF3;a author th&#xEC; books m&#xE0; &#x111;&#x1B0;&#x1EE3;c author s&#x1EBD; b&#x1ECB; x&#xF3;a, c&#xF2;n khi x&#xF3;a books th&#xEC; author n&#xF3; v&#x1EAB;n hi&#x1EC3;n th&#x1ECB; b&#xEC;nh th&#x1B0;&#x1EDD;ng.</p>
<pre><code>// Delete Books
router.delete(&apos;/:id&apos;, async (req, res, next) =&gt; {
    let book
    try {
        book = await Book.findById(req.params.id) // find m&#x1ED9;t book d&#x1EF1;a v&#xE0;o id
        await book.remove() // X&#xF3;a book trong DB
        res.redirect(&apos;/books&apos;)// chuy&#x1EC3;n h&#x1B0;&#x1EDB;ng sang trang /books n&#x1EBF;u x&#xF3;a th&#xE0;nh c&#xF4;ng
    } catch {      
          res.redirect(`/books/${book.id}`) 
    }
})
</code></pre>
<p>Trong <code>views</code> c&#xF3; file <strong>books/show.pug</strong> c&#xE1;c b&#x1EA1;n th&#xEA;m cho m&#xEC;nh &#x111;o&#x1EA1;n m&#xE3; n&#xE0;y <code>&quot;?_method=DELETE&quot;</code> v&#xE0;o trong action c&#x1EE7;a form c&#xE1;i n&#xE0;y m&#xEC;nh &#x111;&#xE3; th&#xEA;m v&#xE0;o ph&#x1EA7;n action trong ph&#x1EA7;n show detail &#x1EDF; ph&#xED;a tr&#xEA;n r&#x1ED3;i nha.<br>
<strong>V&#xE0; &#x111;&#xE2;y l&#xE0; k&#x1EBF;t qu&#x1EA3; khi ch&#xFA;ng ta th&#x1EF1;c hi&#x1EC7;n x&#xF3;a books nha:</strong></p>
<img src="https://media.giphy.com/media/WUIxSyZSTkm4yTJmCM/giphy.gif" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Books Store V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB - Ph&#x1EA7;n 4">
<h2 id="hinthtranghomepage">Hi&#x1EC3;n Th&#x1ECB; Trang HomePage</h2>
<h3 id="nhnghavcontrollerroutertranghomepage">&#x110;&#x1ECB;nh Ngh&#x129;a V&#xE0; Controller Router Trang HomePage</h3>
<p>Trong <code>router</code> c&#xF3; file <code>index.routes.js</code>&#x1EDF; &#x111;&#xE2;y c&#xE1;c b&#x1EA1; t&#x1EA1;o cho m&#xEC;nh m&#x1ED9;t <strong>router.get(&apos;/&apos;,...)</strong> &#x111;&#x1EC3; c&#xF3; th&#x1EC3; get data v&#xE0; hi&#x1EC3;n th&#x1ECB; ra trang homepage. T&#x1EA1;i trang homepage n&#xE0;y m&#x1EE5;c &#x111;&#xED;ch c&#x1EE7;a n&#xF3; ch&#x1EC9; l&#xE0; hi&#x1EC3;n th&#x1ECB; books m&#xE0; th&#xF4;i.<br>
&#x110;&#x1EA7;u ti&#xEA;n c&#xE1;c b&#x1EA1;n c&#x1EA7;n require model books v&#xE0;o tr&#x1B0;&#x1EDB;c nha, sau &#x111;&#xF3; ch&#xFA;ng ta s&#x1EBD; find to&#xE0;n b&#x1ED9; data books d&#x1EF1;a v&#xE0;o th&#x1EDD;i gian t&#x1EA1;o m&#xE0; n&#xF3; s&#x1EBD; hi&#x1EC3;n th&#x1ECB; ra tr&#x1B0;&#x1EDB;c hay l&#xE0; sau nha.</p>
<pre><code>const Book = require(&quot;../models/books.model&quot;)

// Home page
router.get(&apos;/&apos;, async (req, res, next) =&gt; {
  let books
  try {
    // find books &#x111;&#x1B0;&#x1EE3;c s&#x1EAF;p x&#x1EBF;p theo th&#x1EE9; t&#x1EF1; books n&#xE0;o t&#x1EA1;o tr&#x1B0;&#x1EDB;c books n&#xE0;o t&#x1EA1;o sau v&#xE0; ch&#x1EC9; gi&#x1EDB;i h&#x1EA1;n hi&#x1EC3;n th&#x1ECB; 20 books th&#xF4;i nha
    books = await Book.find().sort({createdAt: &apos;desc&apos;}).limit(20).exec() 
  } catch {
    books = []
  }
  res.render(&apos;index&apos;, {
    books: books  // Truy&#x1EC1;n data books v&#xE0;o views &#x111;&#x1EC3; render ra d&#x1EEF; li&#x1EC7;u
  });
})
</code></pre>
<h3 id="giaodinhinthtranghomepage">Giao Di&#x1EC7;n Hi&#x1EC3;n Th&#x1ECB; Trang HomePage</h3>
<p>Trong <code>views</code> c&#xF3; file <strong>index.pug</strong> s&#x1EBD; l&#xE0; n&#x1A1;i m&#xE0; ch&#xFA;ng s&#x1EBD; code ph&#x1EA7;n view cho trang homepage. &#x110;&#x1EC3; hi&#x1EC3;n th&#x1ECB; ra books th&#xEC; c&#x169;ng &#x111;&#x1A1;n gi&#x1EA3;n th&#xF4;i ta ch&#x1EC9; c&#x1EA7;n l&#x1EB7;p qua ch&#xFA;ng r&#x1ED3;i render ra &#x1EA3;nh b&#xEC;a k&#xE8;m theo ti&#xEA;u &#x111;&#x1EC1;, sau khi l&#x1EB7;p qua c&#xE1;c books r&#x1ED3;i th&#xEC; ta c&#x1EA7;n t&#x1EA1;o m&#x1ED9;t th&#x1EBB; li&#xEA;n k&#x1EBF;t a &#x111;&#x1EC3; khi click v&#xE0;o &#x111;&#x1EA5;y s&#x1EBD; show detail books l&#xE0; &#x111;&#x1B0;&#x1EE3;c nha.</p>
<pre><code>extends layouts/layout
block content
   .container
      h2 Books Store 
      each book in books
        a(href=&apos;/books/&apos; + book.id)
         img(src=book.ImageUrl, width=&quot;250&quot; height=&quot;280&quot;)
         h3= book.title
</code></pre>
<p><strong>V&#xE0; &#x111;&#xE2;y l&#xE0; k&#x1EBF;t qu&#x1EA3; khi ch&#xFA;ng ta hi&#x1EC3;n th&#x1ECB; trang HomePage nha:</strong></p>
<img src="https://media.giphy.com/media/eJY2PkuUPmQLBuwntR/giphy.gif" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Books Store V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB - Ph&#x1EA7;n 4">
<h2 id="cssligiaodinchoproject">CSS L&#x1EA1;i Giao Di&#x1EC7;n Cho Project</h2>
<p>Trong <code>public</code> c&#xF3; file <strong>/stylesheets/style.css</strong> c&#xE1;c b&#x1EA1;n nh&#x1EDB; import link css v&#xE0;o trong project nha.<br>
Ri&#xEA;ng c&#xE1;i ph&#x1EA7;n CSS n&#xE0;y c&#xE1;c b&#x1EA1;n c&#xF3; th&#x1EC3; s&#xE1;ng t&#x1EA1;o theo s&#x1EDF; th&#xED;ch c&#x1EE7;a b&#x1EA3;n th&#xE2;n m&#xEC;nh kh&#xF4;ng nh&#x1EA5;t thi&#x1EBF;t ph&#x1EA3;i l&#xE0;m gi&#x1ED1;ng m&#xEC;nh nha.<br>
Ph&#x1EA7;n css n&#xE0;y m&#xEC;nh code kh&#xE1; ng&#x1EAF;n m&#xEC;nh t&#x1EAD;n d&#x1EE5;ng nh&#x1EEF;ng class m&#xE0; bootstrap h&#x1ED7; tr&#x1EE3; &#x111;&#x1EC3; style cho n&#xF3; nha</p>
<p>&#x1EDE; &#x111;&#xE2;y m&#xEC;nh l&#x1B0;u &#xFD; m&#x1ED9;t ch&#xFA;t &#x111;&#xF3; l&#xE0; c&#xE1;c b&#x1EA1;n s&#x1EBD; thay th&#x1EBF; nh&#x1EEF;ng width v&#xE0; height trong c&#xE1;c th&#x1EBB; img d&#xF9;ng &#x111;&#x1EC3; hi&#x1EC3;n th&#x1ECB; cover image b&#x1EB1;ng m&#x1ED9;t class <em>img-item</em> nha. &#x110;&#x1EC3; khi m&#xEC;nh chia layout b&#x1EB1;ng bootstrap th&#xEC; &#x1EA3;nh n&#xF3; kh&#xF4;ng b&#x1ECB; v&#x1EE1; nha.<br>
&#x110;&#x1EC3; bi&#x1EBF;t th&#xEA;m chi ti&#x1EBF;t m&#xEC;nh chia layout nh&#x1B0; n&#xE0;o th&#xEC; xem <strong><a href="https://github.com/long1211/Books_Store/tree/master/src/views">t&#x1EA1;i &#x111;&#xE2;y nha</a></strong>, m&#xEC;nh c&#x169;ng &#x111;&#xE3; n&#xF3;i r&#x1ED3;i ri&#xEA;ng ph&#x1EA7;n n&#xE0;y c&#xE1;c b&#x1EA1;n c&#xF3; th&#x1EC3; t&#x1EF1; style theo s&#x1EE9;c s&#xE1;ng t&#x1EA1;o c&#x1EE7;a b&#x1EA3;n th&#xE2;n m&#xEC;nh nha.<br>
<strong>CSS Project</strong></p>
<pre><code>* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
    font-family: sans-serif;
}

li {
    list-style: none;
}

a,
a:hover,
a:active,
a:visited,
a:focus {
    text-decoration: none;
}

label{
    font-weight: 700;
}

.h-30{
    height: 2rem;
}

/* Header */
.navbar {
    width: 100%;
}

.navbar-light .navbar-toggler {
    outline: none;
    border: none;
}

/* Content */
.title-h2 {
    text-align: center;
    font-weight: 700;
    margin-bottom: 2rem;
}

.item-wrapper:hover {
    box-shadow: 0px 0px 10px #444444;
}

.item-text {
    padding: .8rem 0;
    color: #333333;
    font-size: 1.3rem;
    overflow: hidden;
    text-overflow: ellipsis;
    text-transform: capitalize;
    text-align: center;
}

.item-text:hover {
    color: #337ab7;
}

.img-item {
    width: 100%;
    height: 280px;
}

.form-control,
.btn {
    border-radius: inherit;
}

</code></pre>
<p><strong>V&#xE0; &#x111;&#xE2;y l&#xE0; k&#x1EBF;t qu&#x1EA3; khi ch&#xFA;ng style l&#x1EA1;i to&#xE0;n b&#x1ED9; giao di&#x1EC7;n cho project nha:</strong></p>
<img src="https://media.giphy.com/media/eIb1ME5AG3S9DY8Lh0/giphy.gif" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Books Store V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB - Ph&#x1EA7;n 4">
<h3 id="deployprojectlnheroku">Deploy Project L&#xEA;n Heroku</h3>
<p>&#x110;&#x1EC3; m&#xE0; deploy &#x111;&#x1B0;&#x1EE3;c m&#x1ED9;t project l&#xEA;n heroku th&#xEC; c&#xE1;c b&#x1EA1;n &#x111;&#x1ECD;c m&#x1ED9;t topic m&#xE0; m&#xEC;nh &#x111;&#xE3; t&#x1EEB;ng vi&#x1EBF;t &#x111;&#x1EC3; h&#x1B0;&#x1EDB;ng d&#x1EAB;n <strong><a href="https://www.thanhlongdev.com/huong-dan-cach-deploy-project-nodejs-len-heroku/">t&#x1EA1;i &#x111;&#xE2;y nha</a></strong></p>
<h2 id="gihngphttrinproject">G&#x1EE3;i &#xDD; H&#x1B0;&#x1EDB;ng Ph&#xE1;t Tri&#x1EC3;n Project</h2>
<ul>
<li>T&#x1EA1;o m&#x1ED9;t folder s&#x1EBD; l&#x1EA5;y n&#x1EDB;i ch&#x1EE9;a c&#xE1;c file c&#xF3; source code l&#x1EB7;p &#x111;i l&#x1EB7;p l&#x1EA1;i nhi&#x1EC1;u l&#x1EA7;n<br>
VD: Nh&#x1B0; form t&#x1EA1;o books/author v&#xE0; th&#xF4;ng b&#xE1;o l&#x1ED7;i th&#xEC; s&#x1EBD; t&#x1EA1;o cho n&#xF3; m&#x1ED9;t file ri&#xEA;ng, n&#x1EBF;u mu&#x1ED1;n d&#xF9;ng th&#xEC; ch&#x1EC9; c&#x1EA7;n include v&#xE0;o l&#xE0; &#x111;&#x1B0;&#x1EE3;c t&#xEC;m hi&#x1EC3;u th&#xEA;m <a href="https://pugjs.org/language/includes.html">t&#x1EA1;i &#x111;&#xE2;y nha</a></li>
<li>Ph&#xE1;t tri&#x1EC3;n th&#xE0;nh m&#x1ED9;t trang ebook ch&#x1EB3;ng h&#x1EA1;n khi click show detail book th&#xEC; s&#x1EBD; xu&#x1EA5;t hi&#x1EC3;n t&#xE1;c gi&#x1EA3; gi&#x1EDB;i thi&#x1EC7;u v&#xE0; s&#x1EBD; c&#xF3; m&#x1ED9;t c&#xE1;i n&#xFA;t n&#xE0;o &#x111;&#xF3; khi click v&#xE0;o &#x111;&#x1EA5;y s&#x1EBD; m&#x1EDF; m&#x1ED9;t file PDF ch&#x1EB3;ng h&#x1EA1;n,... C&#xE1;c b&#x1EA1;n c&#x1EA7;n t&#x1EA1;o cho m&#xEC;nh m&#x1ED9;t trang Admin v&#xE0; x&#xE1;c th&#x1EF1;c, ph&#xE2;n quy&#x1EC1;n cho n&#xF3; ch&#x1EC9; c&#xF3; b&#x1EA1;n m&#x1EDB;i &#x111;&#x1B0;&#x1EE3;c v&#xE0;o &#x111;&#x1EC3; &#x111;&#x103;ng s&#xE1;ch, &#x1EDF; &#x111;&#xE2;y m&#xEC;nh kh&#xF4;ng c&#x1EA7;n y&#xEA;u c&#x1EA7;u user login hay l&#xE0;m g&#xEC; c&#x1EA3;. Ho&#x1EB7;c c&#xE1;c b&#x1EA1;n c&#xF3; th&#x1EC3; ph&#xE1;t m&#x1ED9;t n&#x1EC1;n t&#x1EA3;ng chia s&#x1EBB; Ebook c&#xF3; th&#x1EC3; cho ng&#x1B0;&#x1EDD;i d&#xF9;ng &#x111;&#x103;ng ebook l&#xEA;n v&#xE0; m&#xEC;nh s&#x1EBD; ki&#x1EC3;m di&#x1EC7;t ebook &#x111;&#x103;ng l&#xEA;n,...</li>
<li>Ph&#xE1;t tri&#x1EC3;n th&#xE0;nh m&#x1ED9;t trang web b&#xE1;n s&#xE1;ch, ph&#xE1;t tri&#x1EC3;n th&#xEA;m c&#xE1;c ch&#x1EE9;c n&#x103;ng &#x111;&#x103;ng nh&#x1EAD;p &#x111;&#x103;ng k&#xFD; &#x111;&#x1EC3; khi user mu&#x1ED1;n mua h&#xE0;ng th&#xEC; c&#x1EA7;n ph&#x1EA3;i login v&#xE0;o m&#x1EDB;i mua &#x111;&#x1B0;&#x1EE3;c m&#xEC;nh c&#xF3; vi&#x1EBF;t m&#x1ED9;t b&#x1EB1;ng h&#x1B0;&#x1EDB;ng d&#x1EAB;n s&#x1EED; d&#x1EE5;ng jwt &#x111;&#x1EC3; l&#xE0;m hai ch&#x1EE9;c n&#x103;ng tr&#xEA;n b&#x1EA1;n c&#xF3; th&#x1EC3; tham kh&#x1EA3;o <a href="https://www.thanhlongdev.com/huong-dan-xay-dung-nodejs-api-xac-thuc-voi-jwt/">t&#x1EA1;i &#x111;&#xE2;y nha</a></li>
<li>Ph&#xE1;t tri&#x1EC3;n th&#xE0;nh m&#x1ED9;t trang TM&#x110;T m&#xEC;nh s&#x1EBD; cho ph&#xE9;p ng&#x1B0;&#x1EDD;i b&#xE1;n &#x111;&#x103;ng s&#xE1;ch l&#xEA;n b&#xE1;n. M&#xEC;nh s&#x1EBD; l&#xE0; n&#x1A1;i trung gian &#x111;&#x1EC3; ki&#x1EC3;m so&#xE1;t ki&#x1EC3;m di&#x1EC7;t s&#xE1;ch &#x111;&#x1B0;&#x1A1;c &#x111;&#x103;ng l&#xEA;n b&#xE1;n v&#xE0; ng&#x1B0;&#x1EDD;i mua. Ch&#xFA;ng ta c&#x1EA7;n ph&#xE2;n quy&#x1EC1;n ra v&#xED; d&#x1EE5; m&#xEC;nh l&#xE0; n&#x1A1;i trung gian th&#xEC; s&#x1EBD; Admin c&#xF3; nh&#x1EEF;ng ch&#x1EE9;c n&#x103;ng nh&#x1B0;: di&#x1EC7;t s&#xE1;ch c&#x1EA7;n b&#xE1;n, x&#xF3;a s&#xE1;ch vi ph&#x1EA1;m b&#x1EA3;n quy&#x1EC1;n...C&#xF2;n ng&#x1B0;&#x1EDD;i b&#xE1;n s&#x1EBD; c&#xF3; ch&#x1EE9;c n&#x103;ng c&#x1EE7;a seller nh&#x1B0; &#x111;&#x103;ng b&#xE0;i, x&#xF3;a b&#xE0;i c&#x1EE7;a shop m&#xEC;nh,.. C&#xF2;n ng&#x1B0;&#x1EDD;i mua th&#xEC; ch&#x1EC9; c&#xF3; vi&#x1EC7;c mua s&#xE1;ch v&#xE0; &#x111;&#xE1;nh gi&#xE1; s&#xE1;ch,.v.v.</li>
</ul>
<p><strong>V&#x1EAD;y L&#xE0; Xong R&#x1ED3;i Nha Vui Qu&#xE1; =)))</strong><br>
K&#x1EBF;t th&#xFA;c m&#x1ED9;t series v&#x1EC1; project n&#xE0;y nha v&#xE3; th&#x1EAD;t s&#x1EF1;, c&#xE1;c b&#x1EA1;n c&#xF3; th&#x1EC3; tham kh&#x1EA3;o code m&#xE0; m&#xEC;nh &#x111;&#xE3; push l&#xEA;n github <a href="https://github.com/long1211/Books_Store">t&#x1EA1;i &#x111;&#xE2;y nha</a>.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h1 id="likt">L&#x1EDD;i K&#x1EBF;t</h1>
<p>V&#x1EAD;y l&#xE0; xong b&#xE0;i H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Books Store V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB - Ph&#x1EA7;n 4 c&#x169;ng l&#xE0; ph&#x1EA7;n cu&#x1ED1;i r&#x1ED3;i nh&#xE9;. M&#xEC;nh mong mu&#x1ED1;n sau khi c&#xE1;c b&#x1EA1;n ho&#xE0;n th&#xE0;nh xong project n&#xE0;y s&#x1EBD; hi&#x1EC3;u v&#xE0; n&#x1EAF;m r&#xF5; h&#x1A1;n v&#x1EC1; nodejs, express v&#xE0; mongodb n&#xF3;i ri&#xEA;ng v&#xE0; l&#x1EAD;p tr&#xEC;nh n&#xF3;i ch&#xFA;ng. C&#xE1;c b&#x1EA1;n c&#xF3; th&#x1EC3; d&#x1EF1;a v&#xE0;o project n&#xE0;y &#x111;&#x1EC3; c&#xF3; th&#x1EC3; ph&#xE1;t tri&#x1EC3;n v&#xE0; scale project n&#xE0;y l&#x1EDB;n h&#x1A1;n n&#x1EEF;a nha.<br>
<strong>C&#xE1;c b&#x1EA1;n nh&#x1EDB; like v&#xE0; theo d&#xF5;i fanpage <a href="https://www.facebook.com/thanhlongdev/">Thanh Long Dev</a> &#x111;&#x1EC3; nh&#x1EAD;n nh&#x1EEF;ng th&#xF4;ng b&#xE1;o v&#x1EC1; b&#xE0;i vi&#x1EBF;t m&#x1EDB;i nh&#x1EA5;t nha.</strong><br>
<em><strong>N&#x1EBF;u c&#xE1;c b&#x1EA1;n c&#x1EA3;m th&#x1EA5;y b&#xE0;i vi&#x1EBF;t c&#x1EE7;a m&#xEC;nh hay th&#xEC; c&#xE1;c b&#x1EA1;n c&#xF3; th&#x1EC3; &#x1EE7;ng h&#x1ED9; m&#xEC;nh &#x111;&#x1EC3; m&#xEC;nh c&#xF3; th&#xEA;m &#x111;&#x1ED9;ng l&#x1EF1;c &#x111;&#x1EC3; ra nh&#x1EEF;ng b&#xE0;i topic hay v&#xE0; ch&#x1EA5;t l&#x1B0;&#x1EE3;ng h&#x1A1;n &#x1EE7;ng h&#x1ED9; m&#xEC;nh <a href="https://vrdonate.vn/thanhlongdev">t&#x1EA1;i &#x111;&#xE2;y nha.</a></strong></em><br>
<strong>Ch&#xFA;c C&#xE1;c B&#x1EA1;n Th&#xE0;nh C&#xF4;ng!!</strong></p>
<!--kg-card-end: markdown--><!--kg-card-begin: html--><iframe src="https://www.facebook.com/plugins/like.php?href=https%3A%2F%2Fwww.thanhlongdev.com%2Fhuong-dan-xay-dung-books-store-voi-nodejs-express-va-mongodb-phan4%2F&amp;width=450&amp;layout=standard&amp;action=like&amp;size=large&amp;share=true&amp;height=35&amp;appId=2794898430534168" width="450" height="35" style="border:none;overflow:hidden" scrolling="no" frameborder="0" allowtransparency="true" allow="encrypted-media"></iframe><!--kg-card-end: html--><!--kg-card-begin: html--><div class="fb-comments" data-href="https://www.thanhlongdev.com/huong-dan-xay-dung-books-store-voi-nodejs-express-va-mongodb-phan4/" data-width="100%" data-numposts="10"></div><!--kg-card-end: html-->]]></content:encoded></item><item><title><![CDATA[Hướng Dẫn Xây Dựng Books Store Với NodeJS, Express và MongoDB - Phần 3]]></title><description><![CDATA[<!--kg-card-begin: markdown--><h2 id="chcnnghinthchititcpnhtvxaauthor">Ch&#x1EE9;c N&#x103;ng Hi&#x1EC3;n Th&#x1ECB; Chi Ti&#x1EBF;t, C&#x1EAD;p Nh&#x1EAD;t V&#xE0; X&#xF3;a Author</h2>
<h3 id="nhngharouterhinthchitittrongauthor">&#x110;&#x1ECB;nh Ngh&#x129;a Router Hi&#x1EC3;n Th&#x1ECB; Chi Ti&#x1EBF;t Trong Author</h3>
<p>M&#xEC;nh s&#x1EBD;</p>]]></description><link>https://www.thanhlongdev.com/huong-dan-xay-dung-books-store-voi-nodejs-express-va-mongodb-phan3/</link><guid isPermaLink="false">5f49bf598d46df00010124ba</guid><category><![CDATA[Lập Trình Web]]></category><dc:creator><![CDATA[Đặng Thanh Long]]></dc:creator><pubDate>Fri, 04 Sep 2020 10:56:06 GMT</pubDate><media:content url="https://digitalpress.fra1.cdn.digitaloceanspaces.com/4tg23ij/2020/08/33-3.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h2 id="chcnnghinthchititcpnhtvxaauthor">Ch&#x1EE9;c N&#x103;ng Hi&#x1EC3;n Th&#x1ECB; Chi Ti&#x1EBF;t, C&#x1EAD;p Nh&#x1EAD;t V&#xE0; X&#xF3;a Author</h2>
<h3 id="nhngharouterhinthchitittrongauthor">&#x110;&#x1ECB;nh Ngh&#x129;a Router Hi&#x1EC3;n Th&#x1ECB; Chi Ti&#x1EBF;t Trong Author</h3>
<img src="https://digitalpress.fra1.cdn.digitaloceanspaces.com/4tg23ij/2020/08/33-3.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Books Store V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB - Ph&#x1EA7;n 3"><p>M&#xEC;nh s&#x1EBD; n&#xF3;i s&#x1A1; qua m&#x1ED9;t ch&#xFA;t v&#x1EC1; nguy&#xEA;n l&#xED; ho&#x1EA1;t &#x111;&#x1ED9;ng c&#x1EE7;a th&#xE8;n n&#xE0;y t&#xED; nha ^^.<br>
&#x110;&#x1EC3; hi&#x1EC3;n th&#x1ECB; chi ti&#x1EBF;t(show detail) author th&#xEC; ch&#x1EC9; c&#xF3; c&#xE1;ch l&#xE0; l&#x1EA5;y id c&#x1EE7;a author &#x111;&#xF3; r&#x1ED3;i render ra t&#xEA;n c&#x1EE7;a author v&#xE0; books m&#xE0; author &#x111;&#xF3; &#x111;&#xE3; t&#x1EA1;o.<br>
Th&#xEC; c&#xE1;ch ho&#x1EA1;t &#x111;&#x1ED9;ng n&#xF3; ch&#x1EC9; c&#xF3; v&#x1EAD;y th&#xF4;i =))<br>
<strong>B&#x1EAF;t &#x111;&#x1EA7;u code th&#xF4;i n&#xE0;o</strong><br>
Tr&#x1B0;&#x1EDB;c ti&#xEA;n trong <code>views</code> c&#xF3; file <strong>authors/index.pug</strong> c&#xE1;c b&#x1EA1;n th&#xEA;m cho m&#xEC;nh d&#xF2;ng code n&#xE0;y.<br>
&#x110;o&#x1EA1;n code n&#xE0;y l&#xE0; m&#x1ED9;t th&#x1EBB; li&#xEA;n k&#x1EBF;t a c&#xF3; ch&#x1EE9;a id c&#x1EE7;a author m&#xEC;nh click vao View nha.</p>
<pre><code>   div
        a(href=&apos;/authors/&apos; + author.id) View 
</code></pre>
<p>v&#xE0;o ph&#xED;a sau th&#x1EBB; <code>h4= author.name</code> m&#xE0; ph&#x1EA7;n 1 m&#xEC;nh &#x111;&#xE3; t&#x1EA1;o nha. M&#x1EE5;c &#x111;&#xED;ch l&#xE0; t&#x1EA1;o m&#x1ED9;t th&#x1EBB; a khi click v&#xE0;o &#x111;&#x1EA5;y th&#xEC; s&#x1EBD; show detail author.</p>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1598843507/Untitled_buuald.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Books Store V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB - Ph&#x1EA7;n 3">
<h3 id="controllerhinthchitittrongauthor">Controller Hi&#x1EC3;n Th&#x1ECB; Chi Ti&#x1EBF;t Trong Author</h3>
<p>C&#x169;ng trong file <code>author.routes.js</code> ta s&#x1EBD; t&#x1EA1;o m&#x1ED9;t router <strong>router.get(&apos;/:id,...)</strong>, trong router n&#xE0;y s&#x1EBD; l&#xE0; n&#x1A1;i m&#xE0; ch&#xFA;ng ta d&#xF9;ng &#x111;&#x1EC3; show detail b&#x1EB1;ng c&#xE1;ch s&#x1EED; d&#x1EE5;ng id c&#x1EE7;a ch&#xFA;ng.<br>
Tr&#x1B0;&#x1EDB;c ti&#xEA;n ta s&#x1EBD; d&#x1EF1;a v&#xE0;o id c&#x1EE7;a author &#x111;&#x1EC3; l&#x1EA5;y data c&#x1EE7;a author &#x111;&#xF3; ra g&#x1ED3;m c&#xF3; name,... C&#x169;ng t&#x1EEB; author &#x111;&#xF3; th&#xEC; ta s&#x1EBD; l&#x1EA5;y &#x111;&#x1B0;&#x1EE3;c books m&#xE0; author &#x111;&#xE3; t&#x1EA1;o.</p>
<pre><code>// Show Details Author
router.get(&apos;/:id&apos;, async (req, res, next) =&gt; {
  try {
    const author = await Author.findById(req.params.id) // find m&#x1ED9;t author d&#x1EF1;a v&#xE0;o id
    
   const booksByAuthor = await Book.find({ author: author.id }).limit(6).exec() 
   // find t&#x1EA5;t c&#x1EA3; c&#xE1;c book m&#xE0; c&#xF3; author l&#xE0; id c&#x1EE7;a author &#x111;&#x1B0;&#x1EE3;c t&#xEC;m &#x1EDF; tr&#xEA;n v&#xE0; gi&#x1EDB;i h&#x1EA1;n ch&#x1EC9; l&#x1EA5;y 6 books.
    
    // Truy&#x1EC1;n data author v&#xE0; booksByAuthor v&#xE0;o trong views
    res.render(&apos;authors/show&apos;,
      {
        author: author,
        booksByAuthor: booksByAuthor
      })
  } catch{
    res.redirect(&apos;/&apos;)
  }
})
</code></pre>
<p><strong>M&#xEC;nh s&#x1EBD; th&#x1EED; log ra data c&#x1EE7;a author v&#xE0; booksByAuthor cho c&#xE1;c b&#x1EA1;n d&#x1EC5; h&#xEC;nh dung h&#x1A1;n nha:</strong></p>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1598851403/Untitled_salj33.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Books Store V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB - Ph&#x1EA7;n 3">
<h3 id="giaodinhinthchitittrongauthor">Giao Di&#x1EC7;n Hi&#x1EC3;n Th&#x1ECB; Chi Ti&#x1EBF;t Trong Author</h3>
<p>Trong views b&#x1EA1;n t&#x1EA1;o cho m&#xEC;nh th&#x1B0; m&#x1EE5;c l&#xE0; <strong>authors</strong> s&#x1EBD; bao g&#x1ED3;m 4 file <code>index.pug</code>, <code>new.pug</code>, <code>show.pug</code>, <code>edit.pug</code>.<br>
Tr&#x1B0;&#x1EDB;c ti&#xEA;n c&#xE1;c b&#x1EA1;n nh&#x1EDB; extends layout v&#xE0;o nha sau &#x111;&#xF3; ch&#xFA;ng ta c&#x1EA7;n hi&#x1EC3;n th&#x1ECB; t&#xEA;n author, n&#x1EBF;u t&#xE1;c gi&#x1EA3; &#x111;&#xF3; c&#xF3; t&#x1EA1;o books th&#xEC; ta s&#x1EBD; l&#x1EB7;p qua r&#x1ED3;i hi&#x1EC3;n th&#x1ECB; c&#xE1;c th&#xF4;ng tin c&#x1EE7;a books &#x111;&#xF3; v&#xE0; ng&#x1B0;&#x1EE3;c l&#x1EA1;i ta s&#x1EBD; hi&#x1EC3;n th&#x1ECB; m&#x1ED9;t th&#xF4;ng b&#xE1;o v&#x1EDB;i &#x111;o&#x1EA1;n text &quot;No books by author&quot;.<br>
C&#xE2;u h&#x1ECF;i &#x1EDF; &#x111;&#xE2;y l&#xE0; t&#x1EA1;i sao author ta kh&#xF4;ng l&#x1EB7;p m&#xE0; books c&#x1EE7;a author ta l&#x1EA1;i l&#x1EB7;p qua? Th&#xEC; &#x111;&#x1A1;n gi&#x1EA3;n th&#xF4;i khi ch&#xFA;ng ta findById c&#x1EE7;a author th&#xEC; n&#xF3; ch&#x1EC9; find m&#x1ED9;t author c&#xF3; id m&#xE0; n&#xF3; &#x111;ang t&#xEC;m. C&#xF2;n find books th&#xEC; n&#xF3; s&#x1EBD; hi&#x1EC3;n th&#x1ECB; to&#xE0;n b&#x1ED9; s&#xE1;ch m&#xE0; author &#x111;&#xE3; t&#x1EA1;o &#x111;&#x1EC3; render ra views.<br>
<strong>authors/show.pug</strong></p>
<pre><code>extends ../layouts/layout

block content
  div.container  
    h3=&apos;Author: &apos;+ author.name
        
    if booksByAuthor.length &gt; 0
        h2 Books By Author
        each book in booksByAuthor
            a(href=&apos;/books/&apos; + book.id)
                img(src=book.ImageUrl, width=&quot;250&quot; height=&quot;280&quot;)
                h3= book.title
    else
       h2 No books by author        
</code></pre>
<p><strong>V&#xE0; &#x111;&#xE2;y l&#xE0; k&#x1EBF;t qu&#x1EA3; khi ch&#xFA;ng ta show detail authors nha:</strong></p>
<img src="https://media.giphy.com/media/mFAmqdQnWu4IwK2E3l/giphy.gif" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Books Store V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB - Ph&#x1EA7;n 3">
<h3 id="nhngharoutercpnhttrongauthor">&#x110;&#x1ECB;nh Ngh&#x129;a Router C&#x1EAD;p Nh&#x1EAD;t Trong Author</h3>
<p>Th&#xEC; th&#xE8;n c&#x1EAD;p nh&#x1EAD;t n&#xE0;y c&#xE1;ch l&#xE0;m n&#xF3; c&#x169;ng t&#x1EF1;a t&#x1EF1;a nh&#x1B0; t&#x1EA1;o author th&#xF4;i ch&#x1EC9; kh&#xE1;c l&#xE0; thay v&#xEC; s&#x1EBD; t&#x1EA1;o m&#x1ED9;t c&#xE1;i m&#x1EDB;i th&#xEC; ta s&#x1EBD; l&#x1EA5;y id c&#x1EE7;a author &#x111;&#xF3; &#x111;&#x1EC3; edit l&#x1EA1;i t&#xEA;n author m&#xE0; m&#xEC;nh &#x111;&#xE3; t&#x1EA1;o.<br>
&#x110;&#x1EC3; m&#xE0; show detail &#x111;&#x1B0;&#x1EE3;c ch&#xFA;ng ta ph&#x1EA3;i d&#x1EF1;a v&#xE0;o id c&#x1EE7;a author, th&#xEC; update author c&#x169;ng t&#x1B0;&#x1A1;ng t&#x1EF1; v&#x1EAD;y th&#xF4;i nha.<br>
<strong>B&#x1EAF;t &#x111;&#x1EA7;u code th&#xF4;i n&#xE0;o</strong><br>
Tr&#x1B0;&#x1EDB;c ti&#xEA;n trong <code>views</code> c&#xF3; file <strong>authors/index.pug</strong> c&#xE1;c b&#x1EA1;n th&#xEA;m cho m&#xEC;nh d&#xF2;ng code n&#xE0;y.<br>
&#x110;o&#x1EA1;n code n&#xE0;y l&#xE0; m&#x1ED9;t th&#x1EBB; li&#xEA;n k&#x1EBF;t a c&#xF3; ch&#x1EE9;a id c&#x1EE7;a author khi m&#xEC;nh click s&#x1EBD; v&#xE0;o trang edit author nha.</p>
<pre><code>   a(href=&apos;/authors/&apos; + author.id + &apos;/edit&apos;) Edit
</code></pre>
<p>v&#xE0;o ph&#xED;a sau th&#x1EBB; <code>a(href=&apos;/authors/&apos; + author.id) View</code> m&#xE0; &#x1EDF; tr&#xEA;n m&#xEC;nh &#x111;&#xE3; t&#x1EA1;o nha.</p>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1599013938/Untitled_b6m4xg.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Books Store V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB - Ph&#x1EA7;n 3">
<p>C&#x169;ng t&#x1B0;&#x1A1;ng t&#x1EF1; nh&#x1B0; &#x1EDF; tr&#xEA;n trong <code>views</code> c&#xF3; file <strong>authors/show.pug</strong>  c&#xE1;c b&#x1EA1;n th&#xEA;m cho m&#xEC;nh d&#xF2;ng code n&#xE0;y nha.</p>
<pre><code>   div
      a(href=&apos;/authors/&apos;+author.id +&apos;/edit&apos;) Edit
</code></pre>
<p>v&#xE0;o ph&#xED;a sau th&#x1EBB; <code>h2=&apos;Author: &apos;+ author.name</code> m&#xE0; &#x1EDF; tr&#xEA;n m&#xEC;nh &#x111;&#xE3; t&#x1EA1;o nha.</p>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1599013942/Untitled-2_yv37fg.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Books Store V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB - Ph&#x1EA7;n 3">
<p>Trong th&#x1B0; m&#x1EE5;c routes c&#xF3; file <code>author.routes.js</code> c&#xE1;c b&#x1EA1;n t&#x1EA1;o cho m&#xEC;nh hai router update &#x111;&#xF3; l&#xE0; <code>router.get(&apos;/:id/edit&apos;,...)</code> &#x111;&#x1EC3; render ra views v&#xE0; <code>router.put(&apos;/:id&apos;,...)</code>  &#x111;&#x1EC3; c&#x1EAD;p nh&#x1EAD;t author nha. Tr&#x1B0;&#x1EDB;c m&#x1EAF;t c&#xE1;c b&#x1EA1;n ch&#x1EC9; c&#x1EA7;n t&#x1EA1;o v&#xE0; render ra views tr&#x1B0;&#x1EDB;c cho m&#xEC;nh l&#xE0; &#x111;&#x1B0;&#x1EE3;c.</p>
<pre><code>// Get Update Author
router.get(&apos;/:id/edit&apos;, async (req, res, next) =&gt; {
  try {
    const author = await Author.findById(req.params.id) // find ra m&#x1ED9;t author d&#x1EF1;a v&#xE0;o id
    res.render(&apos;authors/edit&apos;, { author: author }) // Truy&#x1EC1;n data v&#xE0;o trong views
  } catch{
    res.redirect(&apos;/authors&apos;)
  }
})
  
// Update Author  
router.put(&apos;/:id&apos;, async (req, res, next) =&gt; {
   
 });
</code></pre>
<h3 id="giaodincpnhttrongauthor">Giao Di&#x1EC7;n C&#x1EAD;p Nh&#x1EAD;t Trong Author</h3>
<p>Trong views b&#x1EA1;n t&#x1EA1;o cho m&#xEC;nh th&#x1B0; m&#x1EE5;c l&#xE0; <strong>authors</strong> s&#x1EBD; bao g&#x1ED3;m 4 file <code>index.pug</code>, <code>new.pug</code>, <code>show.pug</code>, <code>edit.pug</code>.<br>
Tr&#x1B0;&#x1EDB;c ti&#xEA;n c&#xE1;c b&#x1EA1;n nh&#x1EDB; extends layout v&#xE0; t&#x1EA1;o cho m&#xEC;nh m&#x1ED9;t c&#xE1;i form gi&#x1ED1;ng nh&#x1B0; t&#x1EA1;o author nh&#x1B0;ng c&#xE1;c b&#x1EA1;n ph&#x1EA3;i thay &#x111;&#x1ED5;i l&#x1EA1;i &#x111;&#x1B0;&#x1EDD;ng d&#x1EAB;n <em>action</em> nha.<br>
<strong>authors/edit.pug</strong></p>
<pre><code>
block content
  .container
    h2 Edit Author
    form(method=&quot;POST&quot; action=&quot;/authors/&quot; + author.id)
      label(for=&quot;name&quot;) Name
      input(placeholder=&quot;Name&quot;, type=&quot;text&quot; name=&quot;name&quot; value=author.name)
      div
       a(href=&quot;/authors/&quot; + author.id) Cancel
       button(type=&quot;submit&quot;) Update
</code></pre>
<p><strong>V&#xE0; &#x111;&#xE2;y l&#xE0; giao di&#x1EC7;n &#x111;&#x1EC3; c&#x1EAD;p nh&#x1EAD;t author:</strong></p>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1599014273/Untitled-2_yfte3x.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Books Store V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB - Ph&#x1EA7;n 3">
<h3 id="controllercpnhttrongauthor">Controller C&#x1EAD;p Nh&#x1EAD;t Trong Author</h3>
<p>&#x110;&#x1EC3; c&#xF3; th&#x1EC3; c&#x1EAD;p nh&#x1EAD;t &#x111;&#x1B0;&#x1EE3;c author v&#xE0; s&#x1EED; d&#x1EE5;ng &#x111;&#x1B0;&#x1EE3;c ph&#x1B0;&#x1A1;ng th&#x1EE9;c <em>PUT</em> ta c&#x1EA7;n s&#x1EED; d&#x1EE5;ng m&#x1ED9;t middleware &#x111;&#xF3; l&#xE0; <strong>method override</strong>.<br>
Module <strong>method override</strong> n&#xE0;y m&#xEC;nh &#x111;&#xE3; khai b&#xE1;o v&#xE0; k&#xED;ch ho&#x1EA1;t trong file <code>app.js</code> &#x1EDF; ph&#x1EA7;n 1 r&#x1ED3;i nha.<br>
V&#xEC; bi&#x1EC3;u m&#x1EAB;u html n&#xF3; ch&#x1EC9; h&#x1ED7; tr&#x1EE3; hai ph&#x1B0;&#x1A1;ng th&#x1EE9;c l&#xE0; <em>GET</em> v&#xE0; <em>POST</em> m&#xE0; th&#xF4;i, n&#xEA;n &#x111;&#x1EC3; c&#xF3; th&#x1EC3; s&#x1EED; d&#x1EE5;ng &#x111;&#x1B0;&#x1EE3;c ph&#x1B0;&#x1A1;ng th&#x1EE9;c PUT th&#xEC; ta c&#x1EA7;n ph&#x1EA3;i ghi &#x111;&#xE8; ch&#xFA;ng.</p>
<p>Trong <code>views</code> c&#xF3; file <strong>authors/edit.pug</strong> c&#xE1;c b&#x1EA1;n th&#xEA;m cho m&#xEC;nh &#x111;o&#x1EA1;n m&#xE3; n&#xE0;y <code>&quot;?_method=PUT&quot;</code> v&#xE0;o trong action c&#x1EE7;a form gi&#xFA;p m&#xEC;nh v&#x1EDB;i nha.<br>
Ph&#x1B0;&#x1A1;ng th&#x1EE9;c Put ghi &#x111;&#xE8; l&#xEA;n ph&#x1B0;&#x1A1;ng th&#x1EE9;c Post<br>
<code> form(method=&quot;POST&quot; action=&quot;/authors/&quot; + author.id + &quot;?_method=PUT&quot;)</code></p>
<p><strong>Ki&#x1EC3;m tra t&#xEA;n c&#x1EE7;a author khi &#x111;&#x1B0;&#x1EE3;c c&#x1EAD;p nh&#x1EAD;t</strong><br>
Th&#xEC; ph&#x1EA7;n n&#xE0;y n&#xF3; c&#x169;ng gi&#x1ED1;ng nh&#x1B0; t&#x1EA1;o books &#x1EDF; ph&#x1EA7;n 1, ta s&#x1EBD; check xem t&#xEA;n c&#x1EAD;p nh&#x1EAD;t c&#xF3; tr&#xF9;ng v&#x1EDB;i t&#xEA;n m&#xE0; author &#x111;&#xE3; t&#x1EA1;o t&#x1EEB; tr&#x1B0;&#x1EDB;c n&#x1EBF;u tr&#xF9;ng th&#xEC; s&#x1EBD; hi&#x1EC3;n th&#x1ECB; th&#xF4;ng b&#xE1;o.<br>
B&#x1EDF;i v&#xEC; t&#xEA;n t&#xE1;c gi&#x1EA3; c&#x1EE7;a m&#x1ED9;t cu&#x1ED1;n s&#xE1;ch n&#xE0;o &#x111;&#xF3; th&#xEC; r&#x1EA5;t hi&#x1EBF;m khi tr&#xF9;ng nhau c&#xF3; th&#x1EC3; n&#xF3;i l&#xE0; kh&#xF4;ng c&#xF3;, c&#xF2;n t&#xEA;n ng&#x1B0;&#x1EDD;i m&#xE0; tr&#xF9;ng nhau l&#xE0; chuy&#x1EC7;n b&#xEC;nh th&#x1B0;&#x1EDD;ng.</p>
<p>Trong file <code>authors.routes.js</code> ta c&#xF3; <strong>router.put(&apos;/:id&apos;,...)</strong> d&#xF9;ng &#x111;&#x1EC3; update author.</p>
<pre><code>// Update Author

router.put(&apos;/:id&apos;, async (req, res, next) =&gt; {
  let author
  
  author = await Author.findById(req.params.id)// T&#xEC;m m&#x1ED9;t author d&#x1EF1;a v&#xE0;o id

  // Ki&#x1EC3;m tra name author c&#xF3; t&#x1ED3;n t&#x1EA1;i hay kh&#xF4;ng
  const nameAuthor = await Author.findOne({ // T&#xEC;m m&#x1ED9;t t&#xEA;n author trong DB v&#x1EDB;i t&#xEA;n &#x111;&#x1B0;&#x1EE3;c c&#x1EAD;p nh&#x1EAD;t
    name: req.body.name
  });
    // N&#x1EBF;u t&#xEC;m &#x111;&#x1B0;&#x1EE3;c t&#xEA;n tr&#xF9;ng nhau s&#x1EBD; render ra mess
  if (nameAuthor) {
    return res.render(&apos;authors/edit&apos;, {
      author: author,
      errorMessage: &apos;Author Already Exists&apos;
    })
  }
  
  try {
    author.name = req.body.name  // C&#x1EAD;p nh&#x1EAD;t t&#xEA;n c&#x1EE7;a author &#x111;&#xF3;
    await author.save(); // L&#x1B0;u t&#xEA;n &#x111;&#xE3; &#x111;&#x1B0;&#x1EE3;c c&#x1EAD;p nh&#x1EAD;t v&#xE0;o DB
    res.redirect(`/authors/${author.id}`)  // Chuy&#x1EC3;n trang show detail n&#x1EBF;u c&#x1EAD;p nh&#x1EAD;t th&#xE0;nh c&#xF4;ng

  } catch{
    // Ng&#x1B0;&#x1EE3;c l&#x1EA1;i, n&#x1EBF;u c&#x1EAD;p nh&#x1EAD;t th&#x1EA5;t b&#x1EA1;i th&#xEC; s&#x1EBD; th&#xF4;ng b&#xE1;o l&#x1ED7;i
    if (author == null) {  
      res.redirect(&apos;/&apos;)
    } else {
      res.render(&apos;authors/edit&apos;, {
        author: author,
        errorMessage: &apos;Error Updating Author&apos;
      })
    }
  }
})
</code></pre>
<p>N&#x1EBF;u m&#xE0; c&#xF3; l&#x1ED7;i khi c&#x1EAD;p nh&#x1EAD;t author th&#xEC; trong <strong>authors/edit.pug</strong> c&#xE1;c b&#x1EA1;n th&#xEA;m d&#xF2;ng code &#x1EDF; d&#x1B0;&#x1EDB;i v&#xE0;o ph&#xED;a th&#x1EBB; <em>h2 Edit Author</em> &#x111;&#x1EC3; hi&#x1EC3;n th&#x1ECB; th&#xF4;ng b&#xE1;o l&#x1ED7;i nha.</p>
<pre><code>    if locals.errorMessage
        = errorMessage
</code></pre>
<p><strong>V&#xE0; &#x111;&#xE2;y l&#xE0; k&#x1EBF;t qu&#x1EA3; khi ch&#xFA;ng ta c&#x1EAD;p nh&#x1EAD;t author:</strong></p>
<img src="https://media.giphy.com/media/kGzc1xw1NnIkk3sRTN/giphy.gif" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Books Store V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB - Ph&#x1EA7;n 3">
<h3 id="nhngharouterxatrongauthor">&#x110;&#x1ECB;nh Ngh&#x129;a Router X&#xF3;a Trong Author</h3>
<p>Tr&#x1B0;&#x1EDB;c ti&#xEA;n trong <code>views</code> c&#xF3; file <strong>authors/index.pug</strong> c&#xE1;c b&#x1EA1;n th&#xEA;m cho m&#xEC;nh d&#xF2;ng code n&#xE0;y.<br>
&#x110;o&#x1EA1;n code n&#xE0;y l&#xE0; m&#x1ED9;t th&#x1EBB; li&#xEA;n k&#x1EBF;t a c&#xF3; ch&#x1EE9;a id c&#x1EE7;a author khi m&#xEC;nh click s&#x1EBD; x&#xF3;a author nha.</p>
<pre><code> form(method=&quot;POST&quot; action=&quot;/authors/&quot; + author.id )
           button(type=&apos;submit&apos;) Delete
</code></pre>
<p>v&#xE0;o ph&#xED;a sau th&#x1EBB; <code>a(href=&apos;/authors/&apos; + author.id + &apos;/edit&apos;) Edit</code> m&#xE0; &#x1EDF; tr&#xEA;n m&#xEC;nh &#x111;&#xE3; t&#x1EA1;o nha.</p>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1599196579/Untitled_gp1exy.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Books Store V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB - Ph&#x1EA7;n 3">
<p>C&#x169;ng t&#x1B0;&#x1A1;ng t&#x1EF1; nh&#x1B0; &#x1EDF; tr&#xEA;n trong <code>views</code> c&#xF3; file <strong>authors/show.pug</strong>  c&#xE1;c b&#x1EA1;n th&#xEA;m cho m&#xEC;nh d&#xF2;ng code n&#xE0;y nha.</p>
<pre><code>form(method=&quot;POST&quot; action=&quot;/authors/&quot; + author.id )
              button(type=&apos;submit&apos;) Delete      
</code></pre>
<p>v&#xE0;o ph&#xED;a sau th&#x1EBB; <code>a(href=&apos;/authors/&apos;+author.id +&apos;/edit&apos;) Edit</code> m&#xE0; &#x1EDF; tr&#xEA;n m&#xEC;nh &#x111;&#xE3; t&#x1EA1;o nha.</p>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1599196598/Untitled-2_rjc2al.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Books Store V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB - Ph&#x1EA7;n 3">
<h3 id="controllerxaauthor">Controller X&#xF3;a Author</h3>
<p>C&#x169;ng trong file <code>authors.routes.js</code> ta c&#xF3; <strong>router.delete(&apos;/:id&apos;,...)</strong> d&#xF9;ng &#x111;&#x1EC3; x&#xF3;a author.</p>
<pre><code>// Delete Author
router.delete(&apos;/:id&apos;, async (req, res, next) =&gt; {
 let author
  try {
   author = await Author.findById(req.params.id)// find id author c&#x1EA7;n x&#xF3;a
    await author.remove() // X&#xF3;a author
    res.redirect(&apos;/authors&apos;) // Chuy&#x1EC3;n h&#x1B0;&#x1EDB;ng sang trang /authors n&#x1EBF;u x&#xF3;a &#x111;&#x1B0;&#x1EE3;c
  } catch{

    res.redirect(`/authors/${author.id}`)

  }
})
</code></pre>
<p>&#x110;&#x1EC3; x&#xF3;a &#x111;&#x1B0;&#x1EE3;c author th&#xEC; c&#x169;ng gi&#x1ED1;ng nh&#x1B0; c&#x1EAD;p nh&#x1EAD;t author n&#xEA;n m&#xEC;nh s&#x1EBD; kh&#xF4;ng gi&#x1EA3;i th&#xED;ch g&#xEC; nhi&#x1EC1;u n&#x1EEF;a. Mu&#x1ED1;n s&#x1EED; d&#x1EE5;ng &#x111;&#x1B0;&#x1EE3;c ph&#x1B0;&#x1A1;ng th&#x1EE9;c <em>Delete</em> ta c&#x1EA7;n s&#x1EED; d&#x1EE5;ng m&#x1ED9;t middleware &#x111;&#xF3; l&#xE0; <strong>method override</strong>.</p>
<p>Trong <code>views</code> c&#xF3; file <strong>authors/index.pug</strong> v&#xE0; <strong>authors/show.pug</strong> c&#xE1;c b&#x1EA1;n th&#xEA;m cho m&#xEC;nh &#x111;o&#x1EA1;n m&#xE3; n&#xE0;y <code>&quot;?_method=DELETE&quot;</code> v&#xE0;o trong action c&#x1EE7;a form gi&#xFA;p m&#xEC;nh v&#x1EDB;i nha.<br>
Ph&#x1B0;&#x1A1;ng th&#x1EE9;c Delete ghi &#x111;&#xE8; l&#xEA;n ph&#x1B0;&#x1A1;ng th&#x1EE9;c Post<br>
<code> form(method=&quot;POST&quot; action=&quot;/authors/&quot; + author.id + &quot;?_method=DELETE&quot;)</code></p>
<p><strong>Nh&#x1B0;ng ch&#x1EDD; ch&#xFA;t c&#xF2;n m&#x1ED9;t v&#x1EA5;n &#x111;&#x1EC1; n&#x1EEF;a, ch&#x1B0;a xong m&#xF4; n&#x1EA1; :))</strong><br>
C&#xF3; m&#x1ED9;t v&#x1EA5;n &#x111;&#x1EC1; nh&#x1B0; n&#xE0;y n&#x1EBF;u nh&#x1B0; m&#xE0; x&#xF3;a theo c&#xE1;ch tr&#xEA;n &#xED; th&#xEC; ch&#x1EC9; x&#xF3;a author m&#xE0; th&#xF4;i c&#xF2;n books m&#xE0; author t&#x1EA1;o s&#x1EBD; kh&#xF4;ng b&#x1ECB; x&#xF3;a. B&#x1EDF;i v&#x1EAD;y n&#xEA;n khi ch&#xFA;ng ta x&#xF3;a author th&#xEC; c&#x1EA7;n ph&#x1EA3;i x&#xF3;a lu&#xF4;n books m&#xE0; author &#x111;&#xF3; &#x111;&#xE3; t&#x1EA1;o &#x111;&#xFA;ng kh&#xF4;ng n&#xE0;o, m&#xEC;nh &#x111;&#xE3; c&#xF3; c&#xE1;ch gi&#x1EA3;i quy&#x1EBF;t ch&#xFA;ng hehehe.</p>
<p>&#x110;&#x1EC3; khi x&#xF3;a author th&#xEC; books c&#x169;ng &#x111;&#x1B0;&#x1EE3;c x&#xF3;a lu&#xF4;n ta c&#x1EA7;n s&#x1EED; d&#x1EE5;ng m&#x1ED9;t middleware m&#xE0; mongoose cung c&#x1EA5;p &#x111;&#xF3; l&#xE0; <strong>Pre</strong>.<br>
<strong>Pre middleware</strong> n&#xE0;y s&#x1EBD; th&#x1EF1;c hi&#x1EC7;n m&#x1ED9;t method x&#xF3;a tr&#x1B0;&#x1EDB;c m&#x1ED9;t h&#xE0;nh &#x111;&#x1ED9;ng x&#xF3;a x&#x1EA3;y ra, c&#xF3; ngh&#x129;a l&#xE0; n&#xF3; x&#xF3;a books tr&#x1B0;&#x1EDB;c khi x&#xF3;a author n&#xF3;i nh&#x1B0; v&#x1EAD;y cho n&#xF3; d&#x1EC5; hi&#x1EC3;u nha. C&#xF2;n s&#x1EED; d&#x1EE5;ng trong tr&#x1B0;&#x1EDD;ng h&#x1EE3;p n&#xE0;o th&#xEC; c&#xE1;c b&#x1EA1;n t&#xEC;m hi&#x1EC3;u th&#xEA;m <a href="https://mongoosejs.com/docs/middleware.html#pre">t&#x1EA1;i &#x111;&#xE2;y nha</a>.<br>
Trong <code>models</code> c&#xF3; file <strong>author.model.js</strong> &#x111;&#xE2;y l&#xE0; n&#x1A1;i ch&#x1EE9;a c&#xE1;c schema c&#x1EE7;a author. Tr&#x1B0;&#x1EDB;c ti&#xEA;n b&#x1EA1;n c&#x1EA7;n require cho m&#xEC;nh <em>model Book</em> v&#xE0; sau &#x111;&#xF3; g&#x1ECD;i pre middleware function.<br>
Khi b&#x1EA1;n g&#x1ECD;i <code>next()</code> th&#xEC; n&#xF3; s&#x1EBD; &#x111;&#x1B0;&#x1EE3;c chuy&#x1EC3;n sang middleware ti&#x1EBF;p theo nh&#x1B0;ng m&#xE0; v&#x1EAB;n ch&#x1EA1;y c&#xE2;u l&#x1EC7;nh b&#xEA;n d&#x1B0;&#x1EDB;i middleware hi&#x1EC7;n t&#x1EA1;i.<br>
Nh&#x1EEF;ng tr&#x1B0;&#x1EDD;ng h&#x1EE3;p n&#xE0;o m&#xE0; b&#x1EA1;n s&#x1EED; d&#x1EE5;ng d&#x1EE5;ng Pre</p>
<pre><code>const Book = require(&apos;../models/books.model&apos;)

authorSchema.pre(&apos;remove&apos;, function(next) {
    // S&#x1EBD; t&#xEC;m nh&#x1EEF;ng books c&#xF3; id author m&#xE0; b&#x1EA1;n x&#xF3;a
    Book.find({author: this.id}, (err, books) =&gt; {
        if (err) {
            next (err)
        } else if (books.length &gt; 0) { // N&#x1EBF;u author &#x111;&#xF3; c&#xF3; t&#x1EA1;o books th&#xEC; s&#x1EBD; x&#xF3;a to&#xE0;n b&#x1ED9; books
            books.forEach(book =&gt; book.remove())
            next()
        } else {
            next()
        }
    })
})
</code></pre>
<p><strong>V&#xE0; &#x111;&#xE2;y l&#xE0; k&#x1EBF;t qu&#x1EA3; khi ch&#xFA;ng ta th&#x1EF1;c hi&#x1EC7;n x&#xF3;a author nha:</strong></p>
<img src="https://media.giphy.com/media/h2H6ltJzXk9QSStrqh/giphy.gif" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Books Store V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB - Ph&#x1EA7;n 3">
<p>V&#x1EAD;y l&#xE0; k&#x1EBF;t th&#xFA;c ph&#x1EA7;n 3 r&#x1ED3;i nha m&#x1EDD;i c&#xE1;c b&#x1EA1;n xem ti&#x1EBF;p ph&#x1EA7;n 4<br>
<strong>To Be Continued !!</strong></p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h1 id="likt">L&#x1EDD;i K&#x1EBF;t</h1>
<p>V&#x1EAD;y l&#xE0; xong b&#xE0;i H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Books Store V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB - Ph&#x1EA7;n 3 r&#x1ED3;i nh&#xE9;. C&#xE1;c b&#x1EA1;n xem ph&#x1EA7;n ti&#x1EBF;p theo nha m&#xEC;nh chia th&#xE0;nh nhi&#x1EC1;u ph&#x1EA7;n ra &#x111;&#x1EC3; c&#xE1;c b&#x1EA1;n c&#xF3; th&#x1EC3; &#x111;&#x1ECD;c v&#xE0; l&#xE0;m m&#x1ED9;t c&#xE1;ch d&#x1EC5; d&#xE0;ng h&#x1A1;n r&#xE0;nh m&#x1EA1;ch v&#xE0; d&#x1EC5; hi&#x1EC3;u h&#x1A1;n.<br>
<strong>C&#xE1;c b&#x1EA1;n nh&#x1EDB; like v&#xE0; theo d&#xF5;i fanpage <a href="https://www.facebook.com/thanhlongdev/">Thanh Long Dev</a> &#x111;&#x1EC3; nh&#x1EAD;n nh&#x1EEF;ng th&#xF4;ng b&#xE1;o v&#x1EC1; b&#xE0;i vi&#x1EBF;t m&#x1EDB;i nh&#x1EA5;t nha.</strong><br>
<em><strong>N&#x1EBF;u c&#xE1;c b&#x1EA1;n c&#x1EA3;m th&#x1EA5;y b&#xE0;i vi&#x1EBF;t c&#x1EE7;a m&#xEC;nh hay th&#xEC; c&#xE1;c b&#x1EA1;n c&#xF3; th&#x1EC3; &#x1EE7;ng h&#x1ED9; m&#xEC;nh &#x111;&#x1EC3; m&#xEC;nh c&#xF3; th&#xEA;m &#x111;&#x1ED9;ng l&#x1EF1;c &#x111;&#x1EC3; ra nh&#x1EEF;ng b&#xE0;i topic hay v&#xE0; ch&#x1EA5;t l&#x1B0;&#x1EE3;ng h&#x1A1;n &#x1EE7;ng h&#x1ED9; m&#xEC;nh <a href="https://vrdonate.vn/thanhlongdev">t&#x1EA1;i &#x111;&#xE2;y nha.</a></strong></em><br>
<strong>Ch&#xFA;c C&#xE1;c B&#x1EA1;n Th&#xE0;nh C&#xF4;ng!!</strong></p>
<!--kg-card-end: markdown--><!--kg-card-begin: html--><iframe src="https://www.facebook.com/plugins/like.php?href=https%3A%2F%2Fwww.thanhlongdev.com%2Fhuong-dan-xay-dung-books-store-voi-nodejs-express-va-mongodb-phan3%2F&amp;width=450&amp;layout=standard&amp;action=like&amp;size=large&amp;share=true&amp;height=35&amp;appId=2794898430534168" width="450" height="35" style="border:none;overflow:hidden" scrolling="no" frameborder="0" allowtransparency="true" allow="encrypted-media"></iframe><!--kg-card-end: html--><!--kg-card-begin: html--><div class="fb-comments" data-href="https://www.thanhlongdev.com/huong-dan-xay-dung-books-store-voi-nodejs-express-va-mongodb-phan3/" data-width="100%" data-numposts="10"></div><!--kg-card-end: html-->]]></content:encoded></item><item><title><![CDATA[Hướng Dẫn Xây Dựng Books Store Với NodeJS, Express và MongoDB - Phần 2]]></title><description><![CDATA[<!--kg-card-begin: markdown--><h2 id="chcnnghinthvtomibooks">Ch&#x1EE9;c N&#x103;ng Hi&#x1EC3;n Th&#x1ECB; V&#xE0; T&#x1EA1;o M&#x1EDB;i Books</h2>
<h3 id="nhngharoutertomitrongbooks">&#x110;&#x1ECB;nh Ngh&#x129;a Router T&#x1EA1;o M&#x1EDB;i Trong Books</h3>
<p>Trong th&#x1B0; m&#x1EE5;c <strong>routes</strong> c&#xF3; file <code>books.routes.js</code> th&#xEC;</p>]]></description><link>https://www.thanhlongdev.com/huong-dan-xay-dung-books-store-express-nodejs-phan2/</link><guid isPermaLink="false">5f389ee22adbf300017a1139</guid><category><![CDATA[Lập Trình Web]]></category><dc:creator><![CDATA[Đặng Thanh Long]]></dc:creator><pubDate>Sat, 29 Aug 2020 02:26:33 GMT</pubDate><media:content url="https://digitalpress.fra1.cdn.digitaloceanspaces.com/4tg23ij/2020/08/33-2.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h2 id="chcnnghinthvtomibooks">Ch&#x1EE9;c N&#x103;ng Hi&#x1EC3;n Th&#x1ECB; V&#xE0; T&#x1EA1;o M&#x1EDB;i Books</h2>
<h3 id="nhngharoutertomitrongbooks">&#x110;&#x1ECB;nh Ngh&#x129;a Router T&#x1EA1;o M&#x1EDB;i Trong Books</h3>
<img src="https://digitalpress.fra1.cdn.digitaloceanspaces.com/4tg23ij/2020/08/33-2.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Books Store V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB - Ph&#x1EA7;n 2"><p>Trong th&#x1B0; m&#x1EE5;c <strong>routes</strong> c&#xF3; file <code>books.routes.js</code> th&#xEC; trong n&#xE0;y s&#x1EBD; l&#xE0; n&#x1A1;i ch&#x1EE9;a to&#xE0;n b&#x1ED9; c&#xE1;c source li&#xEA;n quan &#x111;&#x1EBF;n books.<br>
Tr&#x1B0;&#x1EDB;c ti&#xEA;n c&#xE1;c b&#x1EA1;n t&#x1EA1;o cho m&#xEC;nh router create books tr&#x1B0;&#x1EDB;c &#x111;&#xE3; nha, trong router n&#xE0;y n&#xF3; s&#x1EBD; bao g&#x1ED3;m 2 router &#x111;&#xF3; l&#xE0; <code>router.get(&apos;/new&apos;)</code> v&#xE0; <code>router.post(&apos;/&apos;)</code>. <strong>Router.get</strong> n&#xF3; th&#x1EF1;c hi&#x1EC7;n nhi&#x1EC7;m v&#x1EE5; get data v&#xE0; render ra views tr&#x1EA3; v&#x1EC1; ph&#xED;a client c&#xF2;n <strong>router.post</strong> s&#x1EBD; g&#x1EED;i d&#x1EEF; li&#x1EC7;u c&#x1EE7;a books l&#xEA;n server. C&#xE1;c b&#x1EA1;n ch&#x1EC9; c&#x1EA7;n t&#x1EA1;o v&#xE0; render ra views tr&#x1B0;&#x1EDB;c cho m&#xEC;nh &#x111;&#xE3; nha v&#xE0; require model author v&#xE0;o nha model n&#xE0;y l&#xE0; m&#xEC;nh &#x111;&#xE3; &#x111;&#x1ECB;nh ngh&#x129;a tr&#x1B0;&#x1EDB;c &#x111;&#xF3; r&#x1ED3;i nha. M&#xEC;nh c&#x169;ng n&#xF3;i s&#x1A1; qua m&#x1ED9;t ch&#xFA;t l&#xE0; trong books n&#xE0;y m&#xEC;nh s&#x1EBD; t&#x1EA1;o c&#xE1;c fields nh&#x1B0;: title, description, author, cover image, page count, publishDate.<br>
<strong>&#x110;&#x1EA5;y c&#xE1;c b&#x1EA1;n xem b&#x1EE9;c h&#xEC;nh &#x1EDF; d&#x1B0;&#x1EDB;i th&#xEC; s&#x1EBD; hi&#x1EC3;u r&#xF5; h&#x1A1;n nha, b&#x1EE9;c h&#xEC;nh &#x111;&#x1EA5;y m&#xEC;nh ch&#x1EC9; m&#xF4; t&#x1EA3; s&#x1A1; qua th&#xF4;i nha.</strong></p>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1598367297/Untitled_xbkk8q.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Books Store V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB - Ph&#x1EA7;n 2">
<pre><code>const express = require(&quot;express&quot;) 
const router = express.Router()
const Author = require(&quot;../models/author.model&quot;) 

   router.get(&apos;/new&apos;, async (req, res, next) =&gt; {
    try {
        const authors = await Author.find()// find author v&#x1EDB;i m&#x1EE5;c &#x111;&#xED;ch l&#xE0; &#x111;&#x1EC3; t&#x1EA1;o books bao g&#x1ED3;m vi&#x1EC7;c ch&#x1ECD;n author trong t&#x1EA1;o books
        const book = new Book()// T&#x1EA1;o m&#x1ED9;t object r&#x1ED7;ng &#x111;&#x1EC3; c&#xF3; th&#x1EC3; truy&#x1EC1;n data v&#xE0; render

        res.render(&apos;books/new&apos;, {
            authors: authors,
            book: book
        })
    } catch{
        res.redirect(&apos;/books&apos;)
    }
   });
    
    
    // Create New Books
    router.post(&apos;/&apos;, async (req, res) =&gt; {
    ....... 
    ....... 
    ); 
</code></pre>
<h3 id="giaodintomitrongbooks">Giao Di&#x1EC7;n T&#x1EA1;o M&#x1EDB;i Trong Books</h3>
<p>Trong <code>views</code> b&#x1EA1;n t&#x1EA1;o cho m&#xEC;nh th&#x1B0; m&#x1EE5;c l&#xE0; <code>books</code> s&#x1EBD; bao g&#x1ED3;m 4 file <code>index.pug</code>, <code>new.pug</code>, <code>show.pug</code>, <code>edit.pug</code>.<br>
Tr&#x1B0;&#x1EDB;c ti&#xEA;n c&#xE1;c b&#x1EA1;n nh&#x1EDB; extends layout v&#xE0;o nha v&#xE0; t&#x1EA1;o cho m&#xEC;nh m&#x1ED9;t form s&#x1EBD; ch&#x1EE9;a c&#xE1;c fields m&#xE0; m&#xEC;nh &#x111;&#xE3; n&#xF3;i &#x1EDF; tr&#xEA;n nha.<br>
<strong>books/new.pug</strong></p>
<pre><code>extends ../layouts/layout
block content
  .container
    h2 New Books
    form(action=&quot;/books&quot; method=&quot;POST&quot;)
     div
      div
        label(for=&quot;name&quot; ) Title
        input(placeholder=&quot;Title&quot;, type=&quot;text&quot; name=&quot;title&quot; value=book.title )
      div   
        label(for=&quot;author&quot;) Author
        select(name=&quot;author&quot;)
          each author in authors 
            if author.id === book.author
              option(selected label=author.name, value=author.id)
            else
              option( label=author.name, value=author.id)
     div
      div
        label(for=&quot;publish date&quot;) Publish Date
        input(type=&quot;date&quot; name=&quot;publishDate&quot; 
                    value= book.publishDate == null ? &apos;&apos; :
                    book.publishDate.toISOString().split(&apos;T&apos;)[0]) // C&#xE1;i n&#xE0;y m&#xEC;nh s&#x1EED; d&#x1EE5;ng to&#xE1;n t&#x1EED; 3 ng&#xF4;i nha, N&#x1EBF;u publishDate kh&#xF4;ng c&#xF3; gi&#xE1; tr&#x1ECB;(true) th&#xEC; n&#xF3; s&#x1EBD; c&#xF3; d&#x1EA1;ng m&#x1ED9;t empty string v&#xE0; ng&#x1B0;&#x1EE3;c l&#x1EA1;i

      div
        label(for=&quot;page count&quot;) Page Count 
        input(placeholder=&quot;Page Count&quot;,type=&quot;number&quot; name=&quot;pageCount&quot; min=&quot;1&quot; value= book.pageCount )                
     div
      div
        label(for=&quot;coverImg&quot;) Image Cover
        input(type=&quot;file&quot; name=&quot;ImageUrl&quot; required)                
  
      div
       label(for=&quot;description&quot;) Description
       textarea(name=&quot;description&quot;, book.description )    
     div
            a(href=&quot;/books&quot;) Cancel
            button(type=&quot;submit&quot;) Create
</code></pre>
<p><strong>V&#xE0; &#x111;&#xE2;y l&#xE0; giao di&#x1EC7;n khi c&#x103;n b&#x1EA3;n khi ch&#xFA;ng ta t&#x1EA1;o books</strong></p>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1598451791/12_upkefv.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Books Store V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB - Ph&#x1EA7;n 2">
<h3 id="nhnghaccschemabookschomongoose">&#x110;&#x1ECB;nh Ngh&#x129;a C&#xE1;c Schema Books Cho Mongoose</h3>
<p>Nh&#x1B0; c&#xE1;c b&#x1EA1;n &#x111;&#xE3; &#x111;&#x1ECD;c &#x1EDF; tr&#xEA;n th&#xEC; c&#x1EA5;u tr&#xFA;c th&#x1B0; m&#x1EE5;c cho d&#x1EF1; &#xE1;n b&#xEA;n trong th&#x1B0; m&#x1EE5;c <code>src</code> c&#xE1;c b&#x1EA1;n t&#x1EA1;o cho m&#xEC;nh th&#x1B0; m&#x1EE5;c <strong>models</strong>, b&#xEA;n trong th&#x1B0; m&#x1EE5;c <strong>models</strong> c&#xE1;c b&#x1EA1;n t&#x1EA1;o cho m&#xEC;nh file <code>books.model.js</code>. Trong file <code>books.model.js</code> c&#x1EA7;n t&#x1EA1;o m&#x1ED9;t &#x111;&#x1ED1;i t&#x1B0;&#x1EE3;ng book v&#xE0; s&#x1EBD; ch&#x1EE9;a c&#xE1;c fields nh&#x1B0; title, description, publishDate, pageCount, createdAT, ImageUrl, author c&#x1EE7;a books.<br>
Ref l&#xE0; m&#x1ED9;t option trong mongoose c&#xF3; th&#x1EC3; hi&#x1EC3;u l&#xE0; n&#xF3; s&#x1EBD; li&#xEA;n k&#x1EBF;t v&#x1EDB;i m&#x1ED9;t model n&#xE0;o &#x111;&#xF3;.<br>
CreatedAT v&#xE0; publishDate n&#xF3; kh&#xE1;c nhau &#x1EDF; ch&#x1ED7; l&#xE0; publishDate s&#x1EBD; tr&#x1EA3; v&#x1EC1; date m&#xE0; b&#x1EA1;n &#x111;&#xE3; ch&#x1ECD;n c&#xF2;n createdAT n&#xF3; s&#x1EBD; tr&#x1EA3; v&#x1EC1; &#x111;&#xFA;ng ng&#xE0;y &#x111;&#xFA;ng th&#x1EDD;i gian m&#xE0; m&#xEC;nh &#x111;&#xE3; t&#x1EA1;o books.</p>
<pre><code>const mongoose = require(&apos;mongoose&apos;);

const bookSchema = new mongoose.Schema({
    title:{type: String, required:true},
    description:{type: String, required:true},
    publishDate:{type: Date, required:true},
    pageCount:{type: Number, required:true},
    createdAT:{type: Date, required:true, default: Date.now},
    ImageUrl:{type:String, required:true},
    author:{type:mongoose.Schema.Types.ObjectId, required:true, ref:&apos;Author&apos;}
})


module.exports = mongoose.model(&apos;Book&apos;, bookSchema)
</code></pre>
<p>Tham s&#x1ED1; th&#x1EE9; nh&#x1EA5;t l&#xE0; t&#xEA;n ri&#xEA;ng cho collection s&#x1EAF;p &#x111;&#x1B0;&#x1EE3;c t&#x1EA1;o ra cho m&#xF4; h&#xEC;nh c&#x1EE7;a b&#x1EA1;n, v&#xE0; tham s&#x1ED1; th&#x1EE9; hai l&#xE0; schema m&#xE0; b&#x1EA1;n mu&#x1ED1;n d&#xF9;ng &#x111;&#x1EC3; t&#x1EA1;o ra m&#xF4; h&#xEC;nh.</p>
<h3 id="controllertomitrongbooks">Controller T&#x1EA1;o M&#x1EDB;i Trong Books</h3>
<p>C&#x169;ng trong file <code>books.routes.js</code> ta c&#xF3; <strong>router.post(&apos;/&apos;,..)</strong> d&#xF9;ng &#x111;&#x1EC3; t&#x1EA1;o books. C&#xE1;c b&#x1EA1;n nh&#x1EDB; require model c&#x1EE7;a book m&#xE0; m&#xEC;nh &#x111;&#xE3; t&#x1EA1;o v&#xE0;o nha.<br>
N&#xF3; s&#x1EBD; t&#x1EA1;o m&#x1ED9;t object r&#x1ED9;ng ch&#x1EE9;a d&#x1EEF; li&#x1EC7;u book &#x111;&#x1B0;&#x1EE3;c truy&#x1EC1;n v&#xE0;o. R&#x1ED3;i l&#x1B0;u d&#x1EEF; li&#x1EC7;u v&#xE0;o database &#x111;&#xE3; &#x111;&#x1B0;&#x1EE3;c kh&#x1EDF;i t&#x1EA1;o.<br>
Ch&#xFA;ng ta s&#x1EED; d&#x1EE5;ng try{} catch{} n&#xEA;n khi c&#xF3; l&#x1ED7;i th&#xEC; s&#x1EBD; render ra l&#x1ED7;i khi t&#x1EA1;o book.</p>
<pre><code>const Book = require(&quot;../models/books.model&quot;) 

// Create New Books
router.post(&apos;/&apos;, async (req, res) =&gt; {
    const authors = await Author.find()
    const book = new Book({
        title: req.body.title,
        author: req.body.author,
        publishDate: new Date(req.body.publishDate),
        pageCount: req.body.pageCount,
        description: req.body.description,
    })
    try {
        const newBook = await book.save()
         res.redirect(&apos;/books&apos;)
    } catch{
        res.render(&apos;books/new&apos;, {
            authors: authors,
            book: book,
            errorMessage: &apos;Error Creating Book&apos;
        })
    }
});

</code></pre>
<p>Khi m&#xEC;nh t&#x1EA1;o book th&#xE0;nh c&#xF4;ng th&#xEC; l&#x1B0;u v&#xE0;o DB v&#xE0; redirect sang trang books, b&#xE2;y gi&#x1EDD; trong <strong>router.get(&apos;/&apos;,..)</strong> c&#xE1;c b&#x1EA1;n res.send m&#x1ED9;t tin nh&#x1EAF;n g&#xEC; &#x111;&#x1EA5;y khi t&#x1EA1;o books th&#xE0;nh c&#xF4;ng ch&#x1EB3;ng h&#x1EA1;n.</p>
<pre><code>router.get(&apos;/&apos;, async (req, res, next) =&gt; {
    res.send(&apos;All books&apos;) 
  }) 
</code></pre>
<p>N&#x1EBF;u m&#xE0; c&#xF3; l&#x1ED7;i khi t&#x1EA1;o book th&#xEC; trong <strong>books/new.pug</strong> c&#xE1;c b&#x1EA1;n th&#xEA;m d&#xF2;ng code &#x1EDF; d&#x1B0;&#x1EDB;i v&#xE0;o ph&#xED;a sau th&#x1EBB; <em>h2 New Books</em> l&#xE0; &#x111;&#x1B0;&#x1EE3;c nha.</p>
<pre><code>        if locals.errorMessage 
             = errorMessage 
</code></pre>
<p><strong>&#x110;&#x1EEB;ng v&#x1ED9;i m&#x1EEB;ng ch&#x1B0;a xong m&#xF4; n&#x1EA1; :)))</strong><br>
Khi c&#xE1;c b&#x1EA1;n t&#x1EA1;o books xong r&#x1ED3;i m&#x1EDB;i nh&#x1EDB; l&#x1EA1;i l&#xE0; Cover image m&#xEC;nh ch&#x1B0;a c&#xF3; th&#xEC; l&#x1EA5;y &#x111;&#xE2;u ra &#x1EA3;nh m&#xE0; hi&#x1EC3;n th&#x1ECB; cho books &#x111;&#xE2;y. C&#xE1;c b&#x1EA1;n c&#x1EE9; y&#xEA;n t&#xE2;m m&#xEC;nh &#x111;&#xE3; c&#xF3; c&#xE1;ch =))</p>
<h3 id="uploadfilesdngcloudinary">Upload File S&#x1EED; D&#x1EE5;ng Cloudinary</h3>
<p>M&#xEC;nh s&#x1EBD; s&#x1EED; d&#x1EE5;ng k&#x1EBF;t h&#x1EE3;p multer + cloudinary &#x111;&#x1EC3; th&#x1EF1;c hi&#x1EC7;n vi&#x1EC7;c upload &#x1EA3;nh cho books C&#xE1;c b&#x1EA1;n xem &#x1EA3;nh &#x1EDF; d&#x1B0;&#x1EDB;i &#x111;&#x1EC3; bi&#x1EBF;t th&#xEA;m v&#x1EC1; nguy&#xEA;n l&#xED; ho&#x1EA1;t &#x111;&#x1ED9;ng nha:</p>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1598456949/upload_cloudi_jioium.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Books Store V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB - Ph&#x1EA7;n 2">
<p>Client(user) upload file(&#x1EA3;nh) th&#xEC; file(&#x1EA3;nh) &#x111;&#x1B0;&#x1EE3;c g&#x1EED;i l&#xEA;n server(multer). Sau &#x111;&#xF3; server s&#x1EBD; upload file(&#x1EA3;nh) l&#xEA;n cloudinary v&#xE0; cloudinary s&#x1EBD; tr&#x1EA3; v&#x1EC1; m&#x1ED9;t url c&#x1EE7;a file(&#x1EA3;nh) &#x111;&#x1EA5;y r&#x1ED3;i &#x111;&#x1B0;&#x1EE3;c l&#x1B0;u v&#xE0;o DB. T&#x1EEB; &#x111;&#xF3; ta ch&#x1EC9; c&#x1EA7;n get url c&#x1EE7;a image trong DB r&#x1ED3;i render ra ph&#xED;a client.<br>
&#x110;&#x1EA7;u ti&#xEA;n c&#xE1;c b&#x1EA1;n n&#xEA;n ch&#x1EC9;nh s&#x1EED;a trong <strong>views</strong> tr&#x1B0;&#x1EDB;c &#x111;&#xE3; nha, trong ph&#x1EA7;n views c&#x1EE7;a <strong>books/new.pug</strong> c&#xE1;c b&#x1EA1;n th&#xEA;m <code>enctype=&quot;multipart/form-data&quot;</code> v&#xE0;o trong form nha <code>form(action=&quot;/books&quot; method=&quot;POST&quot; enctype=&quot;multipart/form-data&quot;)</code>, b&#x1EDF;i v&#xEC; multer n&#xF3; ch&#x1EC9; x&#x1EED; l&#xFD; bi&#x1EC3;u m&#x1EAB;u n&#xE0;o li&#xEA;n quan &#x111;&#x1EBF;n <strong>multipart/form-data</strong></p>
<p>Ti&#x1EBF;p theo nh&#x1B0; c&#xE1;c b&#x1EA1;n &#x111;&#x1EC3; &#xFD; &#x1EDF; trong ph&#x1EA7;n c&#x1EA5;u tr&#xFA;c th&#x1B0; m&#x1EE5;c c&#xF3; folder <strong>handlers</strong> trong folder n&#xE0;y s&#x1EBD; ch&#x1EE9;a file <code>upload.multer.js</code>. Trong file n&#xE0;y l&#xE0; n&#x1A1;i m&#xE0; ch&#xFA;ng ta d&#xF9;ng &#x111;&#x1EC3; code ph&#x1EA7;n multer cho vi&#x1EC7;c upload file(&#x1EA3;nh).</p>
<pre><code>const multer = require(&apos;multer&apos;) // khai b&#xE1;o multer

module.exports = multer({
  storage: multer.diskStorage({}),
  fileFilter: (req, file, cb) =&gt; { // filFilter n&#xF3; s&#x1EBD; ki&#x1EC3;m so&#xE1;t vi&#x1EC7;c file n&#xE0;o n&#xEA;n t&#x1EA3;i l&#xEA;n v&#xE0; file n&#xE0;o kh&#xF4;ng 
    if (!file.mimetype.match(/jpe|jpeg|png|gif$i/)) { // N&#x1EBF;u kh&#xF4;ng &#x111;&#xFA;ng lo&#x1EA1;i file &#x1EA3;nh th&#xEC; s&#x1EBD; kh&#xF4;ng cho upload file v&#xE0; ng&#x1B0;&#x1EE3;c l&#x1EA1;i 
      cb(new Error(&apos;File is not supported&apos;), false)
      return
    }

    cb(null, true)
  }
})
</code></pre>
<p>Trong file <code>books.routes.js</code> th&#xEC; tr&#x1B0;&#x1EDB;c ti&#xEA;n c&#xE1;c b&#x1EA1;n nh&#x1EDB; khai b&#xE1;o file <strong>upload.multer.js</strong> v&#xE0; module <strong>cloudinary</strong>.</p>
<pre><code>const cloudinary = require(&apos;cloudinary&apos;) 
const upload = require(&apos;../handlers/upload.multer&apos;) 
</code></pre>
<h4 id="setupcloudinary">Setup Cloudinary</h4>
<p>Tr&#x1B0;&#x1EDB;c ti&#xEA;n c&#xE1;c b&#x1EA1;n v&#xE0;o website cloudinary <a href="https://cloudinary.com/users/register/free">t&#x1EA1;i &#x111;&#xE2;y</a> &#x111;&#x1EC3; &#x111;&#x103;ng k&#xFD; t&#xE0;i kho&#x1EA3;n, sau khi &#x111;&#x103;ng k&#xFD; xong th&#xEC; login th&#xE0;nh c&#xF4;ng s&#x1EBD; &#x111;&#x1B0;&#x1EE3;c v&#xE0;o trang <strong>dashboard</strong> c&#x1EE7;a cloudinary.<br>
T&#x1EA1;i &#x111;&#xE2;y c&#xE1;c b&#x1EA1;n ch&#xFA; &#xFD; cho m&#xEC;nh ph&#x1EA7;n <strong>Account Details</strong> s&#x1EBD; l&#xE0; n&#x1A1;i ch&#x1EE9;a c&#xE1;c th&#xF4;ng s&#x1ED1; m&#xE0; b&#x1EA1;n d&#xF9;ng &#x111;&#x1EC3; c&#xF3; th&#x1EC3; s&#x1EED; d&#x1EE5;ng &#x111;&#x1EC3; upload &#x1EA3;nh l&#xEA;n cloudinary.</p>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1598545847/12_xpvter.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Books Store V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB - Ph&#x1EA7;n 2">
<p>B&#xE2;y gi&#x1EDD; c&#x169;ng trong file <code>books.routes.js</code> c&#xE1;c b&#x1EA1;n c&#x1EA5;u h&#xEC;nh cloudinary v&#xE0;o nha. CLOUD_NAME, API_ID(API Key) v&#xE0; API_SECRET l&#xE0; c&#xE1;c th&#xF4;ng s&#x1ED1; m&#x1EAD;t n&#xEA;n ch&#xFA;ng ta c&#x1EA7;n l&#x1B0;u &#x1EDF; bi&#x1EBF;n m&#xF4;i tr&#x1B0;&#x1EDD;ng nha <strong>.env</strong> &#x111;&#x1EC3; n&#xF3; c&#xF3; t&#xED;nh b&#x1EA3;o m&#x1EAD;t.</p>
<pre><code>// Setup Cloudinary
cloudinary.config({
    cloud_name: process.env.CLOUD_NAME,
    api_key: process.env.API_ID,
    api_secret: process.env.API_SECRET
})

</code></pre>
<p>Trong <strong>router.post(&apos;/&apos;,...)</strong> c&#xE1;c b&#x1EA1;n ch&#x1EC9; c&#x1EA7;n kh&#x1EDF;i t&#x1EA1;o middleware upload file v&#x1EDB;i c&#x1EA5;u h&#xEC;nh nh&#x1B0; tr&#xEA;n. Sau khi x&#xE1;c &#x111;&#x1ECB;nh c&#xE1;c th&#xF4;ng s&#x1ED1; c&#x1EA5;u h&#xEC;nh Cloudinary th&#xEC; b&#xE2;y gi&#x1EDD; vi&#x1EC7;c upload l&#xEA;n cloudinary kh&#xE1; &#x111;&#x1A1;n gi&#x1EA3;n, n&#x1EBF;u c&#xE1;c b&#x1EA1;n mu&#x1ED1;n bi&#x1EBF;t th&#xEA;m v&#x1EC1; ph&#x1EA7;n upload th&#xEC; xem <a href="https://www.npmjs.com/package/cloudinary#upload">t&#x1EA1;i &#x111;&#xE2;y nha</a>.<br>
Khi upload l&#xEA;n cloudinary th&#xE0;nh c&#xF4;ng th&#xEC; url image s&#x1EBD; &#x111;&#x1B0;&#x1EE3;c l&#x1B0;u v&#xE0;o DB v&#x1EDB;i key l&#xE0; ImageUrl &#x111;&#xE3; &#x111;&#x1B0;&#x1EE3;c c&#x1EA5;u h&#xEC;nh s&#x1EB5;n.</p>
<pre><code>  // Create New Books
   router.post(&apos;/&apos;, upload.single(&apos;ImageUrl&apos;), async (req, res) =&gt; { 
        const result = await cloudinary.v2.uploader.upload(req.file.path) 
        const book = new Book({ 
            ...........
            ...........
            ...........
            ImageUrl: result.secure_url 
        }) 
        ........
        ........
        ........ 
     }); 
</code></pre>
<p><strong>V&#x1EAD;y l&#xE0; xong ph&#x1EA7;n upload file c&#x169;ng nh&#x1B0; xong ph&#x1EA7;n t&#x1EA1;o books r&#x1ED3;i nha</strong><br>
<strong>C&#xF9;ng xem k&#x1EBF;t qu&#x1EA3; n&#xE0;o:</strong></p>
<img src="https://media.giphy.com/media/kGEtnEAfvPGEOme64K/giphy.gif" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Books Store V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB - Ph&#x1EA7;n 2">
<p><strong>V&#xE0; &#x111;&#xE2;y l&#xE0; h&#xEC;nh &#x1EA3;nh sau khi &#x111;&#x1B0;&#x1EE3;c upload l&#xEA;n cloudinary v&#xE0; &#x111;&#x1B0;&#x1EE3;c l&#x1B0;u v&#xE0;o DB</strong></p>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1598667148/12_okmfdm.png" width="650" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Books Store V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB - Ph&#x1EA7;n 2">
<h3 id="nhnghavcontrollerrouterhinthtrongbooks">&#x110;&#x1ECB;nh Ngh&#x129;a V&#xE0; Controller Router Hi&#x1EC3;n Th&#x1ECB; Trong Books</h3>
<p>Trong th&#x1B0; m&#x1EE5;c routes c&#xF3; file <code>books.routes.js</code> th&#xEC; trong n&#xE0;y s&#x1EBD; l&#xE0; n&#x1A1;i ch&#x1EE9;a to&#xE0;n b&#x1ED9; c&#xE1;c source code li&#xEA;n quan &#x111;&#x1EBF;n books.<br>
Ch&#xFA;ng ta t&#x1EA1;o <code>router.get(&apos;/&apos;)</code> &#x111;&#xE2;y ch&#xED;nh l&#xE0; router c&#x1EE7;a trang books, m&#x1EE5;c &#x111;&#xED;ch c&#x1EE7;a trang n&#xE0;y l&#xE0; t&#xEC;m ki&#x1EBF;m v&#xE0; hi&#x1EC3;n th&#x1ECB; books.</p>
<p>C&#xE1;ch l&#xE0;m ch&#x1EE9;c n&#x103;ng t&#xEC;m ki&#x1EBF;m v&#xE0; hi&#x1EC3;n th&#x1ECB; c&#x1EE7;a th&#xE8;n books n&#xE0;y c&#x169;ng kh&#xF4;ng kh&#xE1;c th&#xE8;n author cho l&#x1EAF;m ch&#x1EC9; kh&#xE1;c l&#xE0; m&#xEC;nh s&#x1EBD; c&#xF3; th&#xEA;m ch&#x1EE9;c n&#x103;ng t&#xEC;m ki&#x1EBF;m theo ng&#xE0;y xu&#x1EA5;t b&#x1EA3;n sau v&#xE0; ng&#xE0;y xu&#x1EA5;t b&#x1EA3;n tr&#x1B0;&#x1EDB;c m&#xE0; th&#xF4;i.<br>
Th&#xEC; tr&#x1B0;&#x1EDB;c ti&#xEA;n c&#xE1;c b&#x1EA1;n vi&#x1EBF;t cho m&#xEC;nh h&#xE0;m try{}catch{}, trong try{} l&#xE0; n&#x1A1;i m&#xE0; ta s&#x1EBD; find Book trong DB v&#xE0; render ra author c&#xF2;n catch{} s&#x1EBD; redirect sang trang homepage n&#x1EBF;u c&#xF3; l&#x1ED7;i x&#x1EA3;y ra. C&#xF3; <strong>.exec ()</strong> hay kh&#xF4;ng c&#xF3; th&#xEC; v&#x1EC1; m&#x1EB7;t ch&#x1EE9;c n&#x103;ng hai c&#xE1;i n&#xE0;y t&#x1B0;&#x1A1;ng &#x111;&#x1B0;&#x1A1;ng nhau c&#xE1;c b&#x1EA1;n c&#xF3; th&#x1EC3; xem th&#xEA;m <a href="https://mongoosejs.com/docs/promises.html#should-you-use-exec-with-await?">t&#x1EA1;i &#x111;&#xE2;y nha</a>.</p>
<p>B&#xE2;y gi&#x1EDD; m&#xEC;nh s&#x1EBD; gi&#x1EDB;i thi&#x1EC7;u cho c&#xE1;c b&#x1EA1;n v&#x1EC1; hai th&#xE8;n &#x111;&#xF3; l&#xE0; <em>publishedAfter</em> v&#xE0; <em>publishedBefore</em> l&#xE0; nh&#x1B0; n&#xE0;o.<br>
<strong>publishedAfter</strong> c&#xF3; ngh&#x129;a l&#xE0; xu&#x1EA5;t b&#x1EA3;n sau b&#x1EDF;i v&#x1EAD;y n&#xEA;n ch&#xFA;ng ta s&#x1EBD; s&#x1EED; d&#x1EE5;ng gte l&#xE0; m&#x1ED9;t to&#xE1;n t&#x1EED; truy v&#x1EA5;n, gte c&#xF3; ngh&#x129;a l&#xE0; l&#x1EDB;n h&#x1A1;n ho&#x1EB7;c b&#x1EB1;ng.<br>
<strong>publishedBefore</strong> c&#xF3; ngh&#x129;a l&#xE0; xu&#x1EA5;t b&#x1EA3;n tr&#x1B0;&#x1EDB;c b&#x1EDF;i v&#x1EAD;y n&#xEA;n ch&#xFA;ng ta s&#x1EBD; s&#x1EED; d&#x1EE5;ng lte l&#xE0; m&#x1ED9;t to&#xE1;n t&#x1EED; truy v&#x1EA5;n, lte c&#xF3; ngh&#x129;a l&#xE0; nh&#x1ECF; h&#x1A1;n ho&#x1EB7;c b&#x1EB1;ng.</p>
<p>VD: B&#xE2;y gi&#x1EDD; b&#x1EA1;n publish books v&#xE0;o ng&#xE0;y 28 khi t&#xEC;m ki&#x1EBF;m b&#x1EA1;n ch&#x1ECD;n publishedAfter l&#xE0; ng&#xE0;y 27 v&#xE0; publishedBefore l&#xE0; ng&#xE0;y 29. Th&#xEC; c&#xF3; ph&#x1EA3;i l&#xE0; publishedAfter ta s&#x1EED; d&#x1EE5;ng gte th&#xEC; n&#xF3; s&#x1EBD; tr&#x1EA3; v&#x1EC1; c&#xE1;c ng&#xE0;y 27,28,29,30... C&#xF2;n publishedBefore ta s&#x1EED; d&#x1EE5;ng lte th&#xEC; n&#xF3; s&#x1EBD; tr&#x1EA3; v&#x1EC1; c&#xE1;c ng&#xE0;y 29,28,27,26... C&#xE1;i n&#xE0;y gi&#x1ED1;ng b&#xE0;i to&#xE1;n li&#x1EC7;t k&#xEA; b&#xE2;y gi&#x1EDD; ch&#xFA;ng ta ch&#x1EC9; c&#x1EA7;n l&#x1EA5;y giao c&#x1EE7;a 2 th&#xE8;n th&#xF4;i =))).<br>
V&#xEC; v&#x1EAD;y n&#xEA;n khi t&#xEC;m ki&#x1EBF;m th&#xEC; s&#x1EBD; hi&#x1EC3;n th&#x1ECB; k&#x1EBF;t qu&#x1EA3; t&#x1EEB; ng&#xE0;y 27-&gt;29 c&#xE1;c b&#x1EA1;n t&#xEC;m hi&#x1EC3;u th&#xEA;m <a href="https://www.w3resource.com/mongodb/mongodb-conditional-operators.php">t&#x1EA1;i &#x111;&#xE2;y nha</a>.</p>
<pre><code>// GET Books Page
router.get(&apos;/&apos;, async (req, res, next) =&gt; {
    let query = Book.find()

    if (req.query.title != null &amp;&amp; req.query.title != &apos;&apos;) {
        query = query.regex(&apos;title&apos;, new RegExp(req.query.title, &apos;i&apos;))
    }
    if (req.query.publishedAfter != null &amp;&amp; req.query.publishedAfter != &apos;&apos;) {
        query = query.gte(&apos;publishDate&apos;, req.query.publishedAfter)
    }
    if (req.query.publishedBefore != null &amp;&amp; req.query.publishedBefore != &apos;&apos;) {
        query = query.lte(&apos;publishDate&apos;, req.query.publishedBefore)
    }

    try {
        const books = await query.exec()
        res.render(&apos;books/index&apos;, {
            books: books,
            searchOptions: req.query
        })
    } catch{
        res.redirect(&apos;/&apos;)
    }
});
</code></pre>
<h3 id="giaodinhinthtrongbooks">Giao Di&#x1EC7;n Hi&#x1EC3;n Th&#x1ECB; Trong Books</h3>
<p>Trong <code>views</code> b&#x1EA1;n t&#x1EA1;o cho m&#xEC;nh th&#x1B0; m&#x1EE5;c l&#xE0; books s&#x1EBD; bao g&#x1ED3;m 4 file <code>index.pug</code>, <code>new.pug</code>, <code>show.pug</code>, <code>edit.pug</code>.<br>
Tr&#x1B0;&#x1EDB;c ti&#xEA;n c&#xE1;c b&#x1EA1;n extends layout v&#xE0;o nha v&#xE0; l&#x1EB7;p qua c&#xE1;c books &#x111;&#x1EC3; hi&#x1EC3;n th&#x1ECB; ra cover image v&#xE0; title c&#x1EE7;a books, nh&#x1EDB; b&#x1ECD;c &#x1EDF; ngo&#xE0;i l&#xE0; m&#x1ED9;t th&#x1EBB; a nha c&#xE1;c b&#x1EA1;n &#x111;&#x1EEB;ng quan t&#xE2;m c&#xE1;i books id &#x111;&#xF3; v&#x1ED9;i nha ch&#x1EC9; c&#x1EA7;n bi&#x1EBF;t l&#xE0; n&#xF3; s&#x1EBD; l&#xE0;m ch&#x1EE9;c n&#x103;ng show detail l&#xE0; &#x111;&#x1B0;&#x1EE3;c r&#x1ED3;i. T&#x1EA1;o m&#x1ED9;t form &#x111;&#x1EC3; l&#xE0;m &#xF4; t&#xEC;m ki&#x1EBF;m cho author v&#x1EDB;i method=&quot;GET&quot; nha.<br>
SearchOptions n&#xE0;y l&#xE0; m&#x1ED9;t object do m&#xEC;nh &#x111;&#xE3; &#x111;&#x1ECB;nh ngh&#x129;a req.query &#x1EDF; tr&#xEA;n b&#xE2;y gi&#x1EDD; mu&#x1ED1;n l&#x1EA5;y value th&#xEC; ta c&#x1EA7;n <strong>.title</strong>, <strong>.publishedAfter</strong> v&#xE0; <strong>.publishedBefore</strong> &#x111;&#x1EC3; c&#xF3; th&#x1EC3; l&#x1EA5;y &#x111;&#x1B0;&#x1EE3;c value c&#x1EE7;a ch&#xFA;ng.<br>
<strong>books/index.pug</strong></p>
<pre><code>extends ../layouts/layout

block content
  .container
    h2 Search Books
    form(action=&quot;/books&quot; method=&quot;GET&quot;)
      div 
       label(for=&quot;title&quot;) Title 
       input(placeholder=&quot;Title Book&quot;,type=&quot;text&quot; name=&quot;title&quot; value=searchOptions.title)
      div
       div
        label(for=&quot;published-after&quot;) Published After 
        input( type=&quot;date&quot; name=&quot;publishedAfter&quot; value=searchOptions.publishedAfter)
       div
        label(for=&quot;published-before&quot;) Published Before 
        input(type=&quot;date&quot; name=&quot;publishedBefore&quot; value=searchOptions.publishedBefore)
      div
        button(type=&quot;submit&quot;) Search
    div
      each book in books
         a(href=&apos;/books/&apos; + book.id)
           img(src=book.ImageUrl, width=&quot;250&quot; height=&quot;280&quot;)
           h3= book.title
</code></pre>
<p><strong>L&#x1B0;u &#xFD;</strong>: M&#xEC;nh c&#xF3; c&#x1EAD;p nh&#x1EAD;t l&#x1EA1;i code t&#x1EA1;i m&#x1ED9;t s&#x1ED1; ch&#x1ED7; n&#xEA;n khi b&#x1EA1;n th&#x1EA5;y tr&#xEA;n &#x1EA3;nh gif s&#x1EBD; kh&#xF4;ng &#x111;&#x1B0;&#x1EE3;c ch&#xED;nh x&#xE1;c cho l&#x1EAF;m nha.<br>
<strong>V&#xE0; &#x111;&#xE2;y l&#xE0; k&#x1EBF;t qu&#x1EA3; khi ch&#xFA;ng ta hi&#x1EC3;n th&#x1ECB; v&#xE0; t&#xEC;m ki&#x1EBF;m books nha:</strong></p>
<img src="https://media.giphy.com/media/jUtvBiR5HoGqF621AR/giphy.gif" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Books Store V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB - Ph&#x1EA7;n 2">
<p>V&#x1EAD;y l&#xE0; k&#x1EBF;t th&#xFA;c ph&#x1EA7;n 2 r&#x1ED3;i nha m&#x1EDD;i c&#xE1;c b&#x1EA1;n xem ti&#x1EBF;p ph&#x1EA7;n 3<br>
<strong>To Be Continued !!</strong></p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h1 id="likt">L&#x1EDD;i K&#x1EBF;t</h1>
<p>V&#x1EAD;y l&#xE0; xong b&#xE0;i H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Books Store V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB - Ph&#x1EA7;n 2 r&#x1ED3;i nh&#xE9;. C&#xE1;c b&#x1EA1;n xem ph&#x1EA7;n ti&#x1EBF;p theo nha m&#xEC;nh chia th&#xE0;nh nhi&#x1EC1;u ph&#x1EA7;n ra &#x111;&#x1EC3; c&#xE1;c b&#x1EA1;n c&#xF3; th&#x1EC3; &#x111;&#x1ECD;c v&#xE0; l&#xE0;m m&#x1ED9;t c&#xE1;ch d&#x1EC5; d&#xE0;ng h&#x1A1;n r&#xE0;nh m&#x1EA1;ch v&#xE0; d&#x1EC5; hi&#x1EC3;u h&#x1A1;n.<br>
<strong>C&#xE1;c b&#x1EA1;n nh&#x1EDB; like v&#xE0; theo d&#xF5;i fanpage <a href="https://www.facebook.com/thanhlongdev/">Thanh Long Dev</a> &#x111;&#x1EC3; nh&#x1EAD;n nh&#x1EEF;ng th&#xF4;ng b&#xE1;o v&#x1EC1; b&#xE0;i vi&#x1EBF;t m&#x1EDB;i nh&#x1EA5;t nha.</strong><br>
<em><strong>N&#x1EBF;u c&#xE1;c b&#x1EA1;n c&#x1EA3;m th&#x1EA5;y b&#xE0;i vi&#x1EBF;t c&#x1EE7;a m&#xEC;nh hay th&#xEC; c&#xE1;c b&#x1EA1;n c&#xF3; th&#x1EC3; &#x1EE7;ng h&#x1ED9; m&#xEC;nh &#x111;&#x1EC3; m&#xEC;nh c&#xF3; th&#xEA;m &#x111;&#x1ED9;ng l&#x1EF1;c &#x111;&#x1EC3; ra nh&#x1EEF;ng b&#xE0;i topic hay v&#xE0; ch&#x1EA5;t l&#x1B0;&#x1EE3;ng h&#x1A1;n &#x1EE7;ng h&#x1ED9; m&#xEC;nh <a href="https://vrdonate.vn/thanhlongdev">t&#x1EA1;i &#x111;&#xE2;y nha.</a></strong></em><br>
<strong>Ch&#xFA;c C&#xE1;c B&#x1EA1;n Th&#xE0;nh C&#xF4;ng!!</strong></p>
<!--kg-card-end: markdown--><!--kg-card-begin: html--><iframe src="https://www.facebook.com/plugins/like.php?href=https%3A%2F%2Fwww.thanhlongdev.com%2Fhuong-dan-xay-dung-books-store-express-nodejs-phan2%2F&amp;width=450&amp;layout=standard&amp;action=like&amp;size=large&amp;share=true&amp;height=35&amp;appId=2794898430534168" width="450" height="35" style="border:none;overflow:hidden" scrolling="no" frameborder="0" allowtransparency="true" allow="encrypted-media"></iframe><!--kg-card-end: html--><!--kg-card-begin: html--><div class="fb-comments" data-href="https://www.thanhlongdev.com/huong-dan-xay-dung-books-store-express-nodejs-phan2/" data-width="100%" data-numposts="10"></div><!--kg-card-end: html-->]]></content:encoded></item><item><title><![CDATA[Hướng Dẫn Xây Dựng Books Store Với NodeJS, Express và MongoDB - Phần 1]]></title><description><![CDATA[<!--kg-card-begin: markdown--><h1 id="giithiuchung">Gi&#x1EDB;i Thi&#x1EC7;u Chung</h1>
<p>H&#xF4;m nay m&#xEC;nh s&#x1EBD; h&#x1B0;&#x1EDB;ng d&#x1EAB;n c&#xE1;c b&#x1EA1;n x&#xE2;y d&#x1EF1;ng m&#x1ED9;t project books store v&#x1EDB;i NodeJS, Express v&#xE0; MongoDB.<br>
M&</p>]]></description><link>https://www.thanhlongdev.com/huong-dan-xay-dung-books-store-express-nodejs-phan1/</link><guid isPermaLink="false">5eb921b2f3d8ce0001b4a93b</guid><category><![CDATA[Lập Trình Web]]></category><dc:creator><![CDATA[Đặng Thanh Long]]></dc:creator><pubDate>Sat, 22 Aug 2020 02:57:25 GMT</pubDate><media:content url="https://digitalpress.fra1.cdn.digitaloceanspaces.com/4tg23ij/2020/08/33-1.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h1 id="giithiuchung">Gi&#x1EDB;i Thi&#x1EC7;u Chung</h1>
<img src="https://digitalpress.fra1.cdn.digitaloceanspaces.com/4tg23ij/2020/08/33-1.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Books Store V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB - Ph&#x1EA7;n 1"><p>H&#xF4;m nay m&#xEC;nh s&#x1EBD; h&#x1B0;&#x1EDB;ng d&#x1EAB;n c&#xE1;c b&#x1EA1;n x&#xE2;y d&#x1EF1;ng m&#x1ED9;t project books store v&#x1EDB;i NodeJS, Express v&#xE0; MongoDB.<br>
M&#x1EE5;c &#x111;&#xED;ch c&#x1EE7;a b&#xE0;i n&#xE0;y l&#xE0; m&#xEC;nh mong mu&#x1ED1;n gi&#xFA;p c&#xE1;c b&#x1EA1;n n&#x1EAF;m v&#xE0; &#xF4;n l&#x1EA1;i c&#xE1;c ki&#x1EBF;n th&#x1EE9;c m&#xE0; m&#xEC;nh &#x111;&#x1B0;&#x1EE3;c h&#x1ECD;c th&#xF4;ng qua c&#xE1;c project c&#x103;n b&#x1EA3;n.<br>
M&#xEC;nh s&#x1EBD; vi&#x1EBF;t m&#x1ED9;t c&#xE1;ch t&#x1EAD;n t&#xEC;nh v&#xE0; chu &#x111;&#xE1;o mong c&#xE1;c b&#x1EA1;n xem &#x111;&#x1EA7;y &#x111;&#x1EE7; v&#xE0; k&#x1EF9; c&#xE0;ng. Th&#x1EBF; l&#xE0; m&#xEC;nh vui l&#x1EAF;m r&#x1ED3;i =))</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h1 id="btulmthino">B&#x1EAF;t &#x110;&#x1EA7;u L&#xE0;m Th&#xF4;i N&#xE0;o</h1>
<h2 id="lntng">L&#xEA;n &#xDD; T&#x1B0;&#x1EDF;ng</h2>
<p>Th&#xEC; &#xFD; t&#x1B0;&#x1EDF;ng c&#x1EE7;a b&#xE0;i n&#xE0;y c&#x169;ng d&#x1EF1;a theo c&#xE1;c ph&#x1B0;&#x1A1;ng th&#x1EE9;c Rest &#x111;&#x1EC3; m&#xE0; l&#xE0;m th&#xF4;i &#x111;&#xF3; l&#xE0; Get, Post, Put v&#xE0; Delete,... v&#x1EEB;a gi&#xFA;p c&#xE1;c b&#x1EA1;n h&#x1ECD;c th&#xEA;m c&#x169;ng nh&#x1B0; &#xF4;n l&#x1EA1;i c&#xE1;c ki&#x1EBF;n th&#x1EE9;c m&#xEC;nh &#x111;&#x1B0;&#x1EE3;c h&#x1ECD;c.<br>
Books Store g&#x1ED3;m hai ph&#x1EA7;n ch&#xED;nh &#x111;&#xF3; l&#xE0; books v&#xE0; author.<br>
Project c&#x1EE7;a ch&#xFA;ng ta s&#x1EBD; g&#x1ED3;m c&#xE1;c ch&#x1EE9;c n&#x103;ng nh&#x1B0; sau: t&#x1EA1;o/xem/s&#x1EED;a/x&#xF3;a/t&#xEC;m ki&#x1EBF;m,.. books v&#xE0; author.<br>
<strong>V&#xE0; &#x111;&#x1EC3; bi&#x1EBF;t n&#xF3; &#x111;&#x1B0;&#x1EE3;c l&#xE0;m nh&#x1B0; th&#x1EBF; n&#xE0;o th&#xEC; c&#xE1;c b&#x1EA1;n c&#xF9;ng xem ti&#x1EBF;p ph&#xED;a d&#x1B0;&#x1EDB;i nha :))</strong></p>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1597221211/Untitled_fmmizx.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Books Store V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB - Ph&#x1EA7;n 1">
<h2 id="citvthitlp">C&#xE0;i &#x110;&#x1EB7;t V&#xE0; Thi&#x1EBF;t L&#x1EAD;p</h2>
<p>Tr&#x1B0;&#x1EDB;c ti&#xEA;n c&#xE1;c b&#x1EA1;n t&#x1EA1;o cho m&#xEC;nh m&#x1ED9;t folder trong folder &#x111;&#xF3; l&#xE0; n&#x1A1;i ch&#x1EE9;a c&#xE1;c th&#x1B0; m&#x1EE5;c d&#xF9;ng &#x111;&#x1EC3; m&#xEC;nh code project library books.<br>
&#x110;&#x1EC3; m&#xE0; c&#xE0;i c&#xE1;c module tr&#x1B0;&#x1EDB;c h&#x1EBF;t c&#xE1;c b&#x1EA1;n ph&#x1EA3;i c&#xE0;i &#x111;&#x1EB7;t NodeJS <a href="https://nodejs.org/en/download/">t&#x1EA1;i &#x111;&#xE2;y</a>.<br>
Kh&#x1EDF;i t&#x1EA1;o &#x1EE9;ng d&#x1EE5;ng v&#x1EDB;i file <strong>package.json</strong><br>
Trong th&#x1B0; m&#x1EE5;c g&#x1ED1;c c&#x1EE7;a &#x1EE9;ng d&#x1EE5;ng c&#x1EE7;a b&#x1EA1;n v&#xE0; nh&#x1EAD;p npm init &#x111;&#x1EC3; kh&#x1EDF;i t&#x1EA1;o &#x1EE9;ng d&#x1EE5;ng c&#x1EE7;a b&#x1EA1;n v&#x1EDB;i t&#x1EC7;p <strong>package.json</strong>.<br>
<code>npm init</code><br>
Sau &#x111;&#xF3; c&#xE1;c b&#x1EA1;n c&#xE0;i &#x111;&#x1EB7;t c&#xE1;c module &#x1EDF; d&#x1B0;&#x1EDB;i &#x111;&#x1EC3; thi&#x1EBF;t l&#x1EAD;p &#x1EE9;ng d&#x1EE5;ng nha.</p>
<ul>
<li><strong>npm install express --save</strong><br>
Module d&#xF9;ng &#x111;&#x1EC3; c&#xE0;i &#x111;&#x1EB7;t framework express c&#x1EE7;a nodejs gi&#xFA;p c&#xE1;c b&#x1EA1;n code m&#x1ED9;t c&#xE1;ch t&#x1ED1;i gi&#x1EA3;n c&#x169;ng nh&#x1B0; nhanh ch&#xF3;ng h&#x1A1;n.</li>
<li><strong>npm install body-parse --save</strong><br>
Body-parser l&#xE0; m&#x1ED9;t middleware d&#xF9;ng &#x111;&#x1EC3; x&#x1EED; l&#xFD; d&#x1EEF; li&#x1EC7;u c&#xE1;c <code>HTTP POST</code> request</li>
<li><strong>npm install pug --save</strong><br>
Pug n&#xF3; ch&#x1EC9; l&#xE0; m&#x1ED9;t template engine m&#xE0; th&#xF4;i.</li>
<li><strong>npm install cloudinary --save</strong><br>
Cloudinary l&#xE0; m&#x1ED9;t d&#x1ECB;ch v&#x1EE5; &#x111;&#xE1;m m&#xE2;y cung c&#x1EA5;p gi&#x1EA3;i ph&#xE1;p cho to&#xE0;n b&#x1ED9; quy tr&#xEC;nh qu&#x1EA3;n l&#xFD; h&#xEC;nh &#x1EA3;nh c&#x1EE7;a &#x1EE9;ng d&#x1EE5;ng web.</li>
<li><strong>npm install multer --save</strong><br>
Multer l&#xE0; m&#x1ED9;t middleware x&#x1EED; l&#xFD; c&#xE1;c d&#x1EEF; li&#x1EC7;u <code>multipart/form-data</code> ch&#x1EE7; y&#x1EBF;u l&#xE0; x&#x1EED; l&#xFD; t&#x1EC7;p th&#xF4;i.</li>
<li><strong>npm install method-override --save</strong><br>
Khi ch&#xFA;ng ta s&#x1EED; d&#x1EE5;ng ph&#x1B0;&#x1A1;ng th&#x1EE9;c PUT v&#xE0; DELETE trong HTML th&#xEC; g&#x1EB7;p s&#x1EF1; c&#x1ED1;. C&#xE1;c tr&#xEC;nh duy&#x1EC7;t h&#x1ED7; tr&#x1EE3; PUT v&#xE0; DELETE nh&#x1B0;ng n&#xF3; ch&#x1EC9; b&#x1EB1;ng c&#xE1;ch s&#x1EED; d&#x1EE5;ng y&#xEA;u c&#x1EA7;u qua AJAX, ch&#x1EE9; kh&#xF4;ng ph&#x1EA3;i th&#xF4;ng qua g&#x1EED;i &apos;bi&#x1EC3;u m&#x1EAB;u HTML&apos;.<br>
&#x110;&#xF3; c&#x169;ng l&#xE0; l&#xFD; do t&#x1EA1;i sao ch&#xFA;ng ta l&#x1EA1;i s&#x1EED; d&#x1EE5;ng method-override m&#x1ED9;t middleware &#x111;&#x1EC3; &apos;ghi &#x111;&#xE8; ph&#x1B0;&#x1A1;ng th&#x1EE9;c&apos; &#x111;&#x1EC3; gi&#x1EA3;i quy&#x1EBF;t v&#x1EA5;n &#x111;&#x1EC1; n&#xE0;y.<br>
<em>N&#x1EBF;u c&#xE1;c b&#x1EA1;n mu&#x1ED1;n hi&#x1EC3;u r&#xF5; h&#x1A1;n th&#xEC; t&#xEC;m hi&#x1EC3;u th&#xEA;m <a href="https://dev.to/moz5691/method-override-for-put-and-delete-in-html-3fp2">t&#x1EA1;i &#x111;&#xE2;y nha</a>.</em></li>
<li><strong>npm install nodemon --save</strong><br>
T&#x1EF1; &#x111;&#x1ED9;ng reload l&#x1EA1;i server khi b&#x1EA1;n thay &#x111;&#x1ED5;i code. &#x110;&#x1EC3; kh&#x1EDF;i ch&#x1EA1;y server c&#xE1;c b&#x1EA1;n th&#xEA;m <code>&quot;dev&quot;: &quot;nodemon src/app.js&quot;</code> v&#xE0;o file** package.json** nha. C&#xE1;c b&#x1EA1;n m&#x1EDF; terminal l&#xEA;n sau &#x111;&#xF3; g&#xF5; <code>npm run dev</code> &#x111;&#x1EC3; kh&#x1EDF;i ch&#x1EA1;y server nha.</li>
<li><strong>npm install mongoose --save</strong><br>
Mongoose l&#xE0; m&#x1ED9;t Object Document Mapper (ODM). &#x110;i&#x1EC1;u n&#xE0;y c&#xF3; ngh&#x129;a l&#xE0; Mongoose cho ph&#xE9;p b&#x1EA1;n &#x111;&#x1ECB;nh ngh&#x129;a c&#xE1;c object (&#x111;&#x1ED1;i t&#x1B0;&#x1EE3;ng) v&#x1EDB;i m&#x1ED9;t schema &#x111;&#x1B0;&#x1EE3;c &#x111;&#x1ECB;nh ngh&#x129;a r&#xF5; r&#xE0;ng.</li>
<li><strong>npm install dotenv --save</strong><br>
Dotenv l&#xE0; m&#x1ED9;t bi&#x1EBF;n m&#xF4;i tr&#x1B0;&#x1EDD;ng d&#xF9;ng &#x111;&#x1EC3; b&#x1EA3;o m&#x1EAD;t c&#xE1;c th&#xF4;ng tin quan tr&#x1ECD;ng nh&#x1B0; username, password, url database,...N&#x1EBF;u ch&#xFA;ng ta kh&#xF4;ng l&#x1B0;u nh&#x1EEF;ng th&#xF4;ng tin m&#x1EAD;t v&#xE0;o file .env th&#xEC; khi push source code l&#xEA;n github th&#xEC; ai c&#x169;ng c&#xF3; th&#x1EC3; v&#xE0;o xem &#x111;&#x1B0;&#x1EE3;c v&#xE0; ai c&#x169;ng bi&#x1EBF;t username, password th&#xEC; s&#x1EBD; b&#x1ECB; ng&#x1B0;&#x1EDD;i kh&#xE1;c chi&#x1EBF;m &#x111;o&#x1EA1;t v&#xE0; &#x111;&#xE1;nh c&#x1EAF;p t&#xE0;i li&#x1EC7;u r&#x1EA5;t l&#xE0; nguy hi&#x1EC3;m nha.<br>
<strong>V&#xE0; &#x111;&#xE2;y c&#x169;ng l&#xE0; c&#xE1;c package m&#xE0; m&#xEC;nh khi &#x111;&#xE3; c&#xE0;i &#x111;&#x1EB7;t c&#x169;ng nh&#x1B0; c&#x1EA5;u h&#xEC;nh xong.</strong></li>
</ul>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1597317303/Untitled_quaza6.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Books Store V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB - Ph&#x1EA7;n 1">
<h3 id="cutrcthmcchodn">C&#x1EA5;u Tr&#xFA;c Th&#x1B0; M&#x1EE5;c Cho D&#x1EF1; &#xC1;n</h3>
<p>Sau khi ho&#xE0;n th&#xE0;nh vi&#x1EC7;c c&#xE0;i &#x111;&#x1EB7;t module c&#xE1;c b&#x1EA1;n t&#x1EA1;o cho m&#xEC;nh m&#x1ED9;t th&#x1B0; m&#x1EE5;c src, th&#x1B0; m&#x1EE5;c n&#xE0;y d&#xF9;ng &#x111;&#x1EC3; ch&#x1EE9;a t&#x1EA5;t c&#x1EA3; c&#xE1;c file trong qu&#xE1; tr&#xEC;nh m&#xEC;nh code project.</p>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1597316944/12_h3ga4o.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Books Store V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB - Ph&#x1EA7;n 1">
<p><strong>L&#x1B0;u &#xFD;:</strong> M&#xEC;nh khuy&#xEA;n c&#xE1;c b&#x1EA1;n n&#xEA;n t&#x1EA1;o th&#xEA;m m&#x1ED9;t folder controllers v&#xE0; file &#x111;&#x1EC3; ch&#x1EE9;a c&#xE1;c logic khi m&#xEC;nh code nha. Do m&#xEC;nh code &#x111;&#x1EC3; l&#xE0;m demo cho m&#x1ECD;i ng&#x1B0;&#x1EDD;i n&#xEA;n m&#xEC;nh vi&#x1EBF;t chung v&#xE0;o th&#x1EB1;ng routes lu&#xF4;n.</p>
<h1 id="btucodethino">B&#x1EAF;t &#x110;&#x1EA7;u Code Th&#xF4;i N&#xE0;o</h1>
<h2 id="thitlpwebserver">Thi&#x1EBF;t L&#x1EAD;p Web Server</h2>
<p>Trong th&#x1B0; m&#x1EE5;c g&#x1ED1;c c&#xE1;c b&#x1EA1;n t&#x1EA1;o cho m&#xEC;nh file <code>app.js</code>, file n&#xE0;y l&#xE0; file ch&#xED;nh d&#xF9;ng &#x111;&#x1EC3; &#x111;i&#x1EC1;u khi&#x1EC3;n m&#x1ECD;i ho&#x1EA1;t &#x111;&#x1ED9;ng ch&#xED;nh c&#x1EE7;a server.<br>
Trong file n&#xE0;y c&#xE1;c b&#x1EA1;n c&#x1EA7;n import v&#xE0; enable c&#xE1;c router homepage, authors v&#xE0; books v&#xE0;o nha.<br>
V&#xE0; c&#x169;ng khai b&#xE1;o v&#xE0; enable lu&#xF4;n method-override v&#xE0; body-parser v&#xE0;o lu&#xF4;n nha.</p>
<pre><code>const express = require(&quot;express&quot;)
const app = express()
const bodyParser = require(&apos;body-parser&apos;)
const methodOverride = require(&apos;method-override&apos;)
const port = 4444

// Import routes
const IndexRouter = require(&quot;../src/routes/index.routes&quot;)
const BookRouter = require(&quot;../src/routes/books.routes&quot;)
const AuthorRouter = require(&quot;../src/routes/author.routes&quot;)

// view engine setup
app.set(&apos;view engine&apos;, &apos;pug&apos;);
app.set(&apos;views&apos;, &apos;src/views&apos;);

// Enable Static file
app.use(express.static(&apos;src/public&apos;))

// Enable Method Override
app.use(methodOverride(&apos;_method&apos;));

// Enable Body Parser
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ limit:&apos;10mb&apos; ,extended: false }));  

// Enable Routes
app.use(&apos;/&apos;, IndexRouter)
app.use(&apos;/books&apos;, BookRouter)
app.use(&apos;/authors&apos;, AuthorRouter)

app.listen(port, () =&gt; {
    console.log(`Server listening ${port}`)
})
</code></pre>
<p>Trong th&#x1B0; m&#x1EE5;c routes c&#xF3; file <code>index.routes.js</code>, c&#xE1;c b&#x1EA1;n t&#x1EA1;o cho n&#xF3; m&#x1ED9;t Route handlers v&#xE0; th&#x1EED; ch&#x1EA1;y sever xem sau. M&#x1EE5;c &#x111;&#xED;ch &#x111;&#x1EC3; c&#xE1;c b&#x1EA1;n test xem server c&#xF3; ch&#x1EA1;y kh&#xF4;ng nha.</p>
<pre><code>router.get(&apos;/&apos;, (req, res, next) =&gt; {
   res.send(&apos;Hello Everyone&apos;)
})
</code></pre>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1597321588/Untitled_lkb8gj.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Books Store V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB - Ph&#x1EA7;n 1">
<h2 id="thitlpdatabase">Thi&#x1EBF;t L&#x1EAD;p Database</h2>
<p>&#x110;&#x1EC3; m&#xE0; c&#xF3; th&#x1EC3; thi&#x1EBF;t l&#x1EAD;p &#x111;&#x1B0;&#x1EE3;c database th&#xEC; c&#xE1;c b&#x1EA1;n &#x111;&#x103;ng nh&#x1EAD;p t&#xE0;i kho&#x1EA3;n mongodb atlas <a href="https://account.mongodb.com/account/login">t&#x1EA1;i &#x111;&#xE2;y nha</a>. Sau khi c&#xE1;c b&#x1EA1;n b&#x1EA1;n &#x111;&#xE3; c&#xF3; t&#xE0;i kho&#x1EA3;n mongodb atlas th&#xEC; ti&#x1EBF;p &#x111;&#x1EBF;n c&#xE0;i &#x111;&#x1EB7;t c&#x1EA5;u h&#xEC;nh &#x111;&#x1EC3; c&#xF3; th&#x1EC3; k&#x1EBF;t n&#x1ED1;i mongodb atlas v&#x1EDB;i &#x1EE9;ng d&#x1EE5;ng c&#x1EE7;a ch&#xFA;ng ta. &#x110;&#x1EC3; bi&#x1EBF;t th&#xEA;m chi ti&#x1EBF;t c&#xE1;c b&#x1EA1;n xem b&#x1B0;&#x1EDB;c 3 trong b&#xE0;i vi&#x1EBF;t c&#x1EE7;a m&#xEC;nh h&#x1B0;&#x1EDB;ng d&#x1EAB;n deploy project nodejs l&#xEA;n heroku <a href="https://www.thanhlongdev.com/huong-dan-cach-deploy-project-nodejs-len-heroku/">t&#x1EA1;i &#x111;&#xE2;y nha</a>.<br>
Sau &#x111;&#xF3; c&#xE1;c b&#x1EA1;n copy link database mongodb &#x111;&#xE3; t&#x1EA1;o r&#x1ED3;i paste v&#xE0;o project c&#x1EE7;a m&#xEC;nh l&#xE0; &#x111;&#x1B0;&#x1EE3;c nha. C&#xE1;c b&#x1EA1;n t&#x1EA1;o cho m&#xEC;nh m&#x1ED9;t file <code>.env</code> b&#xEA;n trong th&#x1B0; m&#x1EE5;c g&#x1ED1;c.<br>
Trong file n&#xE0;y c&#xE1;c b&#x1EA1;n t&#x1EA1;o m&#x1ED9;t &#x111;&#x1B0;&#x1EDD;ng d&#x1EAB;n l&#xE0; <code>DATABASE_URL=mongodb+srv://long:&lt;password&gt;@cluster0-b7d8c.mongodb.net/test?retryWrites=true&amp;w=majority</code><br>
Trong file app.js c&#xE1;c b&#x1EA1;n khai b&#xE1;o module dotenv v&#x1EDB;i module mongoose v&#xE0; t&#x1EA1;o &#x111;&#x1B0;&#x1EDD;ng d&#x1EAB;n mongodb.</p>
<pre><code>// Khai b&#xE1;o dotenv
require(&apos;dotenv&apos;).config()

// Khai b&#xE1;o mongoose
var mongoose = require(&apos;mongoose&apos;)

// Connect database
 mongoose.connect(process.env.DATABASE_URL,{useUnifiedTopology: true,
   useNewUrlParser: true, })
 const db = mongoose.connection
  db.on(&apos;error&apos;, error =&gt; console.error(error))
  db.once(&apos;open&apos;, () =&gt; console.log(&apos;Connected to Database&apos;))
</code></pre>
<p>&#x110;&#x1EC3; bi&#x1EBF;t n&#xF3; &#x111;&#xE3; k&#x1EBF;t n&#x1ED1;i hay ch&#x1B0;a c&#xE1;c b&#x1EA1;n kh&#x1EDF;i &#x111;&#x1ED9;ng l&#x1EA1;i server s&#x1EBD; bi&#x1EBF;t nha.</p>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1597398994/Untitled_m8jcc9.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Books Store V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB - Ph&#x1EA7;n 1">
<h2 id="thitklayoutchoproject">Thi&#x1EBF;t K&#x1EBF; Layout Cho Project</h2>
<p>Trong ph&#x1EA7;n c&#x1EA5;u tr&#xFA;c th&#x1B0; m&#x1EE5;c c&#xF3; folder views trong &#x111;&#xF3; b&#x1EA1;n t&#x1EA1;o cho m&#xEC;nh 2 th&#x1B0; m&#x1EE5;c <code>layouts</code> g&#x1ED3;m c&#xF3; file <code>layout.pug</code> v&#xE0; <code>partials</code> g&#x1ED3;m c&#xF3; <code>header.pug</code>. Hai th&#x1B0; m&#x1EE5;c n&#xE0;y s&#x1EBD; n&#x1A1;i ch&#x1EE9;a b&#x1ED1; c&#x1EE5;c c&#x1EE7;a &#x1EE9;ng d&#x1EE5;ng.<br>
<strong>partials/header.pug</strong></p>
<pre><code>header
  .container
    .row
      nav.navbar.navbar-expand-lg.navbar-light
        a.navbar-brand(href=&apos;/&apos;)
          img.img-fluid(src=&apos;https://png.pngtree.com/templates_detail/20180917/book-library-education-logo-png_32062.jpg&apos;, width=&apos;50&apos;)
        button.navbar-toggler(type=&apos;button&apos;, data-toggle=&apos;collapse&apos;, data-target=&apos;#navbarNavDropdown&apos;, aria-controls=&apos;navbarNavDropdown&apos;, aria-expanded=&apos;false&apos;, aria-label=&apos;Toggle navigation&apos;)
             span.navbar-toggler-icon
        #navbarNavDropdown.collapse.navbar-collapse.justify-content-end
          ul.navbar-nav.justify-content-end
            li
              a.nav-link(href=&quot;/authors&quot;) Authors
            li
              a.nav-link(href=&quot;/authors/new&quot;) Add Author
            li
              a.nav-link(href=&quot;/books&quot;) Books
            li
              a.nav-link(href=&quot;/books/new&quot;) Add Book


</code></pre>
<p><strong>layouts/layout.pug</strong><br>
Trong n&#xE0;y b&#x1EA1;n ch&#x1EC9; c&#x1EA7;n include header v&#xE0; li&#xEA;n k&#x1EBF;t c&#xE1;c link bootstrap v&#xE0;o nha</p>
<pre><code>doctype html
html
  head
    title Books Store
    meta(charset=&apos;utf-8&apos;)
    meta(name=&apos;viewport&apos;, content=&apos;width=device-width, initial-scale=1&apos;)
    link(rel=&apos;stylesheet&apos;, href=&apos;https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css&apos;)
    link(rel=&apos;stylesheet&apos;, href=&apos;/stylesheets/style.css&apos;)
  body
    include ../partials/header.pug
    block content
    
    script(src=&apos;https://code.jquery.com/jquery-3.4.1.min.js&apos;, integrity=&apos;sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=&apos;, crossorigin=&apos;anonymous&apos;)
    script(src=&apos;https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js&apos;, integrity=&apos;sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM&apos;, crossorigin=&apos;anonymous&apos;)
</code></pre>
<h2 id="chcnnghinthvtomiauthor">Ch&#x1EE9;c N&#x103;ng Hi&#x1EC3;n Th&#x1ECB; V&#xE0; T&#x1EA1;o M&#x1EDB;i Author</h2>
<h3 id="nhngharoutertomitrongauthor">&#x110;&#x1ECB;nh Ngh&#x129;a Router T&#x1EA1;o M&#x1EDB;i Trong Author</h3>
<p>Trong th&#x1B0; m&#x1EE5;c routes c&#xF3; file <code>author.routes.js</code> th&#xEC; trong n&#xE0;y s&#x1EBD; l&#xE0; n&#x1A1;i ch&#x1EE9;a to&#xE0;n b&#x1ED9; c&#xE1;c source li&#xEA;n quan &#x111;&#x1EBF;n author.<br>
Tr&#x1B0;&#x1EDB;c ti&#xEA;n c&#xE1;c b&#x1EA1;n t&#x1EA1;o cho m&#xEC;nh hai router t&#x1EA1;o m&#x1EDB;i &#x111;&#xF3; l&#xE0; <code>router.get(&apos;/new&apos;,...)</code> v&#xE0; <code>router.post(&apos;/&apos;,...)</code> tr&#x1B0;&#x1EDB;c &#x111;&#xE3; nha. C&#xE1;c b&#x1EA1;n ch&#x1EC9; c&#x1EA7;n t&#x1EA1;o v&#xE0; render ra views tr&#x1B0;&#x1EDB;c cho m&#xEC;nh l&#xE0; &#x111;&#x1B0;&#x1EE3;c.</p>
<pre><code>const express = require(&quot;express&quot;)
const router = express.Router()

// Get New Author
router.get(&apos;/new&apos;, (req, res) =&gt; {
  res.render(&apos;authors/new&apos;, {
    author: new Author()
  });
});
  
// Create new author  
router.post(&apos;/&apos;, async (req, res) =&gt; {
   
 });
</code></pre>
<h3 id="giaodintomitrongauthor">Giao Di&#x1EC7;n T&#x1EA1;o M&#x1EDB;i Trong Author</h3>
<p>Trong <code>views</code> b&#x1EA1;n t&#x1EA1;o cho m&#xEC;nh th&#x1B0; m&#x1EE5;c l&#xE0; <code>authors</code> s&#x1EBD; bao g&#x1ED3;m 4 file <code>index.pug</code>, <code>new.pug</code>, <code>show.pug</code>, <code>edit.pug</code>.<br>
Tr&#x1B0;&#x1EDB;c ti&#xEA;n c&#xE1;c b&#x1EA1;n nh&#x1EDB; extends layout v&#xE0;o nha<br>
<strong>authors/new.pug</strong></p>
<pre><code>extends ../layouts/layout

block content
 .container
   h2 New Author
   form(action=&quot;/authors&quot; method=&quot;POST&quot;)
     label(for=&quot;name&quot;) Name
     input(placeholder=&quot;Name&quot;, type=&quot;text&quot; name=&quot;name&quot; value=author.name)
     div
      a(href=&quot;/authors&quot;) Cancel
      button(type=&quot;submit&quot;) Create  
</code></pre>
<p><strong>V&#xE0; &#x111;&#xE2;y l&#xE0; giao di&#x1EC7;n c&#x103;n b&#x1EA3;n &#x111;&#x1EC3; t&#x1EA1;o author:</strong></p>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1597929822/33_y2ehwk.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Books Store V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB - Ph&#x1EA7;n 1">
<h3 id="nhnghaccschemaauthorchomongoose">&#x110;&#x1ECB;nh Ngh&#x129;a C&#xE1;c Schema Author Cho Mongoose</h3>
<p>Nh&#x1B0; c&#xE1;c b&#x1EA1;n &#x111;&#xE3; &#x111;&#x1ECD;c &#x1EDF; tr&#xEA;n th&#xEC; c&#x1EA5;u tr&#xFA;c th&#x1B0; m&#x1EE5;c cho d&#x1EF1; &#xE1;n b&#xEA;n trong th&#x1B0; m&#x1EE5;c <code>src</code> c&#xE1;c b&#x1EA1;n t&#x1EA1;o cho m&#xEC;nh th&#x1B0; m&#x1EE5;c <strong>models</strong>, b&#xEA;n trong th&#x1B0; m&#x1EE5;c <strong>models</strong> c&#xE1;c b&#x1EA1;n t&#x1EA1;o cho m&#xEC;nh file <code>author.model.js</code>.<br>
Trong file <code>author.model.js</code> c&#x1EA7;n t&#x1EA1;o m&#x1ED9;t &#x111;&#x1ED1;i t&#x1B0;&#x1EE3;ng book v&#xE0; s&#x1EBD; ch&#x1EE9;a fields name author.</p>
<pre><code>const mongoose = require(&apos;mongoose&apos;);

const authorSchema = new mongoose.Schema({
    name:{type: String, required:true}
})

module.exports = mongoose.model(&apos;Author&apos;, authorSchema)
</code></pre>
<p>Tham s&#x1ED1; th&#x1EE9; nh&#x1EA5;t l&#xE0; t&#xEA;n ri&#xEA;ng cho collection s&#x1EAF;p &#x111;&#x1B0;&#x1EE3;c t&#x1EA1;o ra cho m&#xF4; h&#xEC;nh c&#x1EE7;a b&#x1EA1;n, v&#xE0; tham s&#x1ED1; th&#x1EE9; hai l&#xE0; schema m&#xE0; b&#x1EA1;n mu&#x1ED1;n d&#xF9;ng &#x111;&#x1EC3; t&#x1EA1;o ra m&#xF4; h&#xEC;nh.</p>
<h3 id="controllertomitrongauthor">Controller T&#x1EA1;o M&#x1EDB;i Trong Author</h3>
<p>C&#x169;ng trong file <code>authors.routes.js</code> ta c&#xF3; <strong>router.post(&apos;/&apos;,...)</strong> d&#xF9;ng &#x111;&#x1EC3; t&#x1EA1;o author. C&#xE1;c b&#x1EA1;n nh&#x1EDB; require model c&#x1EE7;a author m&#xE0; m&#xEC;nh &#x111;&#xE3; t&#x1EA1;o v&#xE0;o nha.</p>
<p><strong>Ki&#x1EC3;m tra t&#xEA;n c&#x1EE7;a author khi &#x111;&#x1B0;&#x1EE3;c t&#x1EA1;o</strong><br>
Ta s&#x1EBD; check xem t&#xEA;n &#x111;&#x1B0;&#x1EE3;c t&#x1EA1;o c&#xF3; tr&#xF9;ng v&#x1EDB;i t&#xEA;n m&#xE0; author &#x111;&#xE3; t&#x1EA1;o t&#x1EEB; tr&#x1B0;&#x1EDB;c hay kh&#xF4;ng n&#x1EBF;u tr&#xF9;ng th&#xEC; s&#x1EBD; hi&#x1EC3;n th&#x1ECB; th&#xF4;ng b&#xE1;o.<br>
B&#x1EDF;i v&#xEC; t&#xEA;n t&#xE1;c gi&#x1EA3; c&#x1EE7;a m&#x1ED9;t cu&#x1ED1;n s&#xE1;ch n&#xE0;o &#x111;&#xF3; th&#xEC; r&#x1EA5;t hi&#x1EBF;m khi tr&#xF9;ng c&#xF3; th&#x1EC3; n&#xF3;i l&#xE0; kh&#xF4;ng bao gi&#x1EDD; c&#xF3; t&#xEA;n t&#xE1;c gi&#x1EA3; gi&#x1ED1;ng, c&#xF2;n t&#xEA;n ng&#x1B0;&#x1EDD;i m&#xE0; tr&#xF9;ng nhau l&#xE0; chuy&#x1EC7;n b&#xEC;nh th&#x1B0;&#x1EDD;ng. V&#xEC; th&#x1EBF; n&#xEA;n ta c&#x1EA7;n ph&#x1EA3;i check name c&#x1EE7;a t&#xE1;c gi&#x1EA3;</p>
<p>N&#xF3; s&#x1EBD; t&#x1EA1;o m&#x1ED9;t object r&#x1ED9;ng ch&#x1EE9;a d&#x1EEF; li&#x1EC7;u author &#x111;&#x1B0;&#x1EE3;c truy&#x1EC1;n v&#xE0;o. R&#x1ED3;i l&#x1B0;u d&#x1EEF; li&#x1EC7;u v&#xE0;o database &#x111;&#xE3; &#x111;&#x1B0;&#x1EE3;c kh&#x1EDF;i t&#x1EA1;o. Ch&#xFA;ng ta s&#x1EED; d&#x1EE5;ng try{} catch{} n&#xEA;n khi c&#xF3; l&#x1ED7;i th&#xEC; s&#x1EBD; render ra l&#x1ED7;i khi t&#x1EA1;o author.</p>
<pre><code>const Author = require(&apos;../models/author.model&apos;)

// Create New Author  
router.post(&apos;/&apos;, async (req, res) =&gt; {
  const author = new Author({ name: req.body.name })
  
  // Ki&#x1EC3;m tra name author c&#xF3; t&#x1ED3;n t&#x1EA1;i hay kh&#xF4;ng
  // T&#xEC;m m&#x1ED9;t t&#xEA;n author trong DB v&#x1EDB;i t&#xEA;n &#x111;&#x1B0;&#x1EE3;c t&#x1EA1;o
  const nameAuthor = await Author.findOne({ name: req.body.name });
  
  // N&#x1EBF;u t&#xEC;m &#x111;&#x1B0;&#x1EE3;c t&#xEA;n tr&#xF9;ng nhau s&#x1EBD; render ra mess
  if (nameAuthor) {
    return res.render(&apos;authors/new&apos;, {
      author: author,
      errorMessage: &apos;Author Already Exists&apos;
    })
  }

  try {
    await author.save();
    res.redirect(&apos;/authors&apos;)
  } catch {
    res.render(&apos;authors/new&apos;, {
      author: author,
      errorMessage: &apos;Error Creating Author&apos;
    })
  }

});
</code></pre>
<p>Khi m&#xEC;nh t&#x1EA1;o author th&#xE0;nh c&#xF4;ng th&#xEC; l&#x1B0;u v&#xE0;o DB v&#xE0; redirect sang trang authors, b&#xE2;y gi&#x1EDD; trong <code>router.get(&apos;/&apos;,..)</code> c&#xE1;c b&#x1EA1;n res.send m&#x1ED9;t tin nh&#x1EAF;n g&#xEC; &#x111;&#x1EA5;y khi t&#x1EA1;o author th&#xE0;nh c&#xF4;ng ch&#x1EB3;ng h&#x1EA1;n.</p>
<pre><code>router.get(&apos;/&apos;, async (req, res) =&gt; {
  res.send(&apos;Hello Authors&apos;)  
})
</code></pre>
<p>N&#x1EBF;u m&#xE0; c&#xF3; l&#x1ED7;i khi t&#x1EA1;o author th&#xEC; trong <strong>authors/new.pug</strong> c&#xE1;c b&#x1EA1;n th&#xEA;m d&#xF2;ng code &#x1EDF; d&#x1B0;&#x1EDB;i v&#xE0;o ph&#xED;a sau th&#x1EBB; <em>h2 New Author</em> l&#xE0; &#x111;&#x1B0;&#x1EE3;c nha.</p>
<pre><code>    if locals.errorMessage
        = errorMessage
        
</code></pre>
<p><strong>V&#xE0; &#x111;&#xE2;y l&#xE0; k&#x1EBF;t qu&#x1EA3; khi ch&#xFA;ng ta t&#x1EA1;o author nha:</strong></p>
<img src="https://media.giphy.com/media/SUtwtdLvOXelB7EVrJ/giphy.gif" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Books Store V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB - Ph&#x1EA7;n 1">
<h3 id="nhnghavcontrollerrouterhinthtrongauthor">&#x110;&#x1ECB;nh Ngh&#x129;a V&#xE0; Controller Router Hi&#x1EC3;n Th&#x1ECB; Trong Author</h3>
<p>Trong th&#x1B0; m&#x1EE5;c routes c&#xF3; file <code>author.routes.js</code> th&#xEC; trong n&#xE0;y s&#x1EBD; l&#xE0; n&#x1A1;i ch&#x1EE9;a to&#xE0;n b&#x1ED9; c&#xE1;c source code li&#xEA;n quan &#x111;&#x1EBF;n author.<br>
Ch&#xFA;ng ta t&#x1EA1;o <strong>router.get(&apos;/&apos;)</strong> &#x111;&#xE2;y ch&#xED;nh l&#xE0; router c&#x1EE7;a trang authors, m&#x1EE5;c &#x111;&#xED;ch c&#x1EE7;a trang n&#xE0;y l&#xE0; t&#xEC;m ki&#x1EBF;m v&#xE0; hi&#x1EC3;n th&#x1ECB; author.</p>
<p>Th&#xEC; tr&#x1B0;&#x1EDB;c ti&#xEA;n c&#xE1;c b&#x1EA1;n vi&#x1EBF;t cho m&#xEC;nh h&#xE0;m try{}catch{}, trong try{} l&#xE0; n&#x1A1;i m&#xE0; ta s&#x1EBD; find Author trong DB v&#xE0; render ra author c&#xF2;n catch{} s&#x1EBD; redirect sang trang homepage n&#x1EBF;u c&#xF3; l&#x1ED7;i x&#x1EA3;y ra.<br>
C&#xF2;n v&#x1EC1; v&#x1EA5;n &#x111;&#x1EC1; t&#xEC;m ki&#x1EBF;m th&#xEC; m&#xEC;nh s&#x1EBD; s&#x1EED; d&#x1EE5;ng <code>req.query</code> &#x111;&#x1EC3; truy v&#x1EA5;n d&#x1EEF; li&#x1EC7;u nha k&#x1EBF;t h&#x1EE3;p v&#x1EDB;i RegExp.<br>
RegExp l&#xE0; m&#x1ED9;t chu&#x1ED7;i c&#xE1;c k&#xFD; t&#x1EF1; t&#x1EA1;o th&#xE0;nh m&#x1ED9;t m&#x1EAB;u t&#xEC;m ki&#x1EBF;m. M&#x1EAB;u t&#xEC;m ki&#x1EBF;m c&#xF3; th&#x1EC3; &#x111;&#x1B0;&#x1EE3;c s&#x1EED; d&#x1EE5;ng cho c&#xE1;c ho&#x1EA1;t &#x111;&#x1ED9;ng t&#xEC;m ki&#x1EBF;m v&#x103;n b&#x1EA3;n v&#xE0; thay th&#x1EBF; v&#x103;n b&#x1EA3;n.</p>
<p>M&#xEC;nh s&#x1EBD; gi&#x1EA3;i th&#xED;ch s&#x1A1; qua ch&#xFA;t v&#x1EC1; c&#xE1;ch ho&#x1EA1;t &#x111;&#x1ED9;ng c&#x1EE7;a ch&#x1EE9;c n&#x103;ng t&#xEC;m ki&#x1EBF;m. T&#x1EA1;o m&#x1ED9;t object r&#x1ED7;ng l&#xE0; n&#x1A1;i ch&#x1EE9;a c&#xE1;c c&#x1EB7;p key v&#xE0; value, <strong>key</strong> &#x1EDF; &#x111;&#xE2;y l&#xE0; name v&#xE0; <strong>value</strong> l&#xE0; bi&#x1EC3;u th&#x1EE9;c ch&#xED;nh quy <strong>vd: {name: /long/i}</strong>.<br>
To&#xE1;n t&#x1EED; &amp;&amp; s&#x1EBD; tr&#x1EA3; v&#x1EC1; truthy khi t&#x1EA5;t c&#x1EA3; c&#xE1;c to&#xE1;n h&#x1EA1;ng &#x111;&#x1EC1;u l&#xE0; true c&#xF3; ngh&#x129;a l&#xE0; m&#xEC;nh search c&#xF3; name c&#x1EE7;a author th&#xEC; &#x111;i&#x1EC1;u ki&#x1EC7;n n&#xF3; l&#xE0; true.</p>
<pre><code>const Author = require(&apos;../models/author.model&apos;)

// GET Authors Page
router.get(&apos;/&apos;, async (req, res) =&gt; {
   let searchOptions = {}
   if (req.query.name != null &amp;&amp; req.query.name !==&apos;&apos;){
     searchOptions.name = new RegExp(req.query.name, &apos;i&apos;) 
     // &apos;i&apos; &#x1EDF; &#x111;&#xE2;y c&#xF3; ngh&#x129;a l&#xE0; t&#xEC;m ki&#x1EBF;m t&#xEA;n m&#xE0; kh&#xF4;ng ph&#x1EA7;n bi&#x1EC7;t ch&#x1EEF; hoa hay th&#x1B0;&#x1EDD;ng
   }
   try{
     const authors = await Author.find(searchOptions);
     res.render(&apos;authors/index&apos;,{
       authors: authors,
       searchOptions : req.query
     })
   
   }catch{
     res.redirect(&apos;/&apos;)
   }
 
});

</code></pre>
<h3 id="giaodinhinthtrongauthor">Giao Di&#x1EC7;n Hi&#x1EC3;n Th&#x1ECB; Trong Author</h3>
<p>Trong <code>views</code> b&#x1EA1;n t&#x1EA1;o cho m&#xEC;nh th&#x1B0; m&#x1EE5;c l&#xE0; <code>authors</code> s&#x1EBD; bao g&#x1ED3;m 4 file <code>index.pug</code>, <code>new.pug</code>, <code>show.pug</code>, <code>edit.pug</code>.<br>
Tr&#x1B0;&#x1EDB;c ti&#xEA;n c&#xE1;c b&#x1EA1;n nh&#x1EDB; extends layout v&#xE0;o nha v&#xE0; l&#x1EB7;p qua c&#xE1;c author &#x111;&#x1EC3; hi&#x1EC3;n th&#x1ECB; ra t&#xEA;n c&#x1EE7;a author. T&#x1EA1;o m&#x1ED9;t form &#x111;&#x1EC3; l&#xE0;m &#xF4; t&#xEC;m ki&#x1EBF;m cho author v&#x1EDB;i method=&quot;Get&quot; nha.<br>
<code>searchOptions</code> n&#xE0;y l&#xE0; m&#x1ED9;t object do m&#xEC;nh &#x111;&#xE3; &#x111;&#x1ECB;nh ngh&#x129;a <code>req.query</code> &#x1EDF; tr&#xEA;n b&#xE2;y gi&#x1EDD; mu&#x1ED1;n l&#x1EA5;y value th&#xEC; ta c&#x1EA7;n <strong>.name</strong> &#x111;&#x1EC3; c&#xF3; th&#x1EC3; l&#x1EA5;y &#x111;&#x1B0;&#x1EE3;c value c&#x1EE7;a ch&#xFA;ng.<br>
<strong>authors/index.pug</strong></p>
<pre><code>extends ../layouts/layout

block content
 .container
    h2 Search Authors
    form(action=&quot;/authors&quot; method=&quot;GET&quot;)
        input( type=&quot;text&quot; name=&quot;name&quot; placeholder=&quot;Name Author&quot; value=searchOptions.name)
        button(type=&quot;submit&quot;) Search
    each author in authors
      h4= author.name
</code></pre>
<p><strong>L&#x1B0;u &#xFD;</strong>: M&#xEC;nh c&#xF3; c&#x1EAD;p nh&#x1EAD;t l&#x1EA1;i code t&#x1EA1;i m&#x1ED9;t s&#x1ED1; ch&#x1ED7; n&#xEA;n khi b&#x1EA1;n th&#x1EA5;y tr&#xEA;n &#x1EA3;nh gif s&#x1EBD; kh&#xF4;ng &#x111;&#x1B0;&#x1EE3;c ch&#xED;nh x&#xE1;c cho l&#x1EAF;m nha.<br>
<strong>V&#xE0; &#x111;&#xE2;y l&#xE0; k&#x1EBF;t qu&#x1EA3; khi ch&#xFA;ng ta hi&#x1EC3;n th&#x1ECB; v&#xE0; t&#xEC;m ki&#x1EBF;m author nha:</strong></p>
<img src="https://media.giphy.com/media/QwzfX2yYp6y99dl7wh/giphy.gif" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Books Store V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB - Ph&#x1EA7;n 1">
<p>V&#x1EAD;y l&#xE0; k&#x1EBF;t th&#xFA;c ph&#x1EA7;n 1 r&#x1ED3;i nha m&#x1EDD;i c&#xE1;c b&#x1EA1;n xem ti&#x1EBF;p ph&#x1EA7;n 2<br>
<strong>To Be Continued !!</strong></p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h1 id="likt">L&#x1EDD;i K&#x1EBF;t</h1>
<p>V&#x1EAD;y L&#xE0; Xong b&#xE0;i H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Books Store V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB - Ph&#x1EA7;n 1 r&#x1ED3;i nh&#xE9;. C&#xE1;c b&#x1EA1;n xem ph&#x1EA7;n ti&#x1EBF;p theo nha m&#xEC;nh chia th&#xE0;nh nhi&#x1EC1;u ph&#x1EA7;n ra &#x111;&#x1EC3; c&#xE1;c b&#x1EA1;n c&#xF3; th&#x1EC3; &#x111;&#x1ECD;c v&#xE0; l&#xE0;m m&#x1ED9;t c&#xE1;ch d&#x1EC5; d&#xE0;ng h&#x1A1;n r&#xE0;nh m&#x1EA1;ch v&#xE0; d&#x1EC5; hi&#x1EC3;u h&#x1A1;n.</p>
<p><strong>C&#xE1;c b&#x1EA1;n nh&#x1EDB; like v&#xE0; theo d&#xF5;i fanpage <a href="https://www.facebook.com/thanhlongdev/">Thanh Long Dev</a> &#x111;&#x1EC3; nh&#x1EAD;n nh&#x1EEF;ng th&#xF4;ng b&#xE1;o v&#x1EC1; b&#xE0;i vi&#x1EBF;t m&#x1EDB;i nh&#x1EA5;t nha.</strong><br>
<em><strong>N&#x1EBF;u c&#xE1;c b&#x1EA1;n c&#x1EA3;m th&#x1EA5;y b&#xE0;i vi&#x1EBF;t c&#x1EE7;a m&#xEC;nh hay th&#xEC; c&#xE1;c b&#x1EA1;n c&#xF3; th&#x1EC3; &#x1EE7;ng h&#x1ED9; m&#xEC;nh &#x111;&#x1EC3; m&#xEC;nh c&#xF3; th&#xEA;m &#x111;&#x1ED9;ng l&#x1EF1;c &#x111;&#x1EC3; ra nh&#x1EEF;ng b&#xE0;i topic hay v&#xE0; ch&#x1EA5;t l&#x1B0;&#x1EE3;ng h&#x1A1;n &#x1EE7;ng h&#x1ED9; m&#xEC;nh <a href="https://vrdonate.vn/thanhlongdev">t&#x1EA1;i &#x111;&#xE2;y nha.</a></strong></em></p>
<p><strong>Ch&#xFA;c C&#xE1;c B&#x1EA1;n Th&#xE0;nh C&#xF4;ng!!</strong></p>
<!--kg-card-end: markdown--><!--kg-card-begin: html--><iframe src="https://www.facebook.com/plugins/like.php?href=https%3A%2F%2Fwww.thanhlongdev.com%2Fhuong-dan-xay-dung-books-store-express-nodejs-phan1%2F&amp;width=450&amp;layout=standard&amp;action=like&amp;size=large&amp;share=true&amp;height=35&amp;appId=2794898430534168" width="450" height="35" style="border:none;overflow:hidden" scrolling="no" frameborder="0" allowtransparency="true" allow="encrypted-media"></iframe><!--kg-card-end: html--><!--kg-card-begin: html--><div class="fb-comments" data-href="https://www.thanhlongdev.com/huong-dan-xay-dung-books-store-express-nodejs-phan1/" data-width="100%" data-numposts="10"></div><!--kg-card-end: html-->]]></content:encoded></item><item><title><![CDATA[Hướng Dẫn Xây Dựng Pagination Với NodeJS, Express và MongoDB]]></title><description><![CDATA[<!--kg-card-begin: markdown--><h1 id="giithiuchung">Gi&#x1EDB;i Thi&#x1EC7;u Chung</h1>
<p>H&#xF4;m nay m&#xEC;nh s&#x1EBD; h&#x1B0;&#x1EDB;ng d&#x1EAB;n c&#xE1;c b&#x1EA1;n l&#xE0;m m&#x1ED9;t trong nh&#x1EEF;ng ch&#x1EE9;c n&#x103;ng kh&#xE1; ph&#x1ED5; bi&</p>]]></description><link>https://www.thanhlongdev.com/huong-dan-xay-dung-pagination-voi-nodejs-express-va-mongodb/</link><guid isPermaLink="false">5ebf68f266601200016fcfb9</guid><category><![CDATA[Lập Trình Web]]></category><dc:creator><![CDATA[Đặng Thanh Long]]></dc:creator><pubDate>Fri, 17 Jul 2020 15:19:19 GMT</pubDate><media:content url="https://digitalpress.fra1.cdn.digitaloceanspaces.com/4tg23ij/2020/07/pagination_dyjcww.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h1 id="giithiuchung">Gi&#x1EDB;i Thi&#x1EC7;u Chung</h1>
<img src="https://digitalpress.fra1.cdn.digitaloceanspaces.com/4tg23ij/2020/07/pagination_dyjcww.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Pagination V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB"><p>H&#xF4;m nay m&#xEC;nh s&#x1EBD; h&#x1B0;&#x1EDB;ng d&#x1EAB;n c&#xE1;c b&#x1EA1;n l&#xE0;m m&#x1ED9;t trong nh&#x1EEF;ng ch&#x1EE9;c n&#x103;ng kh&#xE1; ph&#x1ED5; bi&#x1EBF;n tr&#xEA;n c&#xE1;c trang web hi&#x1EC7;n nay &#x111;&#xF3; l&#xE0; pagination.<br>
<strong>Pagination</strong> hay c&#xF2;n g&#x1ECD;i l&#xE0; ph&#xE2;n trang, l&#xE0; qu&#xE1; tr&#xEC;nh ph&#xE2;n chia t&#xE0;i li&#x1EC7;u th&#xE0;nh c&#xE1;c trang ri&#xEA;ng bi&#x1EC7;t, ho&#x1EB7;c trang &#x111;i&#x1EC7;n t&#x1EED; ho&#x1EB7;c trang in.<br>
Tuy b&#xE0;i n&#xE0;y kh&#xF4;ng c&#xF3; g&#xEC; g&#x1ECD;i l&#xE0; qu&#xE1; m&#x1EDB;i l&#x1EA1; hay kh&#xE1;c bi&#x1EC7;t nh&#x1B0;ng m&#xEC;nh s&#x1EBD; vi&#x1EBF;t m&#x1ED9;t c&#xE1;ch t&#x1EAD;n t&#xEC;nh v&#xE0; chu &#x111;&#xE1;o mong c&#xE1;c b&#x1EA1;n xem &#x111;&#x1EA7;y &#x111;&#x1EE7; v&#xE0; k&#x1EF9; c&#xE0;ng.</p>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1594998736/blog-pagination-400x200_ljvlbw.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Pagination V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB"><!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h1 id="btulmthino">B&#x1EAF;t &#x110;&#x1EA7;u L&#xE0;m Th&#xF4;i N&#xE0;o</h1>
<h2 id="lntng">L&#xEA;n &#xDD; T&#x1B0;&#x1EDF;ng</h2>
<p>&#xDD; t&#x1B0;&#x1EDF;ng c&#xE1;i n&#xE0;y c&#x169;ng &#x111;&#x1A1;n gi&#x1EA3;n th&#xF4;i th&#xEC; nh&#x1B0; c&#xE1;c b&#x1EA1;n &#x111;&#xE3; bi&#x1EBF;t th&#xEC; b&#xE2;y gi&#x1EDD; m&#xEC;nh s&#x1EBD; t&#x1EA1;o m&#x1ED9;t trang page ch&#x1EE9;a ch&#x1EE9;a t&#x1EA5;t c&#x1EA3; s&#x1EA3;n ph&#x1EA9;m &#x111;&#xFA;ng kh&#xF4;ng n&#xE0;o. Nh&#x1B0;ng b&#xE2;y gi&#x1EDD; n&#x1EBF;u nh&#x1B0; ch&#xFA;ng ta c&#xF3; 200 s&#x1EA3;n ph&#x1EA9;m m&#xE0; ch&#x1EC9; &#x111;&#x1EB7;t ch&#xFA;ng l&#xEA;n m&#x1ED9;t trang th&#xEC; &#x111;&#xF3; kh&#xF4;ng ph&#x1EA3;i l&#xE0; c&#xE1;ch t&#x1ED1;i &#x1B0;u v&#xE0; tr&#x1EA3;i nghi&#x1EC7;m ng&#x1B0;&#x1EDD;i d&#xF9;ng kh&#xF4;ng &#x111;&#x1B0;&#x1EE3;c t&#x1ED1;t. N&#xEA;n ch&#xFA;ng ta s&#x1EBD; s&#x1EED; d&#x1EE5;ng k&#x1EF9; thu&#x1EAD;t ph&#xE2;n trang(pagination).</p>
<p>H&#x1B0;&#x1EDB;ng &#x111;&#x1EC3; l&#xE0;m c&#xE1;i th&#xEC; m&#xEC;nh b&#x1EAF;t bu&#x1ED9;c ph&#x1EA3;i c&#xF3; s&#x1EA3;n ph&#x1EA9;m(data) g&#xEC; &#x111;&#xF3; r&#x1ED3;i m&#x1EDB;i l&#xE0;m ph&#xE2;n trang cho n&#xF3; &#x111;&#xFA;ng kh&#xF4;ng n&#xE0;o. B&#xE2;y gi&#x1EDD; m&#xEC;nh mu&#x1ED1;n ph&#xE2;n l&#xE0;m 4 trang m&#x1ED7;i trang 16 s&#x1EA3;n ph&#x1EA9;m(data) th&#x1EBF; l&#xE0; ch&#xFA;ng ta c&#x1EA7;n ph&#x1EA3;i t&#x1EA1;o 64 s&#x1EA3;n ph&#x1EA9;m &#xE0; t&#x1EA1;o khi n&#xE0;o cho xong n&#xEA;n ta c&#x1EA7;n ph&#x1EA3;i fake data cho ch&#xFA;ng =))</p>
<p>B&#xE0;i n&#xE0;y m&#xEC;nh ch&#x1EC9; h&#x1B0;&#x1EDB;ng d&#x1EAB;n c&#xE1;c b&#x1EA1;n l&#xE0;m v&#x1EC1; pagination n&#xEA;n m&#x1EDB;i fake data ch&#x1EDB; v&#xE0;o th&#x1EF1;c t&#x1EBF; th&#xEC; c&#xE1;c b&#x1EA1;n ph&#x1EA3;i t&#x1EA1;o s&#x1EA3;n ph&#x1EA9;m &#x111;&#x1EA7;y &#x111;&#x1EE7; nha.<br>
Sau khi m&#xE0; fake data th&#xEC; &#x111;&#xE2;y l&#xE0; b&#x1B0;&#x1EDB;c quan tr&#x1ECD;ng nh&#x1EA5;t &#x111;&#xF3; l&#xE0; ph&#xE2;n trang c&#xE1;c b&#x1EA1;n xem ti&#x1EBF;p &#x111;&#x1EC3; bi&#x1EBF;t th&#xEA;m chi ti&#x1EBF;t nha. &#x110;&#xF3; c&#x169;ng ch&#xED;nh l&#xE0; &#xFD; t&#x1B0;&#x1EDF;ng c&#x1EE7;a m&#xEC;nh v&#xE0; b&#xE2;y gi&#x1EDD; ch&#xFA;ng ta s&#x1EBD; bi&#x1EBF;n &#xFD; t&#x1B0;&#x1EDF;ng th&#xE0;nh hi&#x1EC7;n th&#x1EF1;c.</p>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1590681277/layout_tjgvzh.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Pagination V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB">
<h2 id="citvthitlp">C&#xE0;i &#x110;&#x1EB7;t V&#xE0; Thi&#x1EBF;t L&#x1EAD;p</h2>
<p>Tr&#x1B0;&#x1EDB;c ti&#xEA;n c&#xE1;c b&#x1EA1;n t&#x1EA1;o cho m&#xEC;nh m&#x1ED9;t folder trong folder &#x111;&#xF3; l&#xE0; n&#x1A1;i ch&#x1EE9;a c&#xE1;c th&#x1B0; m&#x1EE5;c d&#xF9;ng &#x111;&#x1EC3; m&#xEC;nh code pagination.<br>
&#x110;&#x1EC3; m&#xE0; c&#xE0;i c&#xE1;c module tr&#x1B0;&#x1EDB;c h&#x1EBF;t c&#xE1;c b&#x1EA1;n ph&#x1EA3;i c&#xE0;i &#x111;&#x1EB7;t NodeJS <a href="https://nodejs.org/en/download/">t&#x1EA1;i &#x111;&#xE2;y</a>.<br>
Kh&#x1EDF;i t&#x1EA1;o &#x1EE9;ng d&#x1EE5;ng v&#x1EDB;i file <strong>package.json</strong><br>
Trong th&#x1B0; m&#x1EE5;c g&#x1ED1;c c&#x1EE7;a &#x1EE9;ng d&#x1EE5;ng c&#x1EE7;a b&#x1EA1;n v&#xE0; nh&#x1EAD;p <code>npm init</code> &#x111;&#x1EC3; kh&#x1EDF;i t&#x1EA1;o &#x1EE9;ng d&#x1EE5;ng c&#x1EE7;a b&#x1EA1;n v&#x1EDB;i t&#x1EC7;p <strong>package.json</strong>.<br>
<code>npm init</code><br>
Sau &#x111;&#xF3; c&#xE1;c b&#x1EA1;n c&#xE0;i &#x111;&#x1EB7;t c&#xE1;c module &#x1EDF; d&#x1B0;&#x1EDB;i &#x111;&#x1EC3; thi&#x1EBF;t l&#x1EAD;p &#x1EE9;ng d&#x1EE5;ng nha.</p>
<ul>
<li><strong>npm install express --save</strong><br>
Module d&#xF9;ng &#x111;&#x1EC3; c&#xE0;i &#x111;&#x1EB7;t framework express c&#x1EE7;a nodejs gi&#xFA;p c&#xE1;c b&#x1EA1;n code m&#x1ED9;t c&#xE1;ch t&#x1ED1;i gi&#x1EA3;n c&#x169;ng nh&#x1B0; nhanh ch&#xF3;ng h&#x1A1;n.</li>
<li><strong>npm install nodemon --save</strong><br>
T&#x1EF1; &#x111;&#x1ED9;ng reload l&#x1EA1;i server khi b&#x1EA1;n thay &#x111;&#x1ED5;i code. &#x110;&#x1EC3; kh&#x1EDF;i ch&#x1EA1;y server c&#xE1;c b&#x1EA1;n th&#xEA;m  <code>&quot;dev&quot;: &quot;nodemon src/app.js&quot;</code> v&#xE0;o file <strong>package.json</strong> nha. C&#xE1;c b&#x1EA1;n m&#x1EDF; terminal l&#xEA;n sau &#x111;&#xF3; g&#xF5; <code>npm run dev</code> &#x111;&#x1EC3; kh&#x1EDF;i ch&#x1EA1;y server nha.</li>
<li><strong>npm install mongoose --save</strong><br>
Mongoose l&#xE0; m&#x1ED9;t Object Document Mapper (ODM). &#x110;i&#x1EC1;u n&#xE0;y c&#xF3; ngh&#x129;a l&#xE0; Mongoose cho ph&#xE9;p b&#x1EA1;n &#x111;&#x1ECB;nh ngh&#x129;a c&#xE1;c object (&#x111;&#x1ED1;i t&#x1B0;&#x1EE3;ng) v&#x1EDB;i m&#x1ED9;t schema &#x111;&#x1B0;&#x1EE3;c &#x111;&#x1ECB;nh ngh&#x129;a r&#xF5; r&#xE0;ng.</li>
<li><strong>npm install dotenv --save</strong><br>
Dotenv l&#xE0; m&#x1ED9;t bi&#x1EBF;n m&#xF4;i tr&#x1B0;&#x1EDD;ng d&#xF9;ng &#x111;&#x1EC3; b&#x1EA3;o m&#x1EAD;t c&#xE1;c th&#xF4;ng tin quan tr&#x1ECD;ng nh&#x1B0; username, password, url database,...N&#x1EBF;u ch&#xFA;ng ta kh&#xF4;ng l&#x1B0;u nh&#x1EEF;ng th&#xF4;ng tin m&#x1EAD;t v&#xE0;o file .env th&#xEC; khi push source code l&#xEA;n github th&#xEC; ai c&#x169;ng c&#xF3; th&#x1EC3; v&#xE0;o xem &#x111;&#x1B0;&#x1EE3;c v&#xE0; ai c&#x169;ng bi&#x1EBF;t username, password th&#xEC; s&#x1EBD; b&#x1ECB; ng&#x1B0;&#x1EDD;i kh&#xE1;c chi&#x1EBF;m &#x111;o&#x1EA1;t v&#xE0; &#x111;&#xE1;nh c&#x1EAF;p t&#xE0;i li&#x1EC7;u r&#x1EA5;t l&#xE0; nguy hi&#x1EC3;m nha.</li>
<li><strong>npm install faker --save</strong><br>
Faker l&#xE0; m&#x1ED9;t package d&#xF9;ng &#x111;&#x1EC3; t&#x1EA1;o c&#xE1;c d&#x1EEF; li&#x1EC7;u fake(gi&#x1EA3;) bao g&#x1ED3;m r&#x1EA5;t nhi&#x1EC1;u API methods kh&#xE1;c nhau nh&#x1B0; address, image, name,... c&#xE1;c b&#x1EA1;n xem th&#xEA;m <a href="https://www.npmjs.com/package/faker#api-methods">t&#x1EA1;i &#x111;&#xE2;y nha</a></li>
<li><strong>npm install ejs --save</strong><br>
EJS n&#xF3; ch&#x1EC9; l&#xE0; m&#x1ED9;t template engine m&#xE0; th&#xF4;i h&#xF4;m nay m&#xEC;nh &#x111;&#x1ED5;i gi&#x1EDB; m&#x1ED9;t t&#xED; thay v&#xEC; d&#xF9;ng pug th&#xEC; m&#xEC;nh d&#xF9;ng ejs.<br>
<strong>V&#xE0; &#x111;&#xE2;y c&#x169;ng l&#xE0; c&#xE1;c package m&#xE0; m&#xEC;nh khi &#x111;&#xE3; c&#xE0;i &#x111;&#x1EB7;t c&#x169;ng nh&#x1B0; c&#x1EA5;u h&#xEC;nh xong.</strong></li>
</ul>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1590940626/Untitled_j8tezm.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Pagination V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB">
<h3 id="cutrcthmcchodn">C&#x1EA5;u Tr&#xFA;c Th&#x1B0; M&#x1EE5;c Cho D&#x1EF1; &#xC1;n</h3>
<p>Sau khi ho&#xE0;n th&#xE0;nh vi&#x1EC7;c c&#xE0;i &#x111;&#x1EB7;t module c&#xE1;c b&#x1EA1;n t&#x1EA1;o cho m&#xEC;nh m&#x1ED9;t th&#x1B0; m&#x1EE5;c <code>src</code>, th&#x1B0; m&#x1EE5;c n&#xE0;y d&#xF9;ng &#x111;&#x1EC3; ch&#x1EE9;a t&#x1EA5;t c&#x1EA3; c&#xE1;c file trong qu&#xE1; tr&#xEC;nh m&#xEC;nh code project.<br>
M&#xEC;nh khuy&#xEA;n c&#xE1;c b&#x1EA1;n n&#xEA;n t&#x1EA1;o th&#xEA;m m&#x1ED9;t folder controllers v&#xE0; file &#x111;&#x1EC3; ch&#x1EE9;a c&#xE1;c logic khi m&#xEC;nh code. Do m&#xEC;nh code &#x111;&#x1EC3; l&#xE0;m demo cho m&#x1ECD;i ng&#x1B0;&#x1EDD;i n&#xEA;n m&#xEC;nh vi&#x1EBF;t chung v&#xE0;o th&#x1EB1;ng routes lu&#xF4;n.</p>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1590939933/Untitled_i73dcg.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Pagination V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB">
<h2 id="btucodethino">B&#x1EAF;t &#x110;&#x1EA7;u Code Th&#xF4;i N&#xE0;o</h2>
<h2 id="thitlpwebserver">Thi&#x1EBF;t L&#x1EAD;p Web Server</h2>
<p>Trong th&#x1B0; m&#x1EE5;c g&#x1ED1;c c&#xE1;c b&#x1EA1;n t&#x1EA1;o cho m&#xEC;nh file app.js, file n&#xE0;y l&#xE0; file ch&#xED;nh d&#xF9;ng &#x111;&#x1EC3; &#x111;i&#x1EC1;u khi&#x1EC3;n m&#x1ECD;i ho&#x1EA1;t &#x111;&#x1ED9;ng ch&#xED;nh c&#x1EE7;a server.</p>
<pre><code>const express = require(&quot;express&quot;)
const app = express()
const path = require(&quot;path&quot;)
const port = 3333

// Import routes
const indexRoutes = require(&quot;./routes/index.routes&quot;)

// Settings
app.set(&apos;views&apos;, path.join(__dirname, &apos;views&apos;));
app.set(&apos;view engine&apos;, &apos;ejs&apos;);


// routes
app.use(indexRoutes);

app.listen(port, function(){
    console.log(`Server listening ${port}`)
})
</code></pre>
<p>Trong th&#x1B0; m&#x1EE5;c <code>routes</code> c&#xF3; file <code>index.routes.js</code>, c&#xE1;c b&#x1EA1;n t&#x1EA1;o cho n&#xF3; m&#x1ED9;t Route handlers v&#xE0; th&#x1EED; ch&#x1EA1;y sever xem sau. M&#x1EE5;c &#x111;&#xED;ch &#x111;&#x1EC3; c&#xE1;c b&#x1EA1;n test xem server c&#xF3; ch&#x1EA1;y kh&#xF4;ng nha.</p>
<pre><code>router.get(&apos;/&apos;, (req, res, next) =&gt; {
   res.send(&apos;Hello Everyone&apos;)
})
</code></pre>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1592827103/Untitled_irkhhu.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Pagination V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB">
<h2 id="thitlpdatabase">Thi&#x1EBF;t L&#x1EAD;p Database</h2>
<p>&#x110;&#x1EC3; m&#xE0; c&#xF3; th&#x1EC3; thi&#x1EBF;t l&#x1EAD;p &#x111;&#x1B0;&#x1EE3;c database th&#xEC; c&#xE1;c b&#x1EA1;n &#x111;&#x103;ng nh&#x1EAD;p t&#xE0;i kho&#x1EA3;n mongodb atlas <a href="https://account.mongodb.com/account/login">t&#x1EA1;i &#x111;&#xE2;y nha</a>. Sau khi c&#xE1;c b&#x1EA1;n b&#x1EA1;n &#x111;&#xE3; c&#xF3; t&#xE0;i kho&#x1EA3;n mongodb atlas th&#xEC; ti&#x1EBF;p &#x111;&#x1EBF;n c&#xE0;i &#x111;&#x1EB7;t c&#x1EA5;u h&#xEC;nh &#x111;&#x1EC3; c&#xF3; th&#x1EC3; k&#x1EBF;t n&#x1ED1;i mongodb atlas v&#x1EDB;i &#x1EE9;ng d&#x1EE5;ng c&#x1EE7;a ch&#xFA;ng ta. &#x110;&#x1EC3; bi&#x1EBF;t th&#xEA;m chi ti&#x1EBF;t c&#xE1;c b&#x1EA1;n xem b&#x1B0;&#x1EDB;c 3 trong b&#xE0;i vi&#x1EBF;t c&#x1EE7;a m&#xEC;nh h&#x1B0;&#x1EDB;ng d&#x1EAB;n deploy project nodejs l&#xEA;n heroku <a href="https://www.thanhlongdev.com/huong-dan-cach-deploy-project-nodejs-len-heroku/">t&#x1EA1;i &#x111;&#xE2;y nha</a>.<br>
Sau &#x111;&#xF3; c&#xE1;c b&#x1EA1;n copy link database mongodb &#x111;&#xE3; t&#x1EA1;o r&#x1ED3;i paste v&#xE0;o project c&#x1EE7;a m&#xEC;nh l&#xE0; &#x111;&#x1B0;&#x1EE3;c nha. C&#xE1;c b&#x1EA1;n t&#x1EA1;o cho m&#xEC;nh m&#x1ED9;t file <code>.env</code> b&#xEA;n trong th&#x1B0; m&#x1EE5;c g&#x1ED1;c.<br>
Trong file n&#xE0;y c&#xE1;c b&#x1EA1;n t&#x1EA1;o m&#x1ED9;t &#x111;&#x1B0;&#x1EDD;ng d&#x1EAB;n l&#xE0; <code>DATABASE_URL=mongodb+srv://long:&lt;password&gt;@cluster0-b7d8c.mongodb.net/test?retryWrites=true&amp;w=majority</code><br>
Trong file app.js c&#xE1;c b&#x1EA1;n khai b&#xE1;o module dotenv v&#x1EDB;i module mongoose v&#xE0; t&#x1EA1;o &#x111;&#x1B0;&#x1EDD;ng d&#x1EAB;n mongodb.<br>
// Khai b&#xE1;o dotenv<br>
<code>require(&apos;dotenv&apos;).config()</code><br>
// Khai b&#xE1;o mongoose<br>
<code>var mongoose = require(&apos;mongoose&apos;)</code></p>
<pre><code>// Connect database
mongoose.connect(process.env.DATABASE_URL, 
    {useNewUrlParser: true, useUnifiedTopology: true}).then(function() {
        console.log(&quot;Successfully connected to the database&quot;);    
    }).catch(function(err) {
        console.log(&apos;Could not connect to the database. Exiting now...&apos;, err);
        process.exit();
    });
</code></pre>
<p>&#x110;&#x1EC3; bi&#x1EBF;t n&#xF3; &#x111;&#xE3; k&#x1EBF;t n&#x1ED1;i hay ch&#x1B0;a c&#xE1;c b&#x1EA1;n kh&#x1EDF;i &#x111;&#x1ED9;ng l&#x1EA1;i server s&#x1EBD; bi&#x1EBF;t nha.<br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1591194301/2_erulnp.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Pagination V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB"></p>
<h2 id="thitkgiaodin">Thi&#x1EBF;t K&#x1EBF; Giao Di&#x1EC7;n</h2>
<p>N&#xF3;i thi&#x1EBF;t k&#x1EBF; th&#xEC; n&#xF3; h&#x1A1;i qu&#xE1; ch&#x1EDB; th&#x1EAD;t ra l&#xE0;m c&#xE1;i n&#xE0;y c&#x169;ng &#x111;&#x1A1;n gi&#x1EA3;n. Kh&#xF4;ng c&#x1EA7;n l&#xE0;m m&#xE0; v&#x1EAB;n c&#xF3; &#x103;n^^, &#x111;&#xF9;a ch&#xFA;t th&#xF4;i nha. Tr&#x1B0;&#x1EDB;c ti&#xEA;n m&#xEC;nh s&#x1EBD; code giao di&#x1EC7;n trang ch&#x1EE7; nh&#x1B0; c&#xE1;c b&#x1EA1;n &#x111;&#xE3; th&#x1EA5;y &#x1EDF; tr&#xEA;n ph&#x1EA7;n <strong>c&#x1EA5;u tr&#xFA;c th&#x1B0; m&#x1EE5;c</strong> th&#xEC; ta th&#x1EA5;y trong folder <code>views</code> ch&#x1EE9;a folder layout ch&#x1EE9;a c&#xE1;c file nh&#x1B0;: <strong>header.ejs, footer.ejs</strong> l&#xE0; n&#x1A1;i m&#xE0; ch&#xFA;ng ta d&#xF9;ng &#x111;&#x1EC3; code giao di&#x1EC7;n cho app. M&#xEC;nh s&#x1EED; d&#x1EE5;ng <em><strong>template engine ejs</strong></em> n&#xEA;n n&#xF3; kh&#xE1; quen thu&#x1ED9;c v&#x1EDB;i ch&#xFA;ng ta b&#x1EDF;i v&#xEC; n&#xF3; kh&#xE1; gi&#x1ED1;ng html thu&#x1EA7;n.<br>
Trong file <strong>header.ejs</strong> m&#xEC;nh s&#x1EBD; t&#x1EA1;o cho n&#xF3; m&#x1ED9;t thanh nav s&#x1EBD; bao g&#x1ED3;m logo v&#xE0; menu. V&#xE0; trong menu s&#x1EBD; ch&#x1EEF;a m&#x1ED9;t nav link &#x111;&#xF3; l&#xE0; <em><strong>Fake data product</strong></em> &#x111;&#x1EC3; khi ch&#xFA;ng ta click v&#xE0;o &#x111;&#xF3; s&#x1EBD; t&#x1EA1;o c&#xE1;c data fake c&#xE1;i n&#xE0;y m&#xEC;nh s&#x1EBD; n&#xF3;i r&#xF5; &#x1EDF; ph&#x1EA7;n sau b&#x1EA1;n kh&#xF4;ng c&#x1EA7;n quan t&#xE2;m qu&#xE1; nhi&#x1EC1;u.</p>
<pre><code>&lt;!DOCTYPE html&gt;
&lt;html&gt;

&lt;head&gt;
  &lt;meta charset=&quot;UTF-8&quot;&gt;
  &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&gt;
  &lt;title&gt;Pagination&lt;/title&gt;
  &lt;link rel=&quot;stylesheet&quot; href=&quot;https://maxcdn.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css&quot;&gt;
&lt;/head&gt;

&lt;body&gt;

  &lt;nav class=&quot;navbar navbar-expand-lg navbar-light bg-light&quot;&gt;
    &lt;div class=&quot;container&quot;&gt;
      &lt;a class=&quot;navbar-brand&quot; href=&quot;/&quot;&gt;
      &lt;img src=&quot;https://bizweb.dktcdn.net/100/228/168/themes/715878/assets/logo.png?1594693671116&quot; alt=&quot;logo Linh Ki&#x1EC7;n &#x110;i&#x1EC7;n T&#x1EED; 3M&quot; width=&quot;50%&quot;&gt;
      &lt;/a&gt;
      &lt;button class=&quot;navbar-toggler collapsed&quot; type=&quot;button&quot; data-toggle=&quot;collapse&quot; data-target=&quot;#navbarNavDropdown&quot; aria-controls=&quot;navbarNavDropdown&quot; aria-expanded=&quot;false&quot; aria-label=&quot;Toggle navigation&quot;&gt;
        &lt;span class=&quot;navbar-toggler-icon&quot;&gt;&lt;/span&gt;
    &lt;/button&gt;
      &lt;div class=&quot;navbar-collapse collapse justify-content-end&quot; id=&quot;navbarNavDropdown&quot;&gt;
        &lt;ul class=&quot;navbar-nav&quot;&gt;

          &lt;li class=&quot;nav-item&quot;&gt;
            &lt;a class=&quot;nav-link&quot; href=&quot;/generate-fake-data&quot;&gt;
              Fake data product
            &lt;/a&gt;
          &lt;/li&gt;
         
        &lt;/ul&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/nav&gt;
  &lt;script src=&quot;https://code.jquery.com/jquery-3.4.1.min.js&quot; integrity=&quot;sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;/script&gt;
  &lt;script src=&quot;https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js&quot; integrity=&quot;sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;/script&gt;
</code></pre>
<p><strong>V&#xE0; &#x111;&#xE2;y l&#xE0; giao di&#x1EC7;n cho trang ch&#x1EE7; c&#x1EE7;a ch&#xFA;ng ta</strong></p>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1594996656/Untitled_vcrabe.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Pagination V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB">
<h2 id="nhnghaccschemaproductchomongoose">&#x110;&#x1ECB;nh Ngh&#x129;a C&#xE1;c Schema Product Cho Mongoose</h2>
<p>Nh&#x1B0; c&#xE1;c b&#x1EA1;n &#x111;&#xE3; &#x111;&#x1ECD;c &#x1EDF; tr&#xEA;n th&#xEC; c&#x1EA5;u tr&#xFA;c th&#x1B0; m&#x1EE5;c cho d&#x1EF1; &#xE1;n b&#xEA;n trong th&#x1B0; m&#x1EE5;c <code>src</code> c&#xE1;c b&#x1EA1;n t&#x1EA1;o cho m&#xEC;nh th&#x1B0; m&#x1EE5;c <code>models</code>, b&#xEA;n trong th&#x1B0; m&#x1EE5;c <code>models</code> c&#xE1;c b&#x1EA1;n t&#x1EA1;o cho m&#xEC;nh file <code>product.model.js</code>.<br>
Trong file <code>product.model.js</code> c&#x1EA7;n t&#x1EA1;o m&#x1ED9;t &#x111;&#x1ED1;i t&#x1B0;&#x1EE3;ng book v&#xE0; s&#x1EBD; ch&#x1EE9;a ba fields l&#xE0; name, price v&#xE0; cover.</p>
<pre><code>const mongoose = require(&quot;mongoose&quot;)
const Schema = mongoose.Schema;

const productSchema = new Schema({
    name: {type: String, required: true},
    price: {type: Number, required: true},
    cover: {type: String, required: true}
})
// Bi&#xEA;n d&#x1ECB;ch m&#xF4; h&#xEC;nh t&#x1EEB; schema
module.exports =  mongoose.model(&apos;product&apos;, productSchema)
</code></pre>
<p>Tham s&#x1ED1; th&#x1EE9; nh&#x1EA5;t l&#xE0; t&#xEA;n ri&#xEA;ng cho collection s&#x1EAF;p &#x111;&#x1B0;&#x1EE3;c t&#x1EA1;o ra cho m&#xF4; h&#xEC;nh c&#x1EE7;a b&#x1EA1;n, v&#xE0; tham s&#x1ED1; th&#x1EE9; hai l&#xE0; schema m&#xE0; b&#x1EA1;n mu&#x1ED1;n d&#xF9;ng &#x111;&#x1EC3; t&#x1EA1;o ra m&#xF4; h&#xEC;nh.<br>
<em><strong>Sau khi ch&#xFA;ng ta &#x111;&#xE3; setup xong h&#x1EC7; th&#x1ED1;ng th&#xEC; b&#xE2;y gi&#x1EDD; m&#xEC;nh s&#x1EBD; &#x111;i &#x111;&#x1EBF;n ch&#x1EE9;c n&#x103;ng l&#xE0; t&#x1EA1;o data fake v&#xE0; l&#x1B0;u v&#xE0;o DB nh&#x1B0; mong mu&#x1ED1;n c&#x1EE7;a m&#xEC;nh.</strong></em></p>
<h2 id="todliufake">T&#x1EA1;o D&#x1EEF; Li&#x1EC7;u Fake</h2>
<p>Nh&#xEC;n ti&#xEA;u &#x111;&#x1EC1; h&#x1A1;i c&#x1EE7; chu&#x1ED1;i c&#xE1;c &#xF4;ng nh&#x1EDD; =)). Nh&#x1B0;ng m&#xE0; kh&#xF4;ng sao c&#x1EE7; chu&#x1ED1;i nhi&#x1EC1;u l&#xFA;c c&#x169;ng th&#xFA; v&#x1ECB;, m&#xEC;nh kh&#xF4;ng c&#xF3; &#x111;i v&#xF2;ng vo n&#x1EEF;a m&#xE0; l&#xE0; v&#xE0;o th&#x1EB3;ng v&#x1EAB;n &#x111;&#x1EC1; ch&#xED;nh lu&#xF4;n &#x111;&#xF3; l&#xE0; t&#x1EA1;o data gi&#x1EA3;(fake). L&#xFD; do t&#x1EA1;i sao ch&#xFA;ng ta l&#x1EA1;i ph&#x1EA3;i fake data m&#x1EE5;c &#x111;&#xED;ch c&#x1EE7;a n&#xF3; &#x111;&#x1A1;n gi&#x1EA3;n l&#xE0; c&#xF3; t&#x1EA1;o ra nhi&#x1EC1;u data m&#x1ED9;t c&#xE1;ch nhanh ch&#xF3;ng &#x111;&#x1EC3; th&#x1EF1;c hi&#x1EC7;n c&#xF4;ng vi&#x1EC7;c &#x111;&#xF3; l&#xE0; ph&#xE2;n trang(pagination).<br>
Trong th&#x1B0; m&#x1EE5;c <code>src</code> c&#xE1;c b&#x1EA1;n t&#x1EA1;o cho m&#xEC;nh th&#x1B0; m&#x1EE5;c <code>routes</code>, b&#xEA;n trong th&#x1B0; m&#x1EE5;c <code>routes</code> c&#xE1;c b&#x1EA1;n t&#x1EA1;o cho m&#xEC;nh file <code>index.routes.js</code>.<br>
Trong file <code>index.routes.js</code> c&#xE1;c b&#x1EA1;n c&#x1EA7;n import v&#xE0; khai b&#xE1;o m&#x1ED9;t s&#x1ED1; module nh&#x1B0; model, faker,...<br>
Ti&#x1EBF;p &#x111;&#x1EBF;n b&#x1EA1;n t&#x1EA1;o cho m&#xEC;nh m&#x1ED9;t <code>routes.get(&apos;/generate-fake-data&apos;, ()=&gt;{...})</code> &#x111;&#x1EC3; khi ch&#xFA;ng ta click v&#xE0;o router &#x111;&#xF3; n&#xF3; s&#x1EBD; t&#x1EF1; &#x111;&#x1ED9;ng t&#x1EA1;o cho ta h&#xE0;ng lo&#x1EA1;t c&#xE1;c data fake v&#xE0; l&#x1B0;u v&#xE0;o database nh&#x1B0; ta mong mu&#x1ED1;n.<br>
M&#xEC;nh s&#x1EBD; gi&#x1EA3;i th&#xED;ch qua m&#x1ED9;t ch&#xFA;t &#x111;&#xF3; l&#xE0; ch&#xFA;ng ta t&#x1EA1;o m&#x1ED9;t v&#xF2;ng l&#x1EB7;p &#x111;&#x1EC3; l&#xE0;m g&#xEC; &#x111;&#x1EC3; n&#xF3; c&#xF3; th&#x1EC3; t&#x1EF1; &#x111;&#x1ED9;ng t&#x1EA1;o s&#x1ED1; l&#x1B0;&#x1EE3;ng data m&#xE0; m&#xEC;nh mu&#x1ED1;n fake. Trong v&#xF2;ng l&#x1EB7;p &#x111;&#xF3; t&#x1EA1;o m&#x1ED9;t object empty &#x111;&#x1EC3; ch&#x1EE9;a c&#xE1;c thu&#x1ED9;c t&#xED;nh c&#x1EE7;a m&#x1ED9;t s&#x1EA3;n ph&#x1EA9;m nh&#x1B0; name, price, coverImg v&#xE0; l&#x1B0;u v&#xE0;o database r&#x1ED3;i redirect trang ch&#x1EE7;. C&#xF2;n c&#xE1;c API &#x111;&#x1EC3; t&#x1EA1;o d&#x1EEF; li&#x1EC7;u fake c&#xE1;c b&#x1EA1;n xem <a href="https://www.npmjs.com/package/faker#api-methods">t&#x1EA1;i &#x111;&#xE2;y nha</a> n&#xF3; c&#x169;ng kh&#xE1; l&#xE0; &#x111;&#x1A1;n gi&#x1EA3;n.</p>
<pre><code>const express = require(&quot;express&quot;)
const router = express.Router()
const faker = require(&apos;faker&apos;);
const Product = require(&quot;../models/product.model&quot;)

.............
.............
.............
  // Fake data products
router.get(&apos;/generate-fake-data&apos;, async(req, res, next) =&gt;{
    for(let i = 0; i &lt; 96; i++) {
    const newprd = new Product();
    newprd.name = faker.commerce.productName()
    newprd.price = faker.commerce.price()
    newprd.cover = faker.image.image()
    
    newprd.save((err)=&gt;{
        if (err) { return next(err); }
      });
    }
    res.redirect(&apos;/&apos;);    
}) 

............
............
............

module.exports = router
</code></pre>
<p><strong>Ch&#xFA;ng ta c&#xF9;ng xem th&#x1EED; k&#x1EBF;t qu&#x1EA3; &#x111;&#x1EC3; bi&#x1EBF;t n&#xF3; c&#xF3; t&#x1EF1; &#x111;&#x1ED9;ng fake data v&#xE0; l&#x1B0;u v&#xE0;o DB kh&#xF4;ng nha</strong></p>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1592828286/Untitled_s0qu0p.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Pagination V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB">
<h2 id="hngdnphntrang">H&#x1B0;&#x1EDB;ng D&#x1EAB;n Ph&#xE2;n Trang</h2>
<p>Sau khi &#x111;&#xE3; data fake xong b&#xE2;y gi&#x1EDD; ch&#xFA;ng ta s&#x1EBD; b&#x1EAF;t &#x111;&#x1EA7;u ph&#xE2;n trang cho n&#xF3; nha. &#x110;&#x1EC3; ph&#xE2;n trang m&#xEC;nh c&#x1EA7;n l&#xE0;m nh&#x1B0; nh&#x1EDD; =)) m&#xEC;nh s&#x1EBD; n&#xF3;i s&#x1A1; qua ch&#xFA;t v&#x1EC1; quy tr&#xEC;nh ho&#x1EA1;t &#x111;&#x1ED9;ng nha.<br>
Th&#xEC; khi ch&#xFA;ng ta &#x111;&#xE3; fake d&#x1EEF; li&#x1EC7;u cho n&#xF3; xong th&#xEC; c&#xF4;ng vi&#x1EC7;c b&#xE2;y gi&#x1EDD; ch&#xED;nh l&#xE0; ph&#xE2;n trang. C&#xF3; r&#x1EA5;t nhi&#x1EC1;u c&#xE1;ch &#x111;&#x1EC3; ph&#xE2;n trang nh&#x1B0;ng m&#xEC;nh s&#x1EBD; s&#x1EED; d&#x1EE5;ng <code>req.params</code> v&#xE0; s&#x1EED; d&#x1EE5;ng n&#xF3; nh&#x1B0; th&#x1EBF; n&#xE0;o th&#xEC; c&#xE1;c b&#x1EA1;n xem ti&#x1EBF;p nha.<br>
M&#x1EE5;c &#x111;&#xED;ch khi m&#xEC;nh s&#x1EED; d&#x1EE5;ng <code>req.params</code> &#x111;&#xF3; l&#xE0; l&#x1EA5;y th&#xF4;ng s&#x1ED1; c&#xE1;c page.<br>
<strong>VD:</strong> router.get(&apos;/news/:page&apos;, (req, res, next) =&gt; {} ) th&#xEC; page &#x111;&#x1B0;&#x1EE3;c g&#x1ECD;i l&#xE0; params ngo&#xE0;i c&#xE1;c n&#xE0;y c&#xE1;c b&#x1EA1;n c&#x169;ng c&#xF3; th&#x1EC3; s&#x1EED; d&#x1EE5;ng <code>req.query</code> &#x111;&#x1EC3; truy v&#x1EA5;n v&#xE0;o c&#xE1;c trang &#x111;&#x1B0;&#x1EE3;c pagination.<br>
<em><strong>Code Th&#xF4;i N&#xE0;o</strong></em><br>
Trong qu&#xE1; tr&#xEC;nh code m&#xEC;nh s&#x1EBD; n&#xF3;i th&#xEA;m cho c&#xE1;c b&#x1EA1;n d&#x1EC5; hi&#x1EC3;u h&#x1A1;n.<br>
B&#xEA;n trong th&#x1B0; m&#x1EE5;c <strong>routes</strong> c&#xF3; file <code>index.routes.js</code> ch&#xFA;ng ta s&#x1EBD; t&#x1EA1;o m&#x1ED9;t <code>router.get(&apos;/news/:page&apos;, (req, res, next) =&gt; {} )</code></p>
<pre><code>// pagination
router.get(&apos;/news/:page&apos;, (req, res, next) =&gt; {
    let perPage = 16; // s&#x1ED1; l&#x1B0;&#x1EE3;ng s&#x1EA3;n ph&#x1EA9;m xu&#x1EA5;t hi&#x1EC7;n tr&#xEA;n 1 page
    let page = req.params.page || 1; 
  
    Product
      .find() // find t&#x1EA5;t c&#x1EA3; c&#xE1;c data
      .skip((perPage * page) - perPage) // Trong page &#x111;&#x1EA7;u ti&#xEA;n s&#x1EBD; b&#x1ECF; qua gi&#xE1; tr&#x1ECB; l&#xE0; 0
      .limit(perPage)
      .exec((err, products) =&gt; {
        Product.countDocuments((err, count) =&gt; { // &#x111;&#x1EBF;m &#x111;&#x1EC3; t&#xED;nh c&#xF3; bao nhi&#xEA;u trang
          if (err) return next(err);
           res.send(products) // Tr&#x1EA3; v&#x1EC1; d&#x1EEF; li&#x1EC7;u c&#xE1;c s&#x1EA3;n ph&#x1EA9;m theo &#x111;&#x1ECB;nh d&#x1EA1;ng nh&#x1B0; JSON, XML,...
        });
      });
  });
</code></pre>
<p><strong>V&#xE0; &#x111;&#xE2;y l&#xE0; k&#x1EBF;t qu&#x1EA3; khi ch&#xFA;ng ta truy c&#x1EAD;p url <code>localhost:3333/news/1</code> th&#xEC; n&#xF3; s&#x1EBD; tr&#x1EA3; v&#x1EC1; d&#x1EEF; li&#x1EC7;u c&#xE1;c s&#x1EA3;n ph&#x1EA9;m xu&#x1EA5;t hi&#x1EC7;n tr&#xEA;n m&#x1ED9;t trang &#x111;&#xE2;y l&#xE0; m&#xEC;nh ch&#x1EC9; test th&#x1EED; th&#xF4;i nha.</strong><br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1594133964/Untitled_ocw1mk.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Pagination V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB"></p>
<p>Sau khi ch&#xFA;ng ta &#x111;&#xE3; test th&#xE0;nh c&#xF4;ng b&#x1EB1;ng c&#xE1;ch g&#x1EED;i d&#x1EEF; li&#x1EC7;u v&#x1EC1;, b&#xE2;y gi&#x1EDD; ta c&#x1EA7;n l&#xE0;m l&#xE0; bi&#x1EBF;n ch&#xFA;ng th&#xE0;nh nh&#x1EEF;ng giao di&#x1EC7;n &#x111;&#x1EB9;p m&#x1EAF;t =))<br>
Thay v&#xEC; <code>res.send</code> &#x111;&#x1EC3; tr&#x1EA3; v&#x1EC1; d&#x1EEF; li&#x1EC7;u theo d&#x1EA1;ng json th&#xEC; b&#xE2;y gi&#x1EDD; ch&#xFA;ng ta s&#x1EBD; thay &#x111;&#x1ED5;i th&#xE0;nh <code>res.render</code> &#x111;&#x1EC3; tr&#x1EA3; v&#x1EC1; d&#x1EEF; li&#x1EC7;u d&#x1B0;&#x1EDB;i d&#x1EA1;ng html nha.</p>
<pre><code>// pagination
router.get(&apos;/news/:page&apos;, (req, res, next) =&gt; {

     .............
     .............
     .............
          res.render(&apos;product/index_product&apos;, {
            products, // s&#x1EA3;n ph&#x1EA9;m tr&#xEA;n m&#x1ED9;t page
            current: page, // page hi&#x1EC7;n t&#x1EA1;i
            pages: Math.ceil(count / perPage) // t&#x1ED5;ng s&#x1ED1; c&#xE1;c page
          });
          
      ..............
      ..............
      ..............

</code></pre>
<p>Trong file <code>index_product.ejs</code> ta s&#x1EBD; code giao di&#x1EC7;n pagination cho n&#xF3;. Tr&#x1B0;&#x1EDB;c ti&#xEA;n m&#xEC;nh s&#x1EBD; ph&#x1EA3;i include th&#x1EB1;ng header v&#xE0; footer v&#xE0;o c&#xE1;i &#x111;&#xE3;, &#x111;&#x1EC3; m&#xE0; c&#xF3; th&#x1EC3; hi&#x1EC3;n th&#x1ECB; &#x111;&#x1B0;&#x1EE3;c s&#x1EA3;n ph&#x1EA9;m ta ch&#x1EC9; c&#x1EA7;n l&#x1EB7;p qua r&#x1ED3;i chia c&#x1ED9;t cho n&#xF3; l&#xE0; &#x111;&#x1B0;&#x1EE3;c. N&#x1EBF;u mu&#x1ED1;n hi&#x1EC3;n th&#x1ECB; 3 s&#x1EA3;n ph&#x1EA9;m th&#xEC; col-4 c&#xF2;n mu&#x1ED1;n hi&#x1EC3;n th&#x1ECB; 4 s&#x1EA3;n ph&#x1EA9;m th&#xEC; col-3 c&#xF3; th&#x1EC3; th&#xF4;i &#x1EA5;y m&#xE0; :))</p>
<p>Ti&#x1EBF;p &#x111;&#x1EBF;n ph&#x1EA7;n kh&#xE1; l&#xE0; quan tr&#x1ECD;ng &#x111;&#xF3; l&#xE0; ph&#xE2;n trang</p>
<pre><code>&lt;%- include(&apos;../layout/header&apos;); -%&gt;


&lt;div class=&quot;container&quot; style=&quot;margin-top: 50px&quot;&gt;
  &lt;div class=&quot;row&quot;&gt;

    &lt;!-- ITEMS --&gt;
    &lt;% for(var i = 0; i &lt; products.length; i++) { %&gt;
    &lt;div class=&quot;col-md-3&quot;&gt;
      &lt;div class=&quot;p-1&quot;&gt;
        &lt;div class=&quot;card&quot;&gt;
          &lt;img src=&quot;&lt;%= products[i].cover %&gt;&quot; class=&quot;card-img-top&quot;&gt;
          &lt;div class=&quot;card-body&quot;&gt;
            &lt;h4 class=&quot;card-title&quot;&gt;&lt;%= products[i].name %&gt;&lt;/h4&gt;
            &lt;p class=&quot;card-text&quot;&gt;&lt;%= products[i].category %&gt;&lt;/p&gt;
            &lt;p class=&quot;card-text&quot;&gt;&lt;%= products[i].price %&gt;$&lt;/p&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;% } %&gt;
  &lt;/div&gt;

 &lt;!-- pagination --&gt;
  &lt;div class=&quot;row&quot;&gt;
    &lt;!-- hi&#x1EC3;n th&#x1ECB; ph&#xE2;n trang n&#x1EBF;u c&#xF3; trang --&gt;
    &lt;% if(pages &gt; 0) { %&gt;
    &lt;nav class=&quot;mx-auto&quot;&gt;
      &lt;ul class=&quot;pagination&quot; style=&quot;margin-top: 2rem;&quot;&gt;
      
        &lt;!-- FIRST ITEM --&gt;  
        &lt;% if(current == 1) { %&gt; 
      // N&#x1EBF;u th&#xF4;ng s&#x1ED1; http://localhost:3333/news/1/ l&#xE0; 1 th&#xEC; First s&#x1EBD; b&#x1ECB; disabled
            &lt;li class=&quot;page-item disabled&quot;&gt;
              &lt;a class=&quot;page-link&quot; href=&quot;/&quot;&gt;First&lt;/a&gt;
            &lt;/li&gt;
        &lt;% } else { %&gt;
        // N&#x1EBF;u th&#xF4;ng s&#x1ED1; http://localhost:3333/news/2/ t&#x1EEB; 2 tr&#x1EDF; l&#xEA;n th&#xEC; First s&#x1EBD; b&#x1ECF; disabled
            &lt;li class=&quot;page-item&quot;&gt;
              &lt;a class=&quot;page-link&quot; href=&quot;/&quot;&gt;First&lt;/a&gt;
            &lt;/li&gt;
        &lt;% } %&gt;
        
        &lt;!-- ITEMS  --&gt;
        &lt;% var i = (Number(current) &gt; 3 ? Number(current) - 2 : 1) %&gt; 
  // To&#xE1;n t&#x1EED; &#x111;i&#x1EC1;u ki&#x1EC7;n 3 ng&#xF4;i syntax: &lt; &#x111;i&#x1EC1;u_ki&#x1EC7;n ? gi&#xE1;_tr&#x1ECB;_1 : gi&#xE1;_tr&#x1ECB;_2 &gt;
 // N&#x1EBF;u &#x111;i&#x1EC1;u_ki&#x1EC7;n tr&#x1EA3; v&#x1EC1; true, to&#xE1;n t&#x1EED; c&#xF3; gi&#xE1; tr&#x1ECB; gi&#xE1;_tr&#x1ECB;_1. Ng&#x1B0;&#x1EE3;c l&#x1EA1;i to&#xE1;n t&#x1EED; c&#xF3; gi&#xE1; tr&#x1ECB; gi&#xE1;_tr&#x1ECB;_2.
        &lt;% if(i !== 1) { %&gt;
            &lt;li class=&quot;page-item disabled&quot;&gt;
              &lt;a class=&quot;page-link&quot; href=&quot;#&quot;&gt;...&lt;/a&gt;
            &lt;/li&gt;
        &lt;% } %&gt;
        &lt;% for(; i &lt;= (Number(current) + 2) &amp;&amp; i &lt;= pages; i++) { %&gt;
        // S&#x1EED; d&#x1EE5;ng v&#xF2;ng l&#x1EB7;p &#x111;&#x1EC3; l&#x1EB7;p qua t&#x1EEB;ng trang v&#xE0; t&#x103;ng s&#x1ED1; trang 
        // Trong v&#xF2;ng l&#x1EB7;p for c&#xF3; ba bi&#x1EC3;u th&#x1EE9;c t&#xF9;y ch&#x1ECD;n n&#xEA;n ch&#x1EC9; c&#x1EA7;n c&#xE1;c b&#x1EA1;n t&#xE1;ch m&#x1ED7;i bi&#x1EC3;u th&#x1EE9;c b&#x1EB1;ng d&#x1EA5;u `;` l&#xE0; oke r&#x1ED3;i
          &lt;% if(i == current) { %&gt;
            &lt;li class=&quot;page-item active&quot;&gt;
              &lt;a class=&quot;page-link&quot; href=&quot;/news/&lt;%= i %&gt;/&quot;&gt;
                &lt;%= i %&gt;
              &lt;/a&gt;
            &lt;/li&gt;
        &lt;% } else { %&gt;
            &lt;li class=&quot;page-item&quot;&gt;
              &lt;a class=&quot;page-link&quot; href=&quot;/news/&lt;%= i %&gt;/&quot;&gt;
                &lt;%= i %&gt;
              &lt;/a&gt;
            &lt;/li&gt;
        &lt;% } %&gt;
        &lt;% if (i == Number(current) + 2 &amp;&amp; i &lt; pages) { %&gt;
            &lt;li class=&quot;page-item disabled&quot;&gt;
              &lt;a class=&quot;page-link&quot; href=&quot;#&quot;&gt;...&lt;/a&gt;
            &lt;/li&gt;
        &lt;% } %&gt;
        &lt;% } %&gt;
        
        &lt;!-- LAST ITEM --&gt;
        &lt;% if(current == pages) { %&gt; 
       // N&#x1EBF;u s&#x1ED1; current( ch&#x1EC9; s&#x1ED1; ph&#xE2;n trang ) l&#xE0; 6 v&#xE0; t&#x1ED5;ng s&#x1ED1; page l&#xE0; 6 th&#xEC; Last b&#x1ECB; disabled
            &lt;li class=&quot;page-item disabled&quot;&gt;
              &lt;a class=&quot;page-link&quot; href=&quot;#&quot;&gt;
                Last
              &lt;/a&gt;
            &lt;/li&gt;
        &lt;% } else { %&gt;
        // Ng&#x1B0;&#x1EE3;c l&#x1EA1;i, th&#xEC; Last l&#xE0; trang cu&#x1ED1;i c&#xF9;ng pages &#x1EDF; &#x111;&#xE2;y l&#xE0; 6 &#x111;&#x1ED3;ng ngh&#x129;a v&#x1EDB;i Last l&#xE0; trang s&#x1ED1; 6
            &lt;li class=&quot;page-item&quot;&gt;
              &lt;a class=&quot;page-link&quot; href=&quot;/news/&lt;%= pages %&gt;/&quot;&gt;
                Last
              &lt;/a&gt;
            &lt;/li&gt;
        &lt;% } %&gt;
      &lt;/ul&gt;
    &lt;/nav&gt;
    &lt;% } %&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;%- include(&apos;../layout/footer&apos;); -%&gt;
</code></pre>
<p><strong>V&#xE0; &#x111;&#xE2;y l&#xE0; k&#x1EBF;t qu&#x1EA3; khi ch&#xFA;ng ta &#x111;&#xE3; ho&#xE0;n th&#xE0;nh pagination cho n&#xF3;:))</strong></p>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1594997678/Untitled_affdsg.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Pagination V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB">
<p>T&#x1EEB; t&#x1EEB; m&#x1ECD;i ng&#x1B0;&#x1EDD;i &#x111;&#x1EEB;ng m&#x1EEB;ng v&#x1ED9;i c&#xF2;n m&#x1ED9;t vi&#x1EC7;c n&#x1EEF;a &#x111;&#xF3; l&#xE0; ch&#x1EA3; l&#x1EBB; gi&#x1EDD; mu&#x1ED1;n xem pagination th&#xEC; ph&#x1EA3;i ghi params <code>/news/1/</code> v&#xE0;o url nh&#x1B0; n&#xE0;y <code>http://localhost:3333/news/1/</code> nh&#xEC;n l&#xE0; bi&#x1EBF;t tr&#x1EA3;i nghi&#x1EC7;m ng&#x1B0;&#x1EDD;i d&#xF9;ng kh&#xF4;ng t&#x1ED1;t r&#x1ED3;i =))<br>
B&#xE2;y gi&#x1EDD; m&#xEC;nh s&#x1EBD; chuy&#x1EC3;n pagination ra trang home khi ng&#x1B0;&#x1EDD;i d&#xF9;ng v&#xE0;o l&#xE0; s&#x1EBD; th&#x1EA5;y xu&#x1EA5;t hi&#x1EC7;n ph&#xE2;n trang lu&#xF4;n. &#x110;&#x1A1;n gi&#x1EA3;n th&#xF4;i b&#xE2;y gi&#x1EDD; c&#x169;ng trong file <strong>index.rotes.js</strong> b&#x1EA1;n ch&#x1EC9; c&#x1EA7;n copy nguy&#xEA;n code t&#x1EEB;  <code>router.get(&apos;/news/:page&apos;)</code> sang <code>router.get(&apos;/&apos;)</code> l&#xE0; &#x111;&#x1B0;&#x1EE3;c th&#xF4;i m&#xE0;.</p>
<pre><code>// home page
router.get(&apos;/&apos;, (req, res, next)=&gt;{
  let perPage = 16; // s&#x1ED1; l&#x1B0;&#x1EE3;ng s&#x1EA3;n ph&#x1EA9;m xu&#x1EA5;t hi&#x1EC7;n tr&#xEA;n 1 page
  let page = req.params.page || 1; 

  Product
    .find() // find t&#x1EA5;t c&#x1EA3; c&#xE1;c data
    .skip((perPage * page) - perPage) // Trong page &#x111;&#x1EA7;u ti&#xEA;n s&#x1EBD; b&#x1ECF; qua gi&#xE1; tr&#x1ECB; l&#xE0; 0
    .limit(perPage)
    .exec((err, products) =&gt; {
      Product.countDocuments((err, count) =&gt; { // &#x111;&#x1EBF;m &#x111;&#x1EC3; t&#xED;nh xem c&#xF3; bao nhi&#xEA;u trang
        if (err) return next(err);
        res.render(&apos;product/index_product&apos;, {
          products, // s&#x1EA3;n ph&#x1EA9;m tr&#xEA;n m&#x1ED9;t page
          current: page, // page hi&#x1EC7;n t&#x1EA1;i
          pages: Math.ceil(count / perPage) // t&#x1ED5;ng s&#x1ED1; c&#xE1;c page
        });
      });
    });
})
</code></pre>
<p><strong>V&#xE0; &#x111;&#xE2;y l&#xE0; k&#x1EBF;t qu&#x1EA3; khi ch&#xFA;ng ta chuy&#x1EC3;n pagination ra ngo&#xE0;i home page nha:</strong></p>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1594995872/Untitled_qy9jpg.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Pagination V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB">
<p>V&#x1EAD;y l&#xE0; xong r&#x1ED3;i nha, c&#xE1;c b&#x1EA1;n c&#xF3; th&#x1EC3; tham kh&#x1EA3;o code m&#xE0; m&#xEC;nh &#x111;&#xE3; push l&#xEA;n github <a href="https://github.com/long1211/Pagination_NodeJS_Express">t&#x1EA1;i &#x111;&#xE2;y nha</a>.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h1 id="likt">L&#x1EDD;i K&#x1EBF;t</h1>
<p>V&#x1EAD;y L&#xE0; Xong b&#xE0;i H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Pagination V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB r&#x1ED3;i nh&#xE9;. M&#xEC;nh mong mu&#x1ED1;n sau b&#xE0;i topic n&#xE0;y c&#xE1;c b&#x1EA1;n c&#xF3; th&#x1EC3; bi&#x1EBF;t v&#xE0; hi&#x1EC3;u th&#xEA;m v&#x1EC1; nodejs, express v&#xE0; bi&#x1EBF;t pagination l&#xE0; g&#xEC;?, t&#x1EEB; topic n&#xE0;y c&#xE1;c b&#x1EA1;n c&#xF3; th&#x1EC3; m&#x1EDF; r&#x1ED9;ng th&#xEA;m &#xFD; t&#x1B0;&#x1EDF;ng v&#xE0; c&#xE1;ch l&#xE0;m m&#x1EDB;i. C&#xF3; th&#x1EC3; t&#x1EF1; tay m&#xEC;nh l&#xE0;m nh&#x1EEF;ng project kh&#xF4;ng c&#x1EA7;n ph&#x1EA3;i qu&#xE1; &#x111;&#x1EB7;c bi&#x1EC7;t nh&#x1B0;ng n&#xF3; do ch&#xED;nh b&#x1EA1;n l&#xE0;m th&#xEC; c&#x169;ng coi nh&#x1B0; l&#xE0; th&#xE0;nh qu&#x1EA3; trong qu&#xE1; tr&#xEC;nh b&#x1EA1;n h&#x1ECD;c &#x111;&#x1B0;&#x1EE3;c.</p>
<p><strong>C&#xE1;c b&#x1EA1;n nh&#x1EDB; like v&#xE0; theo d&#xF5;i fanpage <a href="https://www.facebook.com/thanhlongdev/">Thanh Long Dev</a> &#x111;&#x1EC3; nh&#x1EAD;n nh&#x1EEF;ng th&#xF4;ng b&#xE1;o v&#x1EC1; b&#xE0;i vi&#x1EBF;t m&#x1EDB;i nh&#x1EA5;t nha.</strong><br>
<em><strong>N&#x1EBF;u c&#xE1;c b&#x1EA1;n c&#x1EA3;m th&#x1EA5;y b&#xE0;i vi&#x1EBF;t c&#x1EE7;a m&#xEC;nh hay th&#xEC; c&#xE1;c b&#x1EA1;n c&#xF3; th&#x1EC3; &#x1EE7;ng h&#x1ED9; m&#xEC;nh &#x111;&#x1EC3; m&#xEC;nh c&#xF3; th&#xEA;m &#x111;&#x1ED9;ng l&#x1EF1;c &#x111;&#x1EC3; ra nh&#x1EEF;ng b&#xE0;i topic hay v&#xE0; ch&#x1EA5;t l&#x1B0;&#x1EE3;ng h&#x1A1;n &#x1EE7;ng h&#x1ED9; m&#xEC;nh <a href="https://vrdonate.vn/thanhlongdev">t&#x1EA1;i &#x111;&#xE2;y nha.</a></strong></em></p>
<p><strong>Ch&#xFA;c C&#xE1;c B&#x1EA1;n Th&#xE0;nh C&#xF4;ng!!</strong></p>
<!--kg-card-end: markdown--><!--kg-card-begin: html--><iframe src="https://www.facebook.com/plugins/like.php?href=https%3A%2F%2Fwww.thanhlongdev.com%2Fhuong-dan-xay-dung-pagination-voi-nodejs-express-va-mongodb%2F&amp;width=450&amp;layout=standard&amp;action=like&amp;size=large&amp;share=true&amp;height=35&amp;appId=2794898430534168" width="450" height="35" style="border:none;overflow:hidden" scrolling="no" frameborder="0" allowtransparency="true" allow="encrypted-media"></iframe><!--kg-card-end: html--><!--kg-card-begin: html--><div class="fb-comments" data-href="https://www.thanhlongdev.com/huong-dan-xay-dung-pagination-voi-nodejs-express-va-mongodb/" data-width="100%" data-numposts="10"></div><!--kg-card-end: html-->]]></content:encoded></item><item><title><![CDATA[Con Đường Học Lập Trình Web Của Mình Và Truyền Cảm Hứng Học Đến Các Bạn]]></title><description><![CDATA[<!--kg-card-begin: markdown--><h1 id="giithiuchung">Gi&#x1EDB;i Thi&#x1EC7;u Chung</h1>
<p>H&#xF4;m nay m&#xEC;nh s&#x1EBD; vi&#x1EBF;t v&#x1EC1; m&#x1ED9;t topic ch&#x1EA3; li&#xEA;n quan g&#xEC; &#x111;&#x1EBF;n k&#x1EF9; thu&#x1EAD;t c&#x1EA3; v&#xE0; &#x111;&#xE2;y c&#x169;</p>]]></description><link>https://www.thanhlongdev.com/con-duong-hoc-lap-trinh-web-cua-minh/</link><guid isPermaLink="false">5eb0ddf87849f100011f0faa</guid><category><![CDATA[Vừa Code Vừa Xàm]]></category><dc:creator><![CDATA[Đặng Thanh Long]]></dc:creator><pubDate>Sat, 09 May 2020 15:25:58 GMT</pubDate><media:content url="https://digitalpress.fra1.cdn.digitaloceanspaces.com/4tg23ij/2020/05/lap-trinh-vien.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h1 id="giithiuchung">Gi&#x1EDB;i Thi&#x1EC7;u Chung</h1>
<img src="https://digitalpress.fra1.cdn.digitaloceanspaces.com/4tg23ij/2020/05/lap-trinh-vien.png" alt="Con &#x110;&#x1B0;&#x1EDD;ng H&#x1ECD;c L&#x1EAD;p Tr&#xEC;nh Web C&#x1EE7;a M&#xEC;nh V&#xE0; Truy&#x1EC1;n C&#x1EA3;m H&#x1EE9;ng H&#x1ECD;c &#x110;&#x1EBF;n C&#xE1;c B&#x1EA1;n"><p>H&#xF4;m nay m&#xEC;nh s&#x1EBD; vi&#x1EBF;t v&#x1EC1; m&#x1ED9;t topic ch&#x1EA3; li&#xEA;n quan g&#xEC; &#x111;&#x1EBF;n k&#x1EF9; thu&#x1EAD;t c&#x1EA3; v&#xE0; &#x111;&#xE2;y c&#x169;ng l&#xE0; l&#x1EA7;n &#x111;&#x1EA7;u ti&#xEA;n m&#xEC;nh vi&#x1EBF;t v&#x1EC1; m&#x1EA5;y ch&#x1EE7; &#x111;&#x1EC1; n&#xE0;y. N&#x1EBF;u c&#xF3; sai s&#xF3;t g&#xEC; th&#xEC; mong c&#xE1;c b&#x1EA1;n th&#xF4;ng c&#x1EA3;m nha.<br>
Nh&#x1B0; c&#xE1;c b&#x1EA1;n &#x111;&#xE3; th&#x1EA5;y &#x1EDF; tr&#xEA;n ti&#xEA;u &#x111;&#x1EC1; th&#xEC; h&#xF4;m nay m&#xEC;nh s&#x1EBD; vi&#x1EBF;t m&#x1ED9;t b&#xE0;i chia s&#x1EBD; v&#x1EC1; con &#x111;&#x1B0;&#x1EDD;ng tr&#x1EDF; th&#xE0;nh Dev v&#xE0; m&#xEC;nh s&#x1EBD; chia s&#x1EBD; m&#x1ED9;t c&#xE1;ch &#x111;&#x1EA7;y &#x111;&#x1EE7; nh&#x1EA5;t gi&#xFA;p c&#xE1;c b&#x1EA1;n l&#x1EA5;y l&#x1EA1;i &#x111;&#x1ED9;ng l&#x1EF1;c v&#xE0; c&#x1EA3;m h&#x1EE9;ng khi h&#x1ECD;c.<br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1588910246/hoc_lap_trinh_web_ly82px.jpg" width="700" alt="Con &#x110;&#x1B0;&#x1EDD;ng H&#x1ECD;c L&#x1EAD;p Tr&#xEC;nh Web C&#x1EE7;a M&#xEC;nh V&#xE0; Truy&#x1EC1;n C&#x1EA3;m H&#x1EE9;ng H&#x1ECD;c &#x110;&#x1EBF;n C&#xE1;c B&#x1EA1;n"></p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h1 id="connghclptrnhwebcamnh">Con &#x110;&#x1B0;&#x1EDD;ng H&#x1ECD;c L&#x1EAD;p Tr&#xEC;nh Web C&#x1EE7;a M&#xEC;nh</h1>
<p>Th&#xEC; m&#xEC;nh c&#x169;ng kh&#xF4;ng l&#xF2;ng v&#xF2;ng n&#x1EEF;a m&#xEC;nh c&#x169;ng n&#xF3;i lu&#xF4;n. V&#xE0;o <em><strong>th&#xE1;ng 10/2017</strong></em> m&#xEC;nh b&#x1EAF;t &#x111;&#x1EA7;u bi&#x1EBF;t &#x111;&#x1EBF;n l&#x1EAD;p tr&#xEC;nh v&#xE0; &#x111;&#x1B0;&#x1EE3;c va ch&#x1EA1;m v&#x1EDB;i ng&#xF4;n ng&#x1EEF; &#x111;&#x1EA7;u ti&#xEA;n l&#xE0; Pascal(ng&#xF4;n ng&#x1EEF; huy&#x1EC1;n tho&#x1EA1;i^^). M&#xEC;nh l&#xE0; m&#x1ED9;t th&#x1EB1;ng r&#x1EA5;t th&#xED;ch ch&#x1EBF; ch&#xE1;o l&#xE0; fan c&#x1EE9;ng c&#x1EE7;a KST m&#xE0;:)), trong m&#x1ED9;t ng&#xE0;y &#x111;&#x1EB9;p tr&#x1EDD;i m&#xEC;nh &#x111;&#x1B0;&#x1EE3;c m&#x1ED9;t ng&#x1B0;&#x1EDD;i b&#x1EA1;n gi&#x1EDB;i thi&#x1EC7;u v&#x1EC1; arduino.</p>
<p>V&#xE0; th&#x1EBF; l&#xE0; m&#xEC;nh chuy&#x1EC3;n h&#x1B0;&#x1EDB;ng qua v&#x1ECD;c arduino v&#x1EDB;i mong mu&#x1ED1;n l&#xE0; ch&#x1EBF; &#x111;&#x1B0;&#x1EE3;c m&#x1ED9;t con robot ph&#x1A1;i n&#xF4;ng s&#x1EA3;n nh&#x1B0;ng &#x111;&#x1EDD;i kh&#xF4;ng nh&#x1B0; l&#xE0; m&#x1A1;. B&#x1EDF;i v&#xEC; sao n&#xF3; kh&#xF4;ng nh&#x1B0; l&#xE0; m&#x1A1; v&#xEC; m&#xEC;nh m&#xE9;o c&#xF3; t&#x1EB9;o n&#xE0;o v&#x1EC1; c&#x103;n b&#x1EA3;n c&#x1EE7;a arduino nh&#x1B0;ng l&#x1EA1;i mong mu&#x1ED1;n l&#xE0;m &#x111;&#x1B0;&#x1EE3;c m&#x1ED9;t s&#x1EA3;n ph&#x1EA9;m ho&#xE0;n thi&#x1EC7;n. M&#xEC;nh &#x111;&#x1EA7;u t&#x1B0; r&#x1EA5;t nhi&#x1EC1;u v&#x1EC1; th&#x1EDD;i gian, c&#xF4;ng s&#x1EE9;c v&#xE0; ti&#x1EC1;n b&#x1EA1;c v&#x1EC1; c&#xE1;c m&#xF3;n &#x111;&#x1ED3; linh ki&#x1EC7;n &#x111;i&#x1EC7;n t&#x1EED; nh&#x1B0;: module L298, Srf05, Arduino Uno &amp; Mega, Encoder, m&#x1EA1;ch in,...<br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1588950587/Arduino_unoR3_Clock2_qhdwez.png" alt="Con &#x110;&#x1B0;&#x1EDD;ng H&#x1ECD;c L&#x1EAD;p Tr&#xEC;nh Web C&#x1EE7;a M&#xEC;nh V&#xE0; Truy&#x1EC1;n C&#x1EA3;m H&#x1EE9;ng H&#x1ECD;c &#x110;&#x1EBF;n C&#xE1;c B&#x1EA1;n"></p>
<p>Ui c&#xF4;ng nh&#x1EAD;n l&#xFA;c &#x111;&#xF3; m&#xEC;nh l&#xE0;m li&#x1EC1;u th&#x1EAD;t kh&#xF4;ng bi&#x1EBF;t n&#xF3; c&#xF3; ch&#x1EA1;y hay kh&#xF4;ng nh&#x1B0;ng m&#xEC;nh l&#xE0;m kh&#xE1; c&#xF4;ng phu v&#xE0; &#x111;&#x1EBF;n b&#x1B0;&#x1EDB;c quan tr&#x1ECD;ng nh&#x1EA5;t l&#xE0; l&#xE0;m sao &#x111;&#x1EC3; xe n&#xF3; ch&#x1EA1;y theo &#x111;&#xFA;ng &#xFD; m&#xEC;nh th&#xEC; m&#xEC;nh l&#x1EA1;i th&#x1EA5;t b&#x1EA1;i ngay b&#x1B0;&#x1EDB;c n&#xE0;y &#x111;&#xF3; l&#xE0; do s&#x1EF1; chu&#x1EA9;n b&#x1ECB; kh&#xF4;ng t&#x1ED1;t, tr&#xE8;o qu&#xE1; cao m&#xEC;nh kh&#xF4;ng bi&#x1EBF;t n&#xF3;i nh&#x1B0; l&#xE0;o cho h&#x1EE3;p l&#xFD; nh&#x1EDF;. Ki&#x1EC3;u gi&#x1ED1;ng nh&#x1B0; m&#x1ED9;t ng&#xF4;i nh&#xE0; &#x111;ang x&#xE2;y r&#x1EA5;t l&#xE0; cao v&#xE0; &#x111;&#x1EB9;p th&#xEC; b&#x1ED5;ng m&#x1ED9;t ng&#xE0;y n&#xF3; &#x111;&#x1ED5; s&#x1EAD;p l&#xE0; do ph&#x1EA7;n m&#xF3;ng n&#xF3; kh&#xF4;ng &#x111;&#x1B0;&#x1EE3;c ch&#x1EAF;c ch&#x1EAF;n &#x111;&#xFA;ng kh&#xF4;ng n&#xE0;o th&#xEC; s&#x1EA3;n ph&#x1EA9;m m&#xEC;nh l&#xE0;m n&#xF3; c&#x169;ng nh&#x1B0; v&#x1EAD;y &#x111;&#xF3;. Nhi&#x1EC1;u l&#xFA;c n&#x1EA3;n th&#x1EAD;t s&#x1EF1; c&#xE1;c &#xF4;ng &#x1EA1; v&#xE0; m&#xEC;nh c&#x169;ng &#x111;&#xE3; &#x111;&#x1B0;a ra quy&#x1EBF;t &#x111;&#x1ECB;nh l&#xE0; b&#x1ECF; s&#x1EA3;n ph&#x1EA9;m n&#xE0;y &#x111;&#x1EC3; h&#x1ECD;c l&#x1EA1;i ki&#x1EBF;n th&#xFA;c n&#x1EC1;n th&#x1EAD;t v&#x1EEF;ng v&#xE0; l&#xE0;m m&#x1ED9;t s&#x1EA3;n ph&#x1EA9;m v&#xE0; cu&#x1ED1;i c&#xF9;ng n&#xF3; c&#x169;ng &#x111;&#xE3; th&#xE0;nh c&#xF4;ng. Sau m&#x1ED9;t th&#x1EDD;i gian reseach th&#xEC; m&#xEC;nh c&#x1EA3;m th&#x1EA5;y m&#xE9;o c&#xF3; c&#x1EA3;m t&#xEC;nh ch&#xFA;t n&#xE0;o n&#xEA;n b&#x1ECF; arduino &#x111;&#x1EBF;n gi&#x1EDD; v&#xE0; m&#xEC;nh c&#x169;ng qu&#xEA;n cmnr =))).</p>
<p><strong>Note:</strong> Sau b&#xE0;i h&#x1ECD;c tr&#xEA;n th&#xEC; m&#xEC;nh c&#x169;ng r&#xFA;t ra &#x111;&#x1B0;&#x1EE3;c m&#x1ED9;t s&#x1ED1; b&#xE0;i h&#x1ECD;c v&#xE0; mu&#x1ED1;n nh&#x1EAF;n nh&#x1EE7; v&#x1EDB;i c&#xE1;c b&#x1EA1;n r&#x1EB1;ng mu&#x1ED1;n l&#xE0;m &#x111;&#x1B0;&#x1EE3;c vi&#x1EC7;c l&#x1EDB;n th&#xEC; ph&#x1EA3;i l&#xE0;m &#x111;&#x1B0;&#x1EE3;c vi&#x1EC7;c nh&#x1ECF;, kh&#xF4;ng ai h&#x1ECD;c m&#x1ED9;t hay hai ng&#xE0;y m&#xE0; c&#xF3; th&#x1EC3; l&#xE0;m &#x111;&#x1B0;&#x1EE3;c v&#xE0; gi&#x1ECF;i ngay t&#x1EA5;t c&#x1EA3; &#x111;&#x1EC1;u c&#x1EA7;n c&#xF3; th&#x1EDD;i gian &#x111;&#x1EC3; th&#x1EF1;c hi&#x1EC7;n v&#xE0; c&#x1EA7;n ph&#x1EA3;i c&#xF3; c&#xE1;i &quot;m&#xF3;ng&quot; th&#x1EAD;t v&#x1EEF;ng nhoa. M&#xEC;nh th&#x1EA5;y kh&#xE1; r&#xF5; t&#xEC;nh tr&#x1EA1;ng h&#x1ECD;c l&#x1EAD;p tr&#xEC;nh c&#x1EE7;a c&#xE1;c b&#x1EA1;n hi&#x1EC7;n nay l&#xFA;c n&#xE0;o c&#x169;ng mong mu&#x1ED1;n l&#xE0; m&#xEC;nh l&#xE0;m &#x111;&#x1B0;&#x1EE3;c m&#x1ED9;t c&#xE1;i project g&#xEC; &#x111;&#xF3; hay hay v&#xE0; kh&#xF4;ng c&#x1EA7;n bi&#x1EBF;t l&#xE0; n&#xF3; &#x111;&#x1B0;&#x1EE3;c l&#xE0;m nh&#x1B0; th&#x1EBF; n&#xE0;o c&#x1EA3;. &#x110;&#x1EA5;y l&#xE0; m&#x1ED9;t sai l&#x1EA7;m r&#x1EA5;t l&#x1EDB;n nh&#xE1; c&#x1EA7;n ph&#x1EA3;i nh&#xEC;n nh&#x1EAD;n l&#x1EA1;i v&#xE0; thay &#x111;&#x1ED5;i ngay.</p>
<p>Sau bao nhi&#xEA;u ng&#xE0;y th&#xE1;ng ch&#xE1;n n&#x1EA3;n th&#xEC; cu&#x1ED1;i c&#xF9;ng v&#xE0;o <em><strong>th&#xE1;ng 12/2018</strong></em>, m&#xEC;nh c&#x169;ng &#x111;&#xE3; ch&#x1ECD;n &#x111;&#xFA;ng con &#x111;&#x1B0;&#x1EDD;ng m&#xEC;nh &#x111;i v&#xE0; theo n&#xF3; &#x111;&#x1EBF;n c&#xF9;ng &#x111;&#xF3; l&#xE0; l&#x1EAD;p tr&#xEC;nh WEB. Nh&#x1B0;ng c&#x169;ng nh&#x1EDD; nh&#x1EEF;ng v&#x1EA5;p ng&#xE3; &#x1EDF; tr&#xEA;n nh&#x1EEF;ng l&#x1EA7;n th&#x1EA5;t b&#x1EA1;i th&#xEC; m&#xEC;nh c&#xE0;ng m&#x1EA1;nh m&#x1EBD; h&#x1A1;n &#x111;&#x1EC3; c&#xF3; th&#x1EC3; &#x111;&#x1EE9;ng d&#x1EAD;y v&#xE0; l&#xE0;m l&#x1EA1;i t&#x1EEB; &#x111;&#x1EA7;u.<br>
N&#x1A1;i m&#xE0; m&#xEC;nh b&#x1EAF;t &#x111;&#x1EA7;u h&#x1ECD;c &#x111;&#xF3; l&#xE0; k&#xEA;nh youtube th&#x1B0; vi&#x1EC7;n l&#x1EAD;p tr&#xEC;nh l&#xFA;c &#x1EA5;y th&#xEC; c&#x169;ng kh&#xF4;ng bi&#x1EBF;t g&#xEC; c&#x1EA3; l&#xEA;n youtube search v&#x1EDB;i keyword h&#x1ECD;c l&#x1EAD;p tr&#xEC;nh web th&#xEC; n&#xF3; ra m&#x1ED9;t playlist c&#x1EE7;a th&#x1B0; vi&#x1EC7;n l&#x1EAD;p tr&#xEC;nh kh&#xE1; &#x111;&#x1EA7;y &#x111;&#x1EE7; t&#x1EEB; html, css, js,..Nh&#x1EDD; b&#xE0;i h&#x1ECD;c r&#xFA;t ra &#x1EDF; tr&#xEA;n n&#xEA;n khi h&#x1ECD;c l&#x1EAD;p tr&#xEC;nh web m&#xEC;nh h&#x1ECD;c r&#x1EA5;t l&#xE0; nghi&#xEA;m t&#xFA;c t&#x1EEB; c&#x1A1; b&#x1EA3;n &#x111;&#x1EBF;n n&#xE2;ng cao kh&#xF4;ng s&#xF3;t m&#x1ED9;t gi&#xE2;y n&#xE0;o c&#xE1;c &#xF4;ng &#x1EA1;. Sau khi h&#x1ECD;c xong th&#xEC; m&#xEC;nh b&#x1EAF;t &#x111;&#x1EA7;u l&#xE0; c&#x1EAF;t psd sang HTMl, n&#xF3;i th&#x1EAD;t v&#x1EDB;i c&#xE1;c &#xF4;ng ch&#x1EDB; l&#x1EA7;n &#x111;&#x1EA7;u m&#xEC;nh c&#x1EAF;t code n&#xF3; kinh th&#x1EAD;t x&#x1EA5;u d&#xE3; man:)) l&#x1EA7;n &#x111;&#x1EA7;u l&#xE0;m chuy&#x1EC7;n &#x1EA5;y m&#xE0;.</p>
<p>Sau m&#x1ED9;t th&#x1EDD;i gian m&#xEC;nh luy&#x1EC7;n c&#x1EAF;t psd &#x1EA5;y th&#xEC; m&#xEC;nh nh&#x1EAD;n ra l&#xE0; m&#xEC;nh c&#xF2;n ph&#x1EA3;i b&#x1ED5; sung r&#x1EA5;t nhi&#x1EC1;u ki&#x1EBF;n th&#x1EE9;c v&#xE0; nh&#x1EA5;t l&#xE0; JS(javascript). Th&#xEC; t&#xED;nh c&#x1EDD; m&#xEC;nh bi&#x1EBF;t &#x111;&#x1EBF;n CodersX(l&#xFA;c tr&#x1B0;&#x1EDB;c l&#xE0; Coders.Tokyo) c&#xF3; d&#x1EA1;y h&#x1ECD;c l&#x1EAD;p tr&#xEC;nh web mi&#x1EC5;n ph&#xED; th&#x1EBF; l&#xE0; m&#xEC;nh l&#x1EA7;n m&#xF2; &#x111;&#x1EBF;n h&#x1ECD;c thui, ki&#x1EBF;n th&#x1EE9;c &#x1EDF; &#x111;&#x1EA5;y r&#x1EA5;t l&#xE0; hay v&#xE0; b&#x1ED5; &#xED;ch c&#xE1;c &#xF4;ng &#x1EA1; &#x1EDF; m&#xEC;nh &#x111;&#xE2;y m&#xEC;nh kh&#xF4;ng c&#xF3; PR hay g&#xEC; nha n&#x1EBF;u c&#xE1;c &#xF4;ng kh&#xF4;ng tin th&#xEC; ph&#x1EA3;i h&#x1ECD;c th&#x1EED; l&#xE0; bi&#x1EBF;t ngay &#x1EA5;y m&#xE0;. Th&#xEC; nh&#x1EDD; CodersX m&#xE0; m&#xEC;nh h&#x1ECD;c &#x111;&#x1B0;&#x1EE3;c r&#x1EA5;t nhi&#x1EC1;u ki&#x1EBF;n th&#x1EE9;c v&#xE0; c&#x169;ng xin c&#x1EA3;m &#x1A1;n anh Th&#x1ECB;nh v&#xE0; team &#x111;&#xE3; t&#x1EA1;o ra CodersX.</p>
<p>&#x110;&#x1EA5;y ch&#x1EC9; l&#xE0; hai k&#xEA;nh m&#xEC;nh h&#x1ECD;c ch&#x1EE7; y&#x1EBF;u nh&#x1B0;ng trong &#x111;&#xF3; m&#xEC;nh khuy&#xEA;n c&#xE1;c b&#x1EA1;n ch&#x1ECB;u kh&#xF3; reseach xem nhi&#x1EC1;u ki&#x1EBF;n th&#x1EE9;c h&#x1A1;n tr&#xEA;n youtube v&#xE0; &#x111;&#x1ECD;c c&#xE1;c b&#xE0;i blog li&#xEA;n quan &#x111;&#x1EBF;n b&#xE0;i m&#xEC;nh h&#x1ECD;c nha. N&#xF3; gi&#xFA;p &#xED;ch c&#xE1;c b&#x1EA1;n r&#x1EA5;t nhi&#x1EC1;u trong qu&#xE1; tr&#xEC;nh h&#x1ECD;c v&#xE0; l&#xE0;m vi&#x1EC7;c &#x111;&#xF3; nha. <em>M&#xEC;nh &#x111;&#xE3; h&#x1ECD;c l&#x1EAD;p tr&#xEC;nh web v&#xE0; tr&#x1EDF; th&#xE0;nh dev nh&#x1B0; th&#x1EBF; &#x111;&#x1EA5;y ==))</em></p>
<p><strong>Note:</strong> &#x110;&#x1EC3; mu&#x1ED1;n h&#x1ECD;c &#x111;&#x1B0;&#x1EE3;c l&#x1EAD;p tr&#xEC;nh web th&#xEC; c&#xE1;c b&#x1EA1;n c&#x1EA7;n ph&#x1EA3;i n&#x1EAF;m v&#x1EEF;ng c&#xE1;c ki&#x1EBF;n th&#x1EE9;c c&#x1A1; b&#x1EA3;n nha ch&#x1B0;a bi&#x1EBF;t b&#xF2; m&#xE0; mu&#x1ED1;n &#x111;i l&#xE0; h&#xF4;ng &#x111;&#x1B0;&#x1EE3;c &#x111;&#xF3; nha. Ph&#x1EA3;i c&#xF3; l&#x1ED9; tr&#xEC;nh, &#x111;&#x1ECB;nh h&#x1B0;&#x1EDB;ng r&#xF5; r&#xE0;ng h&#x1ECD;c &#x111;&#x1EC3; l&#xE0;m g&#xEC; &#x111;&#x1EC3; khi g&#x1EB7;p kh&#xF3; kh&#x103;n trong qu&#xE1; tr&#xEC;nh h&#x1ECD;c th&#xEC; c&#xF2;n c&#xF3; &#x111;&#x1ED9;ng l&#x1EF1;c m&#xE0; c&#x1ED1; g&#x1EB1;ng v&#xE0; cu&#x1ED1;i c&#xF9;ng &#x111;&#xF3; l&#xE0; &#x111;am m&#xEA;, can &#x111;&#x1EA3;m,...</p>
<h2 id="ltrnhhclptrnhweb">L&#x1ED9; Tr&#xEC;nh H&#x1ECD;c L&#x1EAD;p Tr&#xEC;nh Web</h2>
<p>Trong l&#x1EAD;p tr&#xEC;nh ng&#x1B0;&#x1EDD;i ta chia l&#xE0;m 3 m&#x1EA3;ng: Frontend, Backend or DevOps v&#xE0; c&#xF2;n m&#x1ED9;t th&#x1EB1;ng n&#x1EEF;a &#x111;&#xF3; l&#xE0; phun s&#x1EDD; n&#xE1;ch(fullstack)^^. M&#xEC;nh khuy&#xEA;n c&#xE1;c b&#x1EA1;n n&#xEA;n ch&#x1ECD;n m&#x1ED9;t trong nh&#x1EEF;ng th&#x1EE9; tr&#xEA;n th&#xF4;i nha. Trong qu&#xE1; tr&#xEC;nh b&#x1EA1;n l&#xE0;m hay h&#x1ECD;c th&#xEC; b&#x1EA1;n c&#xF3; th&#x1EC3; h&#x1ECD;c ti&#x1EBF;p c&#xE1;c ki&#x1EBF;n th&#x1EE9;c c&#xF2;n l&#x1EA1;i. C&#xF2;n chi ti&#x1EBF;t frontend, backend v&#xE0; devops c&#x1EA7;n h&#x1ECD;c nh&#x1EEF;ng g&#xEC; th&#xEC; c&#xE1;c b&#x1EA1;n xem <a href="https://github.com/kamranahmedse/developer-roadmap">t&#x1EA1;i &#x111;&#xE2;y nha</a>.<br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1589034126/1_5fAC5CQzotxKjt2YFIg-Rw_g9dpcu.png" alt="Con &#x110;&#x1B0;&#x1EDD;ng H&#x1ECD;c L&#x1EAD;p Tr&#xEC;nh Web C&#x1EE7;a M&#xEC;nh V&#xE0; Truy&#x1EC1;n C&#x1EA3;m H&#x1EE9;ng H&#x1ECD;c &#x110;&#x1EBF;n C&#xE1;c B&#x1EA1;n"></p>
<h1 id="truyncmhnghcnmingi">Truy&#x1EC1;n C&#x1EA3;m H&#x1EE9;ng H&#x1ECD;c &#x110;&#x1EBF;n M&#x1ECD;i Ng&#x1B0;&#x1EDD;i</h1>
<p>Truy&#x1EC1;n c&#x1EA3;m h&#x1EE9;ng &#x1EDF; &#x111;&#xE2;y l&#xE0; m&#xEC;nh mu&#x1ED1;n n&#xF3;i v&#x1EDB;i c&#xE1;c b&#x1EA1;n r&#x1EB1;ng. M&#x1ED7;i ng&#x1B0;&#x1EDD;i ch&#xFA;ng ta &#x111;&#x1EC1;u c&#xF3; con &#x111;&#x1B0;&#x1EDD;ng &#x111;i kh&#xE1;c nhau v&#xE0; c&#xF3; &#x111;i&#x1EC3;m xu&#x1EA5;t ph&#xE1;t kh&#xE1;c nhau, c&#xF3; ng&#x1B0;&#x1EDD;i ba m&#x1EA5;y b&#x1ED1;n m&#x1B0;&#x1A1;i tu&#x1ED5;i m&#x1EDB;i b&#x1EAF;t &#x111;&#x1EA7;u h&#x1ECD;c c&#xF2;n c&#xF3; ng&#x1B0;&#x1EDD;i m&#x1B0;&#x1EDD;i tu&#x1ED5;i l&#xE0; &#x111;&#xE3; l&#xE0;m quen v&#x1EDB;i l&#x1EAD;p tr&#xEC;nh r&#xF9;i. H&#x1ECD;c kh&#xF4;ng bao gi&#x1EDD; l&#xE0; qu&#xE1; mu&#x1ED9;n n&#xF3; ch&#x1EC9; mu&#x1ED9;n khi b&#x1EA1;n kh&#xF4;ng h&#x1ECD;c. C&#xF2;n h&#x1ECD;c nh&#x1B0; th&#x1EBF; n&#xE0;o th&#xEC; m&#xEC;nh c&#x169;ng &#x111;&#xE3; n&#xF3;i &#x1EDF; tr&#xEA;n r&#x1ED3;i. M&#xEC;nh vi&#x1EBF;t blog n&#xE0;y mong mu&#x1ED1;n chia s&#x1EBD; ch&#xFA;t ki&#x1EBF;n th&#x1EE9;c h&#x1EA1;n h&#x1EB9;p c&#x1EE7;a m&#xEC;nh &#x111;&#x1EBF;n c&#xE1;c b&#x1EA1;n &#x111;&#x1EC3; c&#xF9;ng nhau ph&#xE1;t tri&#x1EC3;n. M&#xEC;nh kh&#xF4;ng khuy&#xEA;n c&#xE1;c b&#x1EA1;n n&#xEA;n h&#x1ECD;c c&#xE1;i n&#xE0;y v&#xE0; b&#x1ECF; c&#xE1;i kia. B&#x1EDF;i v&#xEC; cu&#x1ED9;c &#x111;&#x1EDD;i n&#xE0;y l&#xE0; do b&#x1EA1;n quy&#x1EBF;t &#x111;&#x1ECB;nh gi&#xE0;u ngh&#xE8;o c&#x169;ng do b&#x1EA1;n quy&#x1EBF;t &#x111;&#x1ECB;nh, m&#xEC;nh ph&#x1EA3;i tin t&#x1B0;&#x1EDF;ng v&#xE0;o b&#x1EA3;n th&#xE2;n m&#xEC;nh ch&#x1EDB;. M&#xEC;nh tin c&#xE1;c b&#x1EA1;n l&#xE0;m &#x111;&#x1B0;&#x1EE3;c v&#xE0; c&#xF2;n l&#xE0;m r&#x1EA5;t t&#x1ED1;t n&#x1EEF;a.<br>
<em><strong>C&#x1ED0; L&#xCA;N N&#xC0;O!!!</strong></em></p>
<p>Jack Ma c&#xF3; m&#x1ED9;t c&#xE2;u n&#xF3;i r&#x1EA5;t hay: &quot;N&#x1EBF;u b&#x1EA1;n kh&#xF4;ng b&#x1EAF;t tay v&#xE0;o l&#xE0;m th&#xEC; ch&#x1EB3;ng c&#xF3; &#x111;i&#x1EC1;u g&#xEC; l&#xE0; kh&#x1EA3; thi c&#x1EA3;&quot;<br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1589036079/Kh_C3_B4ng_20th_E1_BB_AD_20sao_20bi_E1_BA_BFt_h86pfa.png" alt="Con &#x110;&#x1B0;&#x1EDD;ng H&#x1ECD;c L&#x1EAD;p Tr&#xEC;nh Web C&#x1EE7;a M&#xEC;nh V&#xE0; Truy&#x1EC1;n C&#x1EA3;m H&#x1EE9;ng H&#x1ECD;c &#x110;&#x1EBF;n C&#xE1;c B&#x1EA1;n"></p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h1 id="likt">L&#x1EDD;i K&#x1EBF;t</h1>
<p>T&#xF3;m l&#x1EA1;i th&#xEC; b&#xE0;i n&#xE0;y m&#xEC;nh c&#x169;ng n&#xF3;i v&#x1EC1; con &#x111;&#x1B0;&#x1EDD;ng m&#xE0; m&#xEC;nh h&#x1ECD;c l&#x1EAD;p tr&#xEC;nh web v&#xE0; nh&#x1EEF;ng b&#xE0;i h&#x1ECD;c m&#xEC;nh &#x111;&#xE3; tr&#x1EA3;i qua. Mong mu&#x1ED1;n truy&#x1EC1;n c&#x1EA3;m h&#x1EE9;ng h&#x1ECD;c &#x111;&#x1EBF;n c&#xE1;c b&#x1EA1;n c&#x169;ng m&#x1ED9;t ph&#x1EA7;n n&#xE0;o &#x111;&#xF3; gi&#xFA;p c&#xE1;c b&#x1EA1;n c&#xF3; th&#xEA;m &#x111;&#x1ED9;ng l&#x1EF1;c &#x111;&#x1EC3; h&#x1ECD;c h&#x1A1;n. &#x110;&#xE2;y l&#xE0; l&#x1EA7;n &#x111;&#x1EA7;u m&#xEC;nh vi&#x1EBF;t m&#x1ED9;t topic ch&#x1EA3; li&#xEA;n quan g&#xEC; &#x111;&#x1EBF;n k&#x1EF9; thu&#x1EAD;t n&#xEA;n c&#xF3; sai s&#xF3;t g&#xEC; mong c&#xE1;c b&#x1EA1;n th&#xF4;ng c&#x1EA3;m.</p>
<p><strong>N&#x1EBF;u c&#xE1;c b&#x1EA1;n c&#x1EA3;m th&#x1EA5;y b&#xE0;i vi&#x1EBF;t c&#x1EE7;a m&#xEC;nh hay th&#xEC; c&#xE1;c b&#x1EA1;n c&#xF3; th&#x1EC3; &#x1EE7;ng h&#x1ED9; m&#xEC;nh &#x111;&#x1EC3; m&#xEC;nh c&#xF3; th&#xEA;m &#x111;&#x1ED9;ng l&#x1EF1;c &#x111;&#x1EC3; ra nh&#x1EEF;ng b&#xE0;i topic hay v&#xE0; ch&#x1EA5;t l&#x1B0;&#x1EE3;ng h&#x1A1;n &#x1EE7;ng h&#x1ED9; m&#xEC;nh <a href="https://vrdonate.vn/thanhlongdev">t&#x1EA1;i &#x111;&#xE2;y nha</a>.</strong></p>
<p><em><strong>Ch&#xFA;c C&#xE1;c B&#x1EA1;n Th&#xE0;nh C&#xF4;ng!!</strong></em></p>
<!--kg-card-end: markdown--><!--kg-card-begin: html--><iframe src="https://www.facebook.com/plugins/like.php?href=https%3A%2F%2Fwww.thanhlongdev.com%2Fcon-duong-hoc-lap-trinh-web-cua-minh%2F&amp;width=450&amp;layout=standard&amp;action=like&amp;size=large&amp;share=true&amp;height=35&amp;appId=2794898430534168" width="450" height="35" style="border:none;overflow:hidden" scrolling="no" frameborder="0" allowtransparency="true" allow="encrypted-media"></iframe><!--kg-card-end: html--><!--kg-card-begin: html--><div class="fb-comments" data-href="https://www.thanhlongdev.com/con-duong-hoc-lap-trinh-web-cua-minh/" data-width="100%" data-numposts="10"></div><!--kg-card-end: html-->]]></content:encoded></item><item><title><![CDATA[Hướng Dẫn Crawl Dữ Liệu Với Puppeteer Và Nodejs]]></title><description><![CDATA[<!--kg-card-begin: markdown--><h1 id="giithiuchung">Gi&#x1EDB;i Thi&#x1EC7;u Chung</h1>
<p>H&#xF4;m nay m&#xEC;nh s&#x1EBD; h&#x1B0;&#x1EDB;ng d&#x1EAB;n t&#x1EA5;t c&#x1EA3; m&#x1ECD;i ng&#x1B0;&#x1EDD;i crawl d&#x1EEF; li&#x1EC7;u trang linh ki&#x1EC7;n &#x111;i&#x1EC7;n</p>]]></description><link>https://www.thanhlongdev.com/huong-dan-crawl-du-lieu-bang-puppeteer/</link><guid isPermaLink="false">5e6cf8a78c4cb800013609bd</guid><category><![CDATA[Lập Trình Web]]></category><dc:creator><![CDATA[Đặng Thanh Long]]></dc:creator><pubDate>Mon, 16 Mar 2020 16:16:21 GMT</pubDate><media:content url="https://digitalpress.fra1.cdn.digitaloceanspaces.com/4tg23ij/2020/03/kP6LX2t.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h1 id="giithiuchung">Gi&#x1EDB;i Thi&#x1EC7;u Chung</h1>
<img src="https://digitalpress.fra1.cdn.digitaloceanspaces.com/4tg23ij/2020/03/kP6LX2t.jpg" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n Crawl D&#x1EEF; Li&#x1EC7;u V&#x1EDB;i Puppeteer V&#xE0; Nodejs"><p>H&#xF4;m nay m&#xEC;nh s&#x1EBD; h&#x1B0;&#x1EDB;ng d&#x1EAB;n t&#x1EA5;t c&#x1EA3; m&#x1ECD;i ng&#x1B0;&#x1EDD;i crawl d&#x1EEF; li&#x1EC7;u trang linh ki&#x1EC7;n &#x111;i&#x1EC7;n t&#x1EED; NShop. M&#xEC;nh s&#x1EBD; gi&#x1EDB;i thi&#x1EC7;u &#x111;&#x1EBF;n t&#x1EA5;t c&#x1EA3; m&#x1ECD;i ng&#x1B0;&#x1EDD;i v&#x1EC1; puppeteer, headless browser v&#xE0; puppeteer n&#xF3; d&#xF9;ng &#x111;&#x1EC3; l&#xE0;m g&#xEC;.</p>
<h2 id="headlessbrowserlg">Headless Browser L&#xE0; G&#xEC;?</h2>
<p>Headless Browser l&#xE0; m&#x1ED9;t tr&#xEC;nh duy&#x1EC7;t web kh&#xF4;ng c&#xF3; giao di&#x1EC7;n ng&#x1B0;&#x1EDD;i d&#xF9;ng. C&#xE1;c headless browser cung c&#x1EA5;p t&#x1B0;&#x1A1;ng t&#xE1;c t&#x1EF1; &#x111;&#x1ED9;ng m&#x1ED9;t trang web trong m&#x1ED9;t m&#xF4;i tr&#x1B0;&#x1EDD;ng gi&#x1ED1;ng nh&#x1B0; c&#xE1;c tr&#xEC;nh duy&#x1EC7;t web ph&#x1ED5; bi&#x1EBF;n kh&#xE1;c, nh&#x1B0;ng n&#xF3; &#x111;&#x1B0;&#x1EE3;c th&#x1EF1;c hi&#x1EC7;n th&#xF4;ng qua giao di&#x1EC7;n d&#xF2;ng l&#x1EC7;nh ho&#x1EB7;c qua m&#x1ED9;t m&#x1EA1;ng truy&#x1EC1;n th&#xF4;ng. C&#xE1;c b&#x1EA1;n c&#xF3; th&#x1EC3; tham kh&#x1EA3;o th&#xEA;m <a href="https://en.wikipedia.org/wiki/Headless_browser">t&#x1EA1;i &#x111;&#xE2;y</a>.<br>
&#x1EDE; &#x111;&#xE2;y m&#xEC;nh c&#xF3; t&#xF3;m g&#x1ECD;n l&#x1EA1;i m&#x1ED9;t c&#xE2;u &#x111;&#x1A1;n gi&#x1EA3;n l&#xE0; headless Browser thay v&#xEC; d&#xF9;ng &#x111;&#x1EC3; duy&#x1EC7;t web th&#xEC; n&#xF3; s&#x1EED; d&#x1EE5;ng &#x111;&#x1EC3; c&#xE0;o d&#x1EEF; li&#x1EC7;u, ch&#x1EE5;p &#x1EA3;nh m&#xE0;n h&#xEC;nh c&#x1EE7;a c&#xE1;c trang web,...</p>
<h2 id="puppeteerlg">Puppeteer L&#xE0; G&#xEC;?</h2>
<p>Puppeteer l&#xE0; th&#x1B0; vi&#x1EC7;n c&#x1EE7;a NodeJS, gi&#xFA;p b&#x1EA1;n &#x111;i&#x1EC1;u khi&#x1EC3;n headless Chrome. C&#xE1;c b&#x1EA1;n t&#xEC;m hi&#x1EC3;u th&#xEA;m <a href="https://github.com/puppeteer/puppeteer">t&#x1EA1;i &#x111;&#xE2;y nha</a></p>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1584285751/puppeteer-pyramid-architecture-nodejs-chrome-edge_hmbxzh.png" width="700" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n Crawl D&#x1EEF; Li&#x1EC7;u V&#x1EDB;i Puppeteer V&#xE0; Nodejs">
<h1 id="btulmthino">B&#x1EAF;t &#x110;&#x1EA7;u L&#xE0;m Th&#xF4;i N&#xE0;o</h1>
<h2 id="lntng">L&#xEA;n &#xDD; T&#x1B0;&#x1EDF;ng</h2>
<p>&#xDD; t&#x1B0;&#x1EDF;ng th&#xEC; m&#xEC;nh s&#x1EBD; crawl d&#x1EEF; li&#x1EC7;u trang linh ki&#x1EC7;n &#x111;i&#x1EC7;n t&#x1EED; <a href="https://nshopvn.com/">Nshop</a>. V&#x1EAD;y m&#xEC;nh s&#x1EBD; crawl c&#xE1;i g&#xEC; t&#x1EEB; trang n&#xE0;y, m&#xEC;nh s&#x1EBD; crawl t&#x1EA5;t c&#xE1;c url &#x1EA3;nh, ti&#xEA;u &#x111;&#x1EC1; v&#xE0; gi&#xE1; c&#x1EE7;a t&#x1EEB;ng s&#x1EA3;n ph&#x1EA9;m trong trang ch&#x1EE7; c&#x1EE7;a website. Trang ch&#x1EE7; c&#x1EE7;a th&#x1EB1;ng n&#xE0;y n&#xF3; c&#xF3; 60 s&#x1EA3;n ph&#x1EA9;m th&#xEC; m&#xEC;nh s&#x1EBD; crawl 60 url &#x1EA3;nh, ti&#xEA;u &#x111;&#x1EC1; v&#xE0; price. Crawl nh&#x1B0; th&#x1EBF; n&#xE0;o th&#xEC; c&#xE1;c b&#x1EA1;n xem ti&#x1EBF;p &#x1EDF; ph&#x1EA7;n d&#x1B0;&#x1EDB;i nha.</p>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1584324545/Untitled_vhtem5.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n Crawl D&#x1EEF; Li&#x1EC7;u V&#x1EDB;i Puppeteer V&#xE0; Nodejs">
<h2 id="citvthitlp">C&#xE0;i &#x110;&#x1EB7;t V&#xE0; Thi&#x1EBF;t L&#x1EAD;p</h2>
<p>Tr&#x1B0;&#x1EDB;c ti&#xEA;n c&#xE1;c b&#x1EA1;n t&#x1EA1;o cho m&#xEC;nh m&#x1ED9;t folder trong folder &#x111;&#xF3; l&#xE0; n&#x1A1;i ch&#x1EE9;a c&#xE1;c th&#x1B0; m&#x1EE5;c d&#xF9;ng &#x111;&#x1EC3; crawl d&#x1EEF; li&#x1EC7;u.<br>
<strong>Kh&#x1EDF;i t&#x1EA1;o &#x1EE9;ng d&#x1EE5;ng v&#x1EDB;i file package.json</strong><br>
Trong th&#x1B0; m&#x1EE5;c g&#x1ED1;c c&#x1EE7;a &#x1EE9;ng d&#x1EE5;ng c&#x1EE7;a b&#x1EA1;n v&#xE0; nh&#x1EAD;p <code>npm init</code> &#x111;&#x1EC3; kh&#x1EDF;i t&#x1EA1;o &#x1EE9;ng d&#x1EE5;ng c&#x1EE7;a b&#x1EA1;n v&#x1EDB;i t&#x1EC7;p <strong>package.json</strong>.<br>
<code>npm init</code><br>
Sau &#x111;&#xF3; c&#xE1;c b&#x1EA1;n c&#xE0;i &#x111;&#x1EB7;t module puppeteer &#x111;&#x1EC3; crawl d&#x1EEF; li&#x1EC7;u nha.<br>
&#x110;&#x1EC3; m&#xE0; c&#xE0;i &#x111;&#x1EB7;t puppeteer tr&#x1B0;&#x1EDB;c h&#x1EBF;t c&#xE1;c b&#x1EA1;n ph&#x1EA3;i c&#xE0;i &#x111;&#x1EB7;t NodeJS <a href="https://nodejs.org/en/download/">t&#x1EA1;i &#x111;&#xE2;y</a>.<br>
<code> npm install puppeteer</code><br>
Sau khi c&#xE0;i &#x111;&#x1EB7;t module xong c&#xE1;c b&#x1EA1;n t&#x1EA1;o cho m&#xEC;nh file <code>index.js</code> &#x111;&#x1EC3; m&#xEC;nh vi&#x1EBF;t ch&#x1B0;&#x1A1;ng tr&#xEC;nh crawl d&#x1EEF; li&#x1EC7;u.</p>
<h2 id="btucodethino">B&#x1EAF;t &#x110;&#x1EA7;u Code Th&#xF4;i N&#xE0;o</h2>
<p>Trong file <code>index.js</code> c&#xE1;c b&#x1EA1;n require th&#x1B0; vi&#x1EC7;n v&#xE0;o nha:</p>
<pre><code>const puppeteer = require(&apos;puppeteer&apos;);
</code></pre>
<p>Ti&#x1EBF;p &#x111;&#x1EBF;n, ch&#xFA;ng ta s&#x1EBD; kh&#x1EDF;i t&#x1EA1;o m&#x1ED9;t browser s&#x1EED; d&#x1EE5;ng ph&#x1B0;&#x1A1;ng th&#x1EE9;c <strong>launch()</strong> v&#xE0; truy c&#x1EAD;p v&#xE0;o trang linh ki&#x1EC7;n &#x111;i&#x1EC7;n t&#x1EED; <a href="https://nshopvn.com/">Nshop</a> nh&#x1B0; sau:</p>
<pre><code>const puppeteer = require(&apos;puppeteer&apos;);

let electronicUrl = &apos;https://nshopvn.com/&apos;;
(async () =&gt; {
  const browser = await puppeteer.launch({ headless: true });
  const page = await browser.newPage();
  await page.goto(electronicUrl);
  .........
  .........
  .........
})();
</code></pre>
<p>&#x110;&#x1EC3; c&#xF3; th&#x1EC3; crawl d&#x1EEF; li&#x1EC7;u c&#x1EE7;a trang web c&#xE1;c b&#x1EA1;n c&#x1EA7;n g&#x1ECD;i &#x111;&#x1EBF;n API <strong>page.evaluate</strong>. L&#xE0; m&#x1ED9;t API r&#x1EA5;t quan tr&#x1ECD;ng cho ph&#xE9;p ch&#xFA;ng ta ch&#x1EA1;y script &#x111;&#x1EC3; l&#x1EA5;y n&#x1ED9;i dung tr&#x1EA3; v&#x1EC1;.<br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1584366333/KFBvX_sivhca.png" width="700" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n Crawl D&#x1EEF; Li&#x1EC7;u V&#x1EDB;i Puppeteer V&#xE0; Nodejs"></p>
<p>B&#xE2;y gi&#x1EDD; c&#xE1;c b&#x1EA1;n qua trang <a href="https://nshopvn.com/">Nshop</a> &#x111;&#x1EC3; xem c&#x1EA5;u tr&#xFA;c HTML c&#x1EE7;a n&#xF3; nh&#x1B0; th&#x1EBF; n&#xE0;o nha. &#x110;&#x1EC3; c&#xF3; th&#x1EC3; l&#x1EA5;y url &#x1EA3;nh, ti&#xEA;u &#x111;&#x1EC1; v&#xE0; gi&#xE1; c&#x1EE7;a t&#x1EEB;ng s&#x1EA3;n ph&#x1EA9;m.<br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1584371155/Untitled_yllh7w.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n Crawl D&#x1EEF; Li&#x1EC7;u V&#x1EDB;i Puppeteer V&#xE0; Nodejs"></p>
<p>Nh&#x1B0; c&#xE1;c b&#x1EA1;n &#x111;&#xE3; th&#x1EA5;y tr&#xEA;n &#x1EA3;nh th&#xEC; th&#x1EB1;ng class=&quot;product-wrapper&quot; n&#xF3; l&#xE0; class cha bao b&#x1ECD;c t&#x1EA5;t c&#x1EA3; c&#xE1;c n&#x1ED9;i dung nh&#x1B0;: url &#x1EA3;nh, ti&#xEA;u &#x111;&#x1EC1; v&#xE0; gi&#xE1;.<br>
B&#xE2;y gi&#x1EDD; c&#xE1;c b&#x1EA1;n m&#x1EDF; tab console trong chrome dev tools &#x111;&#x1EC3; c&#xF3; th&#x1EC3; c&#xE0;o d&#x1EEF; li&#x1EC7;u b&#x1EB1;ng c&#xE1;ch vi&#x1EBF;t code JavaScript</p>
<pre><code>let products = []; // t&#x1EA1;o m&#x1ED9;t array &#x111;&#x1EC3; c&#xF3; th&#x1EC3; push d&#x1EEF; li&#x1EC7;u c&#x1EE7;a t&#x1EEB;ng s&#x1EA3;n ph&#x1EA9;m v&#xE0;o
    let product_wrapper = document.querySelectorAll(&apos;.product-wrapper&apos;);
    
    // L&#x1EB7;p qua c&#xE1;c NodeList &#x111;&#x1EC3; c&#xF3; th&#x1EC3; l&#x1EA5;y d&#x1EEF; li&#x1EC7;u v&#xE0; chuy&#x1EC3;n th&#xE0;nh object
    product_wrapper.forEach((product) =&gt; {
      let dataJson = {};
      try {
        dataJson.img = product.querySelector(&apos;.image &gt; img&apos;).src;
        dataJson.title = product.querySelector(&apos;.woocommerce-loop-product__title&apos;).innerText;
        dataJson.price = product.querySelector(&apos;.price&apos;).innerText;
      }
      catch (err) {
          console.log(err)
      }
      products.push(dataJson);// Push d&#x1EEF; li&#x1EC7;u object v&#xE0;o trong array
    });
    console.log(products);
</code></pre>
<p><strong>V&#xE0; &#x111;&#xE2;y l&#xE0; k&#x1EBF;t qu&#x1EA3; khi ch&#xFA;ng ta test trong console:</strong><br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1584372821/Untitled_y1zfxg.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n Crawl D&#x1EEF; Li&#x1EC7;u V&#x1EDB;i Puppeteer V&#xE0; Nodejs"></p>
<p>Sau khi test ok ch&#xFA;ng ta v&#xE0;o file index.js v&#xE0; &#x111;&#xE2;y l&#xE0; code ho&#xE0;n ch&#x1EC9;nh:</p>
<pre><code>const puppeteer = require(&apos;puppeteer&apos;);

let electronicUrl = &apos;https://nshopvn.com/&apos;;
(async () =&gt; {
  const browser = await puppeteer.launch({ headless: true });
  const page = await browser.newPage();
  await page.goto(electronicUrl);

  let electronicData = await page.evaluate(() =&gt; {
    let products = [];
    let product_wrapper = document.querySelectorAll(&apos;.product-wrapper&apos;);
    product_wrapper.forEach((product) =&gt; {
      let dataJson = {};
      try {
        dataJson.img = product.querySelector(&apos;.image &gt; img&apos;).src;
        dataJson.title = product.querySelector(&apos;.woocommerce-loop-product__title&apos;).innerText;
        dataJson.price = product.querySelector(&apos;.price&apos;).innerText;
      }
      catch (err) {
          console.log(err)
      }
      products.push(dataJson);
    });
    return products;
  });

   console.log(electronicData);
    await browser.close();
})();

</code></pre>
<p>Ti&#x1EBF;p &#x111;&#x1EBF;n c&#xE1;c b&#x1EA1;n m&#x1EDF; terminal trong VScode ho&#x1EB7;c trong c&#x1EED;a s&#x1ED5; cmd c&#xE1;c b&#x1EA1;n g&#xF5; cho m&#xEC;nh <strong>node index.js</strong>. V&#xE0; &#x111;&#x1EC3; xem n&#xF3; crawl d&#x1EEF; li&#x1EC7;u nh&#x1B0; th&#x1EBF; n&#xE0;o nha.<br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1584373725/Untitled_ypcv6s.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n Crawl D&#x1EEF; Li&#x1EC7;u V&#x1EDB;i Puppeteer V&#xE0; Nodejs"></p>
<p>V&#x1EAD;y l&#xE0; xong r&#x1ED3;i nha, c&#xE1;c b&#x1EA1;n c&#xF3; th&#x1EC3; tham kh&#x1EA3;o code m&#xE0; m&#xEC;nh &#x111;&#xE3; push l&#xEA;n github <a href="https://github.com/long1211/Crawl-data-with-puppeteer">t&#x1EA1;i &#x111;&#xE2;y nha</a></p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h1 id="likt">L&#x1EDD;i K&#x1EBF;t</h1>
<p>V&#x1EAD;y L&#xE0; Xong b&#xE0;i H&#x1B0;&#x1EDB;ng D&#x1EAB;n Crawl D&#x1EEF; Li&#x1EC7;u V&#x1EDB;i Puppeteer V&#xE0; Nodejs r&#x1ED3;i nh&#xE9;. M&#xEC;nh mong mu&#x1ED1;n sau b&#xE0;i topic n&#xE0;y c&#xE1;c b&#x1EA1;n c&#xF3; th&#x1EC3; bi&#x1EBF;t v&#xE0; hi&#x1EC3;u th&#xEA;m v&#x1EC1; puppeteer, t&#x1EEB; topic n&#xE0;y c&#xE1;c b&#x1EA1;n c&#xF3; th&#x1EC3; m&#x1EDF; r&#x1ED9;ng th&#xEA;m &#xFD; t&#x1B0;&#x1EDF;ng m&#x1EDB;i. V&#xE0; c&#xF3; th&#x1EC3; t&#x1EF1; tay m&#xEC;nh l&#xE0;m nh&#x1EEF;ng project kh&#xF4;ng c&#x1EA7;n ph&#x1EA3;i qu&#xE1; &#x111;&#x1EB7;c bi&#x1EC7;t nh&#x1B0;ng n&#xF3; do ch&#xED;nh b&#x1EA1;n l&#xE0;m th&#xEC; c&#x169;ng coi nh&#x1B0; l&#xE0; th&#xE0;nh qu&#x1EA3; trong qu&#xE1; tr&#xEC;nh b&#x1EA1;n h&#x1ECD;c &#x111;&#x1B0;&#x1EE3;c.</p>
<p><strong>N&#x1EBF;u c&#xE1;c b&#x1EA1;n c&#x1EA3;m th&#x1EA5;y b&#xE0;i vi&#x1EBF;t c&#x1EE7;a m&#xEC;nh hay th&#xEC; c&#xE1;c b&#x1EA1;n c&#xF3; th&#x1EC3; &#x1EE7;ng h&#x1ED9; m&#xEC;nh &#x111;&#x1EC3; m&#xEC;nh c&#xF3; th&#xEA;m &#x111;&#x1ED9;ng l&#x1EF1;c &#x111;&#x1EC3; ra nh&#x1EEF;ng b&#xE0;i topic hay v&#xE0; ch&#x1EA5;t l&#x1B0;&#x1EE3;ng h&#x1A1;n &#x1EE7;ng h&#x1ED9; m&#xEC;nh <a href="https://vrdonate.vn/thanhlongdev">t&#x1EA1;i &#x111;&#xE2;y nha.</a></strong></p>
<p><em><strong>Ch&#xFA;c C&#xE1;c B&#x1EA1;n Th&#xE0;nh C&#xF4;ng!!</strong></em></p>
<!--kg-card-end: markdown--><!--kg-card-begin: html--><iframe src="https://www.facebook.com/plugins/like.php?href=https%3A%2F%2Fwww.thanhlongdev.com%2Fhuong-dan-crawl-du-lieu-bang-puppeteer%2F&amp;width=450&amp;layout=standard&amp;action=like&amp;size=large&amp;share=true&amp;height=35&amp;appId=2794898430534168" width="450" height="35" style="border:none;overflow:hidden" scrolling="no" frameborder="0" allowtransparency="true" allow="encrypted-media"></iframe><!--kg-card-end: html--><!--kg-card-begin: html--><div class="fb-comments" data-href="https://www.thanhlongdev.com/huong-dan-crawl-du-lieu-bang-puppeteer/" data-width="100%" data-numposts="10"></div><!--kg-card-end: html-->]]></content:encoded></item><item><title><![CDATA[Hướng Dẫn Xây Dựng Tabs Với HTML, CSS và Javascript]]></title><description><![CDATA[<!--kg-card-begin: markdown--><h1 id="giithiuchung">Gi&#x1EDB;i Thi&#x1EC7;u Chung</h1>
<p>H&#xF4;m nay m&#xEC;nh s&#x1EBD; h&#x1B0;&#x1EDB;ng d&#x1EAB;n c&#xE1;c b&#x1EA1;n x&#xE2;y d&#x1EF1;ng m&#x1ED9;t c&#xE1;i ch&#x1EE9;c n&#x103;ng r&#x1EA5;t</p>]]></description><link>https://www.thanhlongdev.com/huong-dan-xay-dung-tabs-voi-html-css-javascript/</link><guid isPermaLink="false">5e5361d9c4d07d00017a048e</guid><category><![CDATA[Lập Trình Web]]></category><category><![CDATA[Vừa Code Vừa Xàm]]></category><dc:creator><![CDATA[Đặng Thanh Long]]></dc:creator><pubDate>Tue, 25 Feb 2020 03:07:30 GMT</pubDate><media:content url="https://digitalpress.fra1.cdn.digitaloceanspaces.com/4tg23ij/2020/03/tab-design-hover-movement.gif" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h1 id="giithiuchung">Gi&#x1EDB;i Thi&#x1EC7;u Chung</h1>
<img src="https://digitalpress.fra1.cdn.digitaloceanspaces.com/4tg23ij/2020/03/tab-design-hover-movement.gif" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Tabs V&#x1EDB;i HTML, CSS v&#xE0; Javascript"><p>H&#xF4;m nay m&#xEC;nh s&#x1EBD; h&#x1B0;&#x1EDB;ng d&#x1EAB;n c&#xE1;c b&#x1EA1;n x&#xE2;y d&#x1EF1;ng m&#x1ED9;t c&#xE1;i ch&#x1EE9;c n&#x103;ng r&#x1EA5;t ph&#x1ED5; bi&#x1EBF;n hi&#x1EC7;n nay trong c&#xE1;c trang web &#x111;&#xF3; l&#xE0; tabs.</p>
<h3 id="tisaomnhlihngdnccbnxydngtabs">T&#x1EA1;i Sao M&#xEC;nh L&#x1EA1;i H&#x1B0;&#x1EDB;ng D&#x1EAB;n C&#xE1;c B&#x1EA1;n X&#xE2;y D&#x1EF1;ng Tabs</h3>
<p>Th&#xEC; c&#xE1;c b&#x1EA1;n th&#x1EED; search tr&#xEA;n google c&#xF3; r&#x1EA5;t nhi&#x1EC1;u b&#xE0;i vi&#x1EBF;t h&#x1B0;&#x1EDB;ng d&#x1EAB;n c&#xE1;c b&#x1EA1;n l&#xE0;m tabs, c&#xE1;c plugin nh&#x1B0; bootstrap tabs,.. Nh&#x1B0;ng m&#xE0; m&#xEC;nh v&#x1EAB;n mu&#x1ED1;n vi&#x1EBF;t b&#xE0;i &#x111;&#x1EC3; h&#x1B0;&#x1EDB;ng d&#x1EAB;n c&#xE1;c b&#x1EA1;n. <strong>V&#x1EAD;y m&#x1EE5;c &#x111;&#xED;ch c&#x1EE7;a m&#xEC;nh l&#xE0; g&#xEC;?</strong></p>
<h1 id="mcchbivit">M&#x1EE5;c &#x110;&#xED;ch B&#xE0;i Vi&#x1EBF;t</h1>
<p>M&#x1EE5;c &#x111;&#xED;ch c&#x1EE7;a b&#xE0;i vi&#x1EBF;t n&#xE0;y gi&#xFA;p c&#xE1;c b&#x1EA1;n &#xF4;n l&#x1EA1;i c&#xE1;c ki&#x1EBF;n th&#x1EE9;c v&#x1EC1; html, css v&#xE0; js. Kh&#xF4;ng ph&#x1EE5; thu&#x1ED9;c qu&#xE1; nhi&#x1EC1;u v&#xE0;o c&#xE1;c th&#x1B0; vi&#x1EC7;n gi&#xFA;p c&#xE1;c b&#x1EA1;n n&#xE2;ng cao kh&#x1EA3; n&#x103;ng t&#x1B0; duy, logic v&#xE0; kh&#x1EA3; n&#x103;ng gi&#x1EA3;i quy&#x1EBF;t v&#x1EA5;n &#x111;&#x1EC1;.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h1 id="btuthino">B&#x1EAF;t &#x110;&#x1EA7;u Th&#xF4;i N&#xE0;o</h1>
<h2 id="lntng">L&#xEA;n &#xDD; T&#x1B0;&#x1EDF;ng</h2>
<p>Th&#xEC; th&#x1EB1;ng tabs n&#xE0;y n&#xF3; sinh ra d&#xF9;ng &#x111;&#x1EC3; hi&#x1EC3;n th&#x1ECB; c&#xE1;c th&#x1EC3; lo&#x1EA1;i kh&#xE1;c nhau theo t&#x1EEB;ng tabs kh&#xE1;c nha. Ch&#xFA;ng ta s&#x1EED; d&#x1EE5;ng html, css &#x111;&#x1EC3; l&#xE0;m layout v&#xE0; d&#xF9;ng JS &#x111;&#x1EC3; l&#xE0;m hi&#x1EC3;u &#x1EE9;ng chuy&#x1EC3;n tabs.<br>
V&#xED; d&#x1EE5; nh&#x1B0; website linh ki&#x1EC7;n &#x111;i&#x1EC7;n t&#x1EED; 3M trong ph&#x1EA7;n <strong>s&#x1EA3;n ph&#x1EA9;m n&#x1ED5;i b&#x1EAD;t</strong> n&#xF3; c&#x169;ng chia ra l&#xE0;m ba tabs kh&#xE1;c nha.<br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1582541653/Untitled_wav4do.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Tabs V&#x1EDB;i HTML, CSS v&#xE0; Javascript"></p>
<h2 id="codethino">Code Th&#xF4;i N&#xE0;o</h2>
<h3 id="codehtml">Code HTML</h3>
<p>Tr&#x1B0;&#x1EDB;c ti&#xEA;n c&#xE1;c b&#x1EA1;n c&#x1EA7;n ph&#x1EA3;i code cho m&#xEC;nh m&#x1ED9;t b&#x1ED9; khung c&#x1EA7;n c&#xF3; &#x111;&#x1EC3; t&#x1EA1;o tabs cho n&#xF3;. Trong tabs &#x111;&#xF3; c&#xF3; hai ph&#x1EA7;n ch&#xED;nh l&#xE0; tab links v&#xE0; tab content.<br>
Trong tab links c&#xE1;c b&#x1EA1;n t&#x1EA1;o cho m&#xEC;nh c&#xE1;c button trong button n&#xE0;y ch&#x1EE9;a c&#xE1;c data- attributes. &#x111;&#x1EC3; c&#xF3; th&#x1EC3; truy v&#x1EA5;n v&#xE0;o &#x111;&#x1B0;&#x1EE3;c c&#xE1;c tab content m&#x1EE5;c &#x111;&#xED;ch l&#xE0; s&#x1EED; d&#x1EE5;ng tab links &#x111;&#x1EC3; chuy&#x1EC3;n c&#xE1;c tabs.<br>
Ti&#x1EBF;p theo l&#xE0; trong tab content c&#xE1;c b&#x1EA1;n cho m&#xEC;nh m&#x1ED7;i content m&#x1ED9;t id kh&#xE1;c nhau nh&#x1B0;ng ph&#x1EA3;i gi&#x1ED1;ng c&#xE1;c gi&#xE1; tr&#x1ECB; trong data-attributes. C&#xF2;n n&#x1ED9;i dung nh&#x1B0; th&#x1EBF; n&#xE0;o th&#xEC; b&#x1EA1;n c&#xF3; th&#x1EC3; t&#x1EF1; custom theo &#xFD; mu&#x1ED1;n.<br>
C&#xE1;c b&#x1EA1;n &#x111;&#x1EC3; &#xFD; trong button &#x111;&#x1EA7;u ti&#xEA;n c&#x1EE7;a tab links ch&#xFA;ng ta s&#x1EBD; th&#x1EA5;y th&#xEA;m m&#x1ED9;t class n&#x1EEF;a &#x111;&#xF3; l&#xE0; active, v&#x1EAD;y class active &#x111;&#xF3; d&#xF9;ng &#x111;&#x1EC3; l&#xE0;m g&#xEC; v&#x1EAD;y th&#xEC; ch&#xFA;ng ta c&#xF9;ng xem &#x1EDF; ph&#x1EA7;n css nha. C&#x169;ng t&#x1B0;&#x1A1;ng t&#x1EF1; nh&#x1B0; trong ph&#x1EA7;n tab content.</p>
<pre><code> &lt;!-- Tab links --&gt;
      &lt;div class=&quot;tabs&quot;&gt;
         &lt;button class=&quot;tablinks active&quot; data-electronic=&quot;allproducts&quot;&gt;T&#x1EA5;t c&#x1EA3; s&#x1EA3;n ph&#x1EA9;m&lt;/button&gt;
         &lt;button class=&quot;tablinks&quot; data-electronic=&quot;Microcontrollers&quot;&gt;Vi &#x111;i&#x1EC1;u khi&#x1EC3;n - Nh&#xFA;ng&lt;/button&gt;
         &lt;button class=&quot;tablinks&quot; data-electronic=&quot;module&quot;&gt;Module &#x1EE9;ng d&#x1EE5;ng&lt;/button&gt;
      &lt;/div&gt;

      &lt;!-- Tab content --&gt;
      &lt;div class=&quot;wrapper_tabcontent&quot;&gt;
         &lt;div id=&quot;allproducts&quot; class=&quot;tabcontent active&quot;&gt;
           &lt;img src=&quot;https://bizweb.dktcdn.net/thumb/large/100/228/168/products/sp1-949f885f-8d8a-445e-be5c-0cce06cdb4b1.jpg?v=1582441789000&quot; width=&quot;100%&quot;/&gt;
           &lt;h3&gt;Combo Tr&#x1EA1;m H&#xE0;n Hakko 936 + Sensor H&#xE0;n A1321&lt;/h3&gt;
         &lt;/div&gt;

         &lt;div id=&quot;Microcontrollers&quot; class=&quot;tabcontent&quot;&gt;
                &lt;img src=&quot;https://bizweb.dktcdn.net/thumb/large/100/228/168/products/raspberry-pi-4-model-b.jpg?v=1566526980000&quot; width=&quot;100%&quot;/&gt;
           &lt;h3&gt;Raspberry Pi 4 Model B 2019&lt;/h3&gt;
         &lt;/div&gt;

         &lt;div id=&quot;module&quot; class=&quot;tabcontent&quot;&gt;
           &lt;img src=&quot;//bizweb.dktcdn.net/thumb/large/100/228/168/products/sp1-96b83938-650f-4f51-8b0a-61ee9f8f9039.jpg?v=1580721383000&quot; width=&quot;100%&quot;/&gt;
           &lt;h3&gt;Module Khu&#x1EBF;ch &#x110;&#x1EA1;i &#xC2;m Thanh Bluetooth Stereo 30W/40W C&#xF4;ng Su&#x1EA5;t Cao XY-P40W&lt;/h3&gt;
         &lt;/div&gt;
      &lt;/div&gt;
</code></pre>
<p><em><strong>l&#x1B0;u &#xFD;</strong></em>: M&#xEC;nh s&#x1EED; d&#x1EE5;ng codepen.io &#x111;&#x1EC3; code t&#x1EA1;o tabs, c&#xE1;c b&#x1EA1;n c&#x169;ng c&#xF3; th&#x1EC3; s&#x1EED; d&#x1EE5;ng c&#xE1;c text editor hay IDE kh&#xE1;c &#x111;&#x1EC3; code t&#x1EA1;o tabs nha.<br>
<strong>C&#xE1;c b&#x1EA1;n c&#xF9;ng xem th&#x1EED; k&#x1EBF;t qu&#x1EA3; khi ch&#xFA;ng ta code HTML cho n&#xF3; nha.</strong><br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1582556115/html_fazwnx.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Tabs V&#x1EDB;i HTML, CSS v&#xE0; Javascript"></p>
<h3 id="codecss">Code CSS</h3>
<p>&#x110;&#x1EC3; m&#xE0; tabs ch&#xFA;ng ta d&#x1EC5; nh&#xEC;n h&#x1A1;n, b&#x1ED1; c&#x1EE5;c &#x111;&#x1EB9;p m&#x1EAF;t h&#x1A1;n th&#xEC; ch&#xFA;ng ta c&#x1EA7;n ph&#x1EA3;i css cho n&#xF3;. Trong ph&#x1EA7;n CSS n&#xE0;y m&#xEC;nh kh&#xF4;ng n&#xF3;i nhi&#x1EC1;u cho l&#x1EAF;m b&#x1EDF;i v&#xEC; &#x111;&#xE2;y ho&#xE0;n to&#xE0;n l&#xE0; c&#xE1;c ki&#x1EBF;n th&#x1EE9;c c&#x1A1; b&#x1EA3;n.<br>
Trong n&#xE0;y c&#xE1;c b&#x1EA1;n css cho m&#xEC;nh hai .active &#x111;&#xF3; l&#xE0; <code>.tablinks.active</code> v&#xE0; <code>.tabcontent.active</code> m&#x1ED9;t c&#xE1;i l&#xE0; d&#xF9;ng &#x111;&#x1EC3; hi&#x1EC3;n th&#x1ECB; m&#xE0;u n&#x1EC1;n, m&#xE0;u ch&#x1EEF; c&#xE1;i c&#xF2;n l&#x1EA1;i d&#xF9;ng &#x111;&#x1EC3; hi&#x1EC3;n th&#x1ECB; n&#x1ED9;i dung c&#x1EE7;a tab m&#xE0; ch&#xFA;ng ta add class v&#xE0;o.</p>
<pre><code>/* Tab Links */
.tabs{
  display:flex;
}
.tablinks {
  border: none;
  outline: none;
  cursor: pointer;
  width: 100%;
  padding: 1rem;
  font-size: 13px;
  text-transform: uppercase;
  font-weight:600;
  transition: 0.2s ease;
}
.tablinks:hover{
  background:blue;
  color:#fff;
}
/* Tab active */
.tablinks.active {
   background:blue;
  color:#fff;
}

/* tab content */
.tabcontent {
  display: none;
}
/* Text*/
.tabcontent p {
  color: #333;
  font-size: 16px;
}
/* tab content active */
.tabcontent.active {
  display: block;
}
</code></pre>
<p><strong>C&#xE1;c b&#x1EA1;n c&#xF9;ng xem th&#x1EED; k&#x1EBF;t qu&#x1EA3; khi ch&#xFA;ng ta code CSS cho n&#xF3; nha.</strong><br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1582556524/css_bcknum.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Tabs V&#x1EDB;i HTML, CSS v&#xE0; Javascript"></p>
<p>Cu&#x1ED1;i c&#xF9;ng th&#xEC; c&#xF4;ng vi&#x1EC7;c chia layout c&#x169;ng nh&#x1B0; giao di&#x1EC7;n cho tabs ch&#xFA;ng ta c&#x169;ng &#x111;&#xE3; l&#xE0;m xong m&#x1ED9;t c&#xE1;ch c&#x169;ng kh&#xE1; l&#xE0; &#x1ED5;n gi&#x1EDD; &#x111;&#x1EBF;n c&#xF4;ng &#x111;o&#x1EA1;n l&#xE0;m hi&#x1EC7;u &#x1EE9;ng chuy&#x1EC3;n tabs.</p>
<h3 id="codejavascript">Code Javascript</h3>
<p>&#x110;&#xE2;y l&#xE0; ph&#x1EA7;n kh&#xE1; l&#xE0; quan tr&#x1ECD;ng trong b&#xE0;i vi&#x1EBF;t ng&#xE0;y h&#xF4;m. Tuy n&#xF3; kh&#xE1; quan tr&#x1ECD;ng nh&#x1B0;ng n&#xF3; c&#x169;ng kh&#xF4;ng qu&#xE1; kh&#xF3; l&#x1EAF;m &#x111;&#xE2;u.<br>
Tr&#x1B0;&#x1EDB;c ti&#xEA;n m&#xEC;nh s&#x1EBD; n&#xF3;i s&#x1A1; qua thu&#x1EAD;t to&#xE1;n t&#xED; l&#xE0;m sao &#x111;&#x1EC3; ch&#xFA;ng ta c&#xF3; th&#x1EC3; chuy&#x1EC3;n tabs. Th&#xEC; trong tabs link ch&#xFA;ng ta c&#xF3; ba button th&#xEC; khi click button th&#x1EE9; hai th&#xEC; n&#x1ED9;i dung trong th&#x1EBB; th&#x1EE9; hai ph&#x1EA3;i &#x111;&#x1B0;&#x1EE3;c hi&#x1EC3;n th&#x1ECB; v&#xE0; c&#x169;ng t&#x1B0;&#x1A1;ng t&#x1EF1; nh&#x1B0; n&#x1ED9;i dung trong  th&#x1EBB; button th&#x1EE9; ba v&#xE0; th&#x1EE9; nh&#x1EA5;t. V&#xE0; c&#xE1;c th&#x1EBB; m&#xE0; &#x111;&#x1B0;&#x1EE3;c add .active khi click v&#xE0;o button kh&#xE1;c th&#xEC; ph&#x1EA3;i &#x111;&#x1B0;&#x1EE3;c remove.<br>
V&#xEC; v&#x1EAD;y n&#xEA;n ch&#xFA;ng ta m&#x1EDB;i s&#x1EED; d&#x1EE5;ng data-attribute v&#xE0; id &#x111;&#x1EC3; c&#xF3; th&#x1EC3; l&#x1EA5;y &#x111;&#x1B0;&#x1EE3;c n&#x1ED9;i dung c&#x1EE7;a t&#x1EEB;ng tab kh&#xE1;c nhau.</p>
<pre><code>var tabLinks = document.querySelectorAll(&quot;.tablinks&quot;);
var tabContent =document.querySelectorAll(&quot;.tabcontent&quot;);

tabLinks.forEach(function(el) {
   el.addEventListener(&quot;click&quot;, openTabs);
});


function openTabs(el) {
   var btn = el.currentTarget; // l&#x1EAF;ng nghe s&#x1EF1; ki&#x1EC7;n v&#xE0; hi&#x1EC3;n th&#x1ECB; c&#xE1;c element
   var electronic = btn.dataset.electronic; // l&#x1EA5;y gi&#xE1; tr&#x1ECB; trong data-electronic
 
   tabContent.forEach(function(el) {
      el.classList.remove(&quot;active&quot;);
   }); //l&#x1EB7;p qua c&#xE1;c tab content &#x111;&#x1EC3; remove class active

   tabLinks.forEach(function(el) {
      el.classList.remove(&quot;active&quot;);
   }); //l&#x1EB7;p qua c&#xE1;c tab links &#x111;&#x1EC3; remove class active

   document.querySelector(&quot;#&quot; + electronic).classList.add(&quot;active&quot;);
   // tr&#x1EA3; v&#x1EC1; ph&#x1EA7;n t&#x1EED; &#x111;&#x1EA7;u ti&#xEA;n c&#xF3; id=&quot;&quot; &#x111;&#x1B0;&#x1EE3;c add class active
   
   btn.classList.add(&quot;active&quot;);
   // c&#xE1;c button m&#xE0; ch&#xFA;ng ta click v&#xE0;o s&#x1EBD; &#x111;&#x1B0;&#x1EE3;c add class active
}
</code></pre>
<p>Ch&#xFA;ng ta &#x111;&#x1EC3; &#xFD; th&#x1EA5;y hai d&#xF2;ng &#x111;&#x1EA7;u ti&#xEA;n t&#x1EA1;i sao m&#xEC;nh l&#x1EA1;i kh&#xF4;ng s&#x1EED; ph&#x1B0;&#x1A1;ng th&#x1EE9;c getElementsByClassName m&#xE0; l&#x1EA1;i s&#x1EED; d&#x1EE5;ng querySelectorAll th&#xEC; c&#xE2;u tr&#x1EA3; c&#x1EE7;a m&#xEC;nh th&#xEC; s&#x1EED; d&#x1EE5;ng c&#xE1;i n&#xE0;o c&#x169;ng &#x111;&#x1B0;&#x1EE3;c c&#x1EA3; n&#x1EBF;u &#x111;&#xF3; l&#xE0; class th&#xEC; getElementsByClassName.<br>
&#x110;&#x1EC3; c&#xF3; th&#x1EC3; chuy&#x1EC3;n tab ch&#xFA;ng ta c&#x1EA7;n ph&#x1EA3;i b&#x1EAF;t s&#x1EF1; ki&#x1EC7;n click &#x111;&#x1EC3; c&#xF3; th&#x1EC3; click v&#xE0;o c&#xE1;c button &#x111;&#x1EC3; chuy&#x1EC3;n tab. tham s&#x1ED1; el n&#xE0;y l&#xE0; t&#x1EEB; &#x111;&#x1B0;&#x1EE3;c vi&#x1EBF;t t&#x1EAF;t b&#x1EDF;i t&#x1EEB; element.</p>
<p>Th&#xEC; m&#x1EB7;c &#x111;&#x1ECB;nh tab links v&#xE0; tab content th&#x1B0; nh&#x1EA5;t s&#x1EBD; &#x111;&#x1B0;&#x1EE3;c add class s&#x1EB5;n. N&#xEA;n khi ch&#xFA;ng ta click v&#xE0;o tab links th&#x1EE9; hai th&#xEC; tab links, tab content s&#x1EBD; &#x111;&#x1B0;&#x1EE3;c ch&#x1EA1;y v&#xF2;ng l&#x1EB7;p n&#x1EBF;u th&#x1EB1;ng n&#xE0;o trong tab links hay tab content c&#xF3; add .active th&#xEC; s&#x1EBD; b&#x1ECB; remove. Khi remove xong th&#xEC; tab links v&#xE0; tab content th&#x1EE9; hai s&#x1EBD; &#x111;&#x1B0;&#x1EE3;c add .active</p>
<p><strong>Ch&#xFA;ng ta c&#xF9;ng xem th&#x1EED; n&#xF3; chuy&#x1EC3;n tab nh&#x1B0; th&#x1EBF; n&#xE0;o nh&#xE9;.</strong><br>
<img src="https://media.giphy.com/media/ehPDtBlIs43lDrWCe3/giphy.gif" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Tabs V&#x1EDB;i HTML, CSS v&#xE0; Javascript"></p>
<p><em><strong>C&#xE1;c b&#x1EA1;n c&#xF3; th&#x1EC3; tham kh&#x1EA3;o full source code m&#xEC;nh &#x111;&#xE3; code trong codepen <a href="https://codepen.io/long1211/pen/mdJOoeV?editors=1111">t&#x1EA1;i &#x111;&#xE2;y</a></strong></em></p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h1 id="likt">L&#x1EDD;i K&#x1EBF;t</h1>
<p>V&#x1EAD;y L&#xE0; Xong b&#xE0;i vi&#x1EBF;t H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Tabs V&#x1EDB;i HTML, CSS v&#xE0; Javascript r&#x1ED3;i nh&#xE9;. M&#xEC;nh mong mu&#x1ED1;n sau b&#xE0;i topic n&#xE0;y c&#xE1;c b&#x1EA1;n c&#xF3; th&#x1EC3; n&#x1EAF;m v&#x1EEF;ng th&#xEA;m v&#x1EC1; c&#xE1;c ki&#x1EBF;n th&#x1EE9;c HTML, CSS v&#xE0; JS... H&#x1ECD;c th&#xEA;m &#x111;&#x1B0;&#x1EE3;c nhi&#x1EC1;u ki&#x1EBF;n th&#x1EE9;c tuy kh&#xF4;ng m&#x1EDB;i l&#x1EAF;m nh&#x1B0;ng c&#x169;ng c&#xF3; th&#x1EC3; gi&#xFA;p &#x111;&#x1B0;&#x1EE3;c ph&#x1EA7;n n&#xE0;o &#x111;&#xF3; c&#x1EE7;a c&#xE1;c b&#x1EA1;n. C&#xF3; th&#x1EC3; t&#x1EF1; tay m&#xEC;nh l&#xE0;m nh&#x1EEF;ng project kh&#xF4;ng c&#x1EA7;n ph&#x1EA3;i qu&#xE1; &#x111;&#x1EB7;c bi&#x1EC7;t nh&#x1B0;ng n&#xF3; do ch&#xED;nh b&#x1EA1;n l&#xE0;m th&#xEC; c&#x169;ng coi nh&#x1B0; l&#xE0; th&#xE0;nh qu&#x1EA3; trong qu&#xE1; tr&#xEC;nh b&#x1EA1;n h&#x1ECD;c &#x111;&#x1B0;&#x1EE3;c.</p>
<p><strong>N&#x1EBF;u c&#xE1;c b&#x1EA1;n c&#x1EA3;m th&#x1EA5;y b&#xE0;i vi&#x1EBF;t c&#x1EE7;a m&#xEC;nh hay th&#xEC; c&#xE1;c b&#x1EA1;n c&#xF3; th&#x1EC3; &#x1EE7;ng h&#x1ED9; m&#xEC;nh &#x111;&#x1EC3; m&#xEC;nh c&#xF3; th&#xEA;m &#x111;&#x1ED9;ng l&#x1EF1;c &#x111;&#x1EC3; ra nh&#x1EEF;ng b&#xE0;i topic hay v&#xE0; ch&#x1EA5;t l&#x1B0;&#x1EE3;ng h&#x1A1;n &#x1EE7;ng h&#x1ED9; m&#xEC;nh <a href="https://vrdonate.vn/thanhlongdev">t&#x1EA1;i &#x111;&#xE2;y nha</a></strong></p>
<p><em><strong>Ch&#xFA;c C&#xE1;c B&#x1EA1;n Th&#xE0;nh C&#xF4;ng!!</strong></em></p>
<!--kg-card-end: markdown--><!--kg-card-begin: html--><iframe src="https://www.facebook.com/plugins/like.php?href=https%3A%2F%2Fwww.thanhlongdev.com%2Fhuong-dan-xay-dung-tabs-voi-html-css-javascript%2F&amp;width=450&amp;layout=standard&amp;action=like&amp;size=large&amp;share=true&amp;height=35&amp;appId=2794898430534168" width="450" height="35" style="border:none;overflow:hidden" scrolling="no" frameborder="0" allowtransparency="true" allow="encrypted-media"></iframe><!--kg-card-end: html--><!--kg-card-begin: html--><div class="fb-comments" data-href="https://www.thanhlongdev.com/huong-dan-xay-dung-tabs-voi-html-css-javascript/" data-width="100%" data-numposts="10"></div><!--kg-card-end: html-->]]></content:encoded></item><item><title><![CDATA[Hướng Dẫn Xây Dựng NodeJS API Xác Thực Với JWT]]></title><description><![CDATA[<!--kg-card-begin: markdown--><h1 id="giithiuchung">Gi&#x1EDB;i Thi&#x1EC7;u Chung</h1>
<p>H&#xF4;m nay m&#xEC;nh s&#x1EBD; h&#x1B0;&#x1EDB;ng d&#x1EAB;n c&#xE1;c b&#x1EA1;n x&#xE2;y d&#x1EF1;ng API x&#xE1;c th&#x1EF1;c v&#x1EDB;i nodejs, express v&#xE0; mongodb.</p>]]></description><link>https://www.thanhlongdev.com/huong-dan-xay-dung-nodejs-api-xac-thuc-voi-jwt/</link><guid isPermaLink="false">5e1532cf7c64520001bb0913</guid><category><![CDATA[Lập Trình Web]]></category><dc:creator><![CDATA[Đặng Thanh Long]]></dc:creator><pubDate>Mon, 17 Feb 2020 06:10:50 GMT</pubDate><media:content url="https://digitalpress.fra1.cdn.digitaloceanspaces.com/4tg23ij/2020/02/67f2ab00afa6.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h1 id="giithiuchung">Gi&#x1EDB;i Thi&#x1EC7;u Chung</h1>
<img src="https://digitalpress.fra1.cdn.digitaloceanspaces.com/4tg23ij/2020/02/67f2ab00afa6.jpg" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng NodeJS API X&#xE1;c Th&#x1EF1;c V&#x1EDB;i JWT"><p>H&#xF4;m nay m&#xEC;nh s&#x1EBD; h&#x1B0;&#x1EDB;ng d&#x1EAB;n c&#xE1;c b&#x1EA1;n x&#xE2;y d&#x1EF1;ng API x&#xE1;c th&#x1EF1;c v&#x1EDB;i nodejs, express v&#xE0; mongodb.<br>
API x&#xE1;c th&#x1EF1;c n&#xE0;y s&#x1EBD; bao g&#x1ED3;m c&#xE1;c ch&#x1EE9;c n&#x103;ng &#x111;&#x103;ng k&#xFD;, &#x111;&#x103;ng nh&#x1EAD;p, validate &#x111;&#x1EA7;u v&#xE0;o, hash pass, x&#xE1;c th&#x1EF1;c v&#x1EDB;i jwt,..</p>
<h2 id="jwtlg">JWT L&#xE0; G&#xEC;?</h2>
<p>JSON Web Token (JWT) l&#xE0; m&#x1ED9;t chu&#x1EA9;n m&#x1EDF; (RFC 7519) &#x111;&#x1ECB;nh ngh&#x129;a m&#x1ED9;t c&#xE1;ch nh&#x1ECF; g&#x1ECD;n v&#xE0; kh&#xE9;p k&#xED;n &#x111;&#x1EC3; truy&#x1EC1;n th&#xF4;ng tin m&#x1ED9;t c&#xE1;ch an to&#xE0;n gi&#x1EEF;a c&#xE1;c b&#xEA;n d&#x1B0;&#x1EDB;i d&#x1EA1;ng &#x111;&#x1ED1;i t&#x1B0;&#x1EE3;ng JSON. Token bao g&#x1ED3;m m&#x1ED9;t header, m&#x1ED9;t payload v&#xE0; m&#x1ED9;t ch&#x1EEF; k&#xFD;.<br>
C&#xE1;c b&#x1EA1;n c&#xF3; th&#x1EC3; t&#xEC;m hi&#x1EC3;u th&#xEA;m v&#x1EC1; JWT <a href="https://jwt.io/introduction/">t&#x1EA1;i &#x111;&#xE2;y</a>.</p>
<h2 id="jwthotngnhthno">JWT Ho&#x1EA1;t &#x110;&#x1ED9;ng Nh&#x1B0; Th&#x1EBF; N&#xE0;o?</h2>
<p>Th&#xEC; m&#xEC;nh m&#x1EDB;i s&#x1B0;u t&#x1EA7;m &#x111;&#x1B0;&#x1EE3;c tr&#xEA;n google m&#x1ED9;t h&#xEC;nh v&#x1EBD; kh&#xE1; chi ti&#x1EBF;t v&#x1EC1; c&#xE1;ch ho&#x1EA1;t &#x111;&#x1ED9;ng c&#x1EE7;a JWT.<br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1581521944/jwt_vlecak.jpg" width="700" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng NodeJS API X&#xE1;c Th&#x1EF1;c V&#x1EDB;i JWT"></p>
<p>&#x1EDE; &#x111;&#xE2;y m&#xEC;nh c&#x169;ng gi&#x1EA3;i th&#xED;ch m&#x1ED9;t t&#xED; cho c&#xE1;c b&#x1EA1;n hi&#x1EC3;u th&#xEA;m v&#x1EC1; c&#xE1;ch ho&#x1EA1;t &#x111;&#x1ED9;ng c&#x1EE7;a JWT, &#x111;&#xF3; l&#xE0; khi ch&#xFA;ng ta &#x111;&#x103;ng nh&#x1EAD;p m&#x1ED9;t t&#xE0;i kho&#x1EA3;n v&#xE0; g&#x1EED;i c&#xE1;c th&#xF4;ng tin nh&#x1B0; email/password l&#xEA;n server th&#xEC; n&#xF3; s&#x1EBD; k&#xFD; m&#x1ED9;t token v&#xE0; g&#x1EED;i token &#x111;&#xF3; v&#x1EC1; ph&#xED;a client &#x111;&#x1EC3; l&#x1B0;u tr&#x1EEF;.<br>
C&#x1EE9; nh&#x1B0; v&#x1EAD;y m&#x1ED7;i l&#x1EA7;n client truy c&#x1EAD;p trang th&#xEC; s&#x1EBD; g&#x1EED;i request l&#xEA;n th&#xEC; ph&#x1EA3;i k&#xE8;m theo token, sau &#x111;&#xF3; server s&#x1EBD; check m&#xE3; n&#xE0;y v&#xE0; g&#x1EED;i l&#x1EA1;i response th&#xE0;nh c&#xF4;ng hay th&#x1EA5;t b&#x1EA1;i t&#x1B0;&#x1A1;ng &#x1EE9;ng ng&#x1B0;&#x1EE3;c v&#x1EC1; client.</p>
<h1 id="mcchbivit">M&#x1EE5;c &#x110;&#xED;ch B&#xE0;i Vi&#x1EBF;t</h1>
<p>Gi&#xFA;p c&#xE1;c b&#x1EA1;n &#xF4;n l&#x1EA1;i c&#xE1;c ki&#x1EBF;n th&#x1EE9;c v&#x1EC1; NodeJS, c&#xE1;ch x&#xE2;y d&#x1EF1;ng c&#x169;ng nh&#x1B0; truy v&#x1EA5;n database MongoDB.<br>
V&#xE0; h&#x1ECD;c c&#x169;ng nh&#x1B0; t&#xEC;m hi&#x1EC3;u th&#xEA;m v&#x1EC1; JWT, c&#xE1;ch x&#xE2;y d&#x1EF1;ng m&#x1ED9;t API v&#x1EC1; x&#xE1;c th&#x1EF1;c v&#xE0; c&#xE1;ch s&#x1EED; d&#x1EE5;ng postman.<br>
Sau b&#xE0;i n&#xE0;y c&#xE1;c b&#x1EA1;n c&#xF3; th&#x1EC3; t&#x1EF1; m&#xEC;nh l&#xE0;m m&#x1ED9;t trang web g&#x1ED3;m c&#xE1;c ch&#x1EE9;c n&#x103;ng &#x111;&#x103;ng nh&#x1EAD;p, &#x111;&#x103;ng k&#xFD; t&#x1EEB; API m&#xEC;nh x&#xE2;y d&#x1EF1;ng &#x111;&#x1B0;&#x1EE3;c. &#x110;&#xF3; c&#x169;ng l&#xE0; m&#x1ED9;t c&#xE1;ch gi&#xFA;p c&#xE1;c b&#x1EA1;n c&#xF3; th&#x1EC3; n&#x1EAF;m v&#x1EEF;ng c&#xE1;c ki&#x1EBF;n th&#x1EE9;c &#x111;&#x1B0;&#x1EE3;c h&#x1ECD;c.<br>
M&#xEC;nh mong mu&#x1ED1;n c&#xE1;c b&#x1EA1;n &#x111;&#x1ECD;c b&#xE0;i m&#x1ED9;t c&#xE1;ch t&#x1EC9; m&#x1EC9;, &#x111;&#x1ECD;c kh&#xF4;ng l&#x1B0;&#x1EDB;t nha.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h1 id="btuthino">B&#x1EAF;t &#x110;&#x1EA7;u Th&#xF4;i N&#xE0;o</h1>
<h2 id="lntngxydngapixcthc">L&#xEA;n &#xDD; T&#x1B0;&#x1EDF;ng X&#xE2;y D&#x1EF1;ng API X&#xE1;c Th&#x1EF1;c</h2>
<p>Tr&#x1B0;&#x1EDB;c khi c&#xE1;c b&#x1EA1;n l&#xE0;m m&#x1ED9;t c&#xE1;i g&#xEC; &#x111;&#xF3; th&#xEC; tr&#x1B0;&#x1EDB;c h&#x1EBF;t ph&#x1EA3;i h&#xEC;nh th&#xE0;nh &#xFD; t&#x1B0;&#x1EDF;ng, sau &#x111;&#xF3; tri&#x1EC3;n khai &#xFD; t&#x1B0;&#x1EDF;ng. &#x110;i&#x1EC1;u n&#xE0;y gi&#xFA;p c&#xE1;c b&#x1EA1;n l&#xE0;m vi&#x1EC7;c m&#x1ED9;t c&#xE1;ch c&#xF3; logic v&#xE0; khoa h&#x1ECD;c h&#x1A1;n.<br>
Tr&#x1B0;&#x1EDB;c khi ch&#xFA;ng ta b&#x1EAF;t tay v&#xE0;o code th&#xEC; m&#xEC;nh s&#x1EBD; gi&#xFA;p c&#xE1;c b&#x1EA1;n n&#x1EAF;m r&#xF5; h&#x1A1;n &#xFD; t&#x1B0;&#x1EDF;ng m&#xEC;nh c&#x1EA7;n l&#xE0;m nha.<br>
Ch&#xFA;ng ta s&#x1EBD; x&#xE2;y d&#x1EF1;ng c&#xE1;c ch&#x1EE9;c n&#x103;ng &#x111;&#x103;ng nh&#x1EAD;p v&#xE0; &#x111;&#x103;ng k&#xFD; tr&#x1B0;&#x1EDB;c ti&#xEA;n &#x111;&#xE3;. &#x110;&#x103;ng nh&#x1EAD;p v&#xE0; &#x111;&#x103;ng k&#xFD; th&#xEC; ch&#xFA;ng ta c&#x1EA7;n ph&#x1EA3;i validate cho n&#xF3;, m&#xE3; h&#xF3;a password,..S&#x1EED; d&#x1EE5;ng JWT &#x111;&#x1EC3; t&#x1EA1;o c&#xE1;c private routes.<br>
<em>&#x1EDE; &#x111;&#xE2;y m&#xEC;nh ch&#x1EC9; n&#xF3;i s&#x1A1; qua th&#xF4;i &#x111;&#x1EC3; cho c&#xE1;c b&#x1EA1;n c&#xF3; th&#x1EC3; h&#xEC;nh dung ra &#x111;&#x1B0;&#x1EE3;c m&#xEC;nh c&#x1EA7;n l&#xE0;m g&#xEC; th&#xF4;i nha. C&#xE1;c b&#x1EA1;n c&#x169;ng theo d&#xF5;i c&#xE1;c ph&#x1EA7;n ti&#x1EBF;p theo &#x111;&#x1EC3; bi&#x1EBF;t th&#xEA;m chi ti&#x1EBF;t nha.</em></p>
<h2 id="citvthitlp">C&#xE0;i &#x110;&#x1EB7;t V&#xE0; Thi&#x1EBF;t L&#x1EAD;p</h2>
<p>Tr&#x1B0;&#x1EDB;c ti&#xEA;n c&#xE1;c b&#x1EA1;n t&#x1EA1;o cho m&#xEC;nh m&#x1ED9;t folder trong folder &#x111;&#xF3; l&#xE0; n&#x1A1;i ch&#x1EE9;a c&#xE1;c th&#x1B0; m&#x1EE5;c v&#xE0; ch&#x1B0;&#x1A1;ng tr&#xEC;nh m&#xE0; ch&#xFA;ng ta d&#xF9;ng &#x111;&#x1EC3; vi&#x1EBF;t API x&#xE1;c th&#x1EF1;c.<br>
<strong>Kh&#x1EDF;i t&#x1EA1;o &#x1EE9;ng d&#x1EE5;ng v&#x1EDB;i file package.json</strong><br>
Trong th&#x1B0; m&#x1EE5;c g&#x1ED1;c c&#x1EE7;a &#x1EE9;ng d&#x1EE5;ng c&#x1EE7;a b&#x1EA1;n v&#xE0; nh&#x1EAD;p <code>npm init</code> &#x111;&#x1EC3; kh&#x1EDF;i t&#x1EA1;o &#x1EE9;ng d&#x1EE5;ng c&#x1EE7;a b&#x1EA1;n v&#x1EDB;i t&#x1EC7;p <code>package.json.</code><br>
<code>npm init </code><br>
Sau &#x111;&#xF3; c&#xE1;c b&#x1EA1;n c&#xE0;i &#x111;&#x1EB7;t c&#xE1;c module &#x1EDF; d&#x1B0;&#x1EDB;i &#x111;&#x1EC3; thi&#x1EBF;t l&#x1EAD;p &#x1EE9;ng d&#x1EE5;ng nha.<br>
&#x110;&#x1EC3; m&#xE0; c&#xE0;i c&#xE1;c module tr&#x1B0;&#x1EDB;c h&#x1EBF;t c&#xE1;c b&#x1EA1;n ph&#x1EA3;i c&#xE0;i &#x111;&#x1EB7;t NodeJS t&#x1EA1;i &#x111;&#xE2;y.</p>
<ul>
<li><strong>npm install express --save</strong><br>
Module d&#xF9;ng &#x111;&#x1EC3; c&#xE0;i &#x111;&#x1EB7;t framework express c&#x1EE7;a nodejs gi&#xFA;p c&#xE1;c b&#x1EA1;n code m&#x1ED9;t c&#xE1;ch t&#x1ED1;i gi&#x1EA3;n c&#x169;ng nh&#x1B0; nhanh ch&#xF3;ng h&#x1A1;n.</li>
<li><strong>npm install body-parse --save</strong><br>
Package body-parser d&#xF9;ng &#x111;&#x1EC3; truy xu&#x1EA5;t d&#x1EEF; li&#x1EC7;u trong form g&#x1EED;i l&#xEA;n server theo ph&#x1B0;&#x1A1;ng th&#x1EE9;c POST.</li>
<li><strong>npm install nodemon --save</strong><br>
T&#x1EF1; &#x111;&#x1ED9;ng reload l&#x1EA1;i server khi b&#x1EA1;n thay &#x111;&#x1ED5;i code. &#x110;&#x1EC3; kh&#x1EDF;i ch&#x1EA1;y server c&#xE1;c b&#x1EA1;n th&#xEA;m <code>&quot;devStart&quot;: &quot;nodemon app.js&quot;</code> v&#xE0;o file <strong>package.json</strong> nha. C&#xE1;c b&#x1EA1;n m&#x1EDF; terminal l&#xEA;n sau &#x111;&#xF3; g&#xF5; <code>npm run devStart</code> &#x111;&#x1EC3; kh&#x1EDF;i ch&#x1EA1;y server nha.</li>
<li><strong>npm install mongoose --save</strong><br>
Mongoose l&#xE0; m&#x1ED9;t Object Document Mapper (ODM). &#x110;i&#x1EC1;u n&#xE0;y c&#xF3; ngh&#x129;a l&#xE0; Mongoose cho ph&#xE9;p b&#x1EA1;n &#x111;&#x1ECB;nh ngh&#x129;a c&#xE1;c object (&#x111;&#x1ED1;i t&#x1B0;&#x1EE3;ng) v&#x1EDB;i m&#x1ED9;t schema &#x111;&#x1B0;&#x1EE3;c &#x111;&#x1ECB;nh ngh&#x129;a r&#xF5; r&#xE0;ng.</li>
<li><strong>npm install dotenv --save</strong><br>
Dotenv l&#xE0; m&#x1ED9;t bi&#x1EBF;n m&#xF4;i tr&#x1B0;&#x1EDD;ng d&#xF9;ng &#x111;&#x1EC3; b&#x1EA3;o m&#x1EAD;t c&#xE1;c th&#xF4;ng tin quan tr&#x1ECD;ng nh&#x1B0; username, password, url database,...N&#x1EBF;u ch&#xFA;ng ta kh&#xF4;ng l&#x1B0;u nh&#x1EEF;ng th&#xF4;ng tin m&#x1EAD;t v&#xE0;o file .env th&#xEC; khi push source code l&#xEA;n github th&#xEC; ai c&#x169;ng c&#xF3; th&#x1EC3; v&#xE0;o xem &#x111;&#x1B0;&#x1EE3;c v&#xE0; ai c&#x169;ng bi&#x1EBF;t username, password th&#xEC; s&#x1EBD; b&#x1ECB; ng&#x1B0;&#x1EDD;i kh&#xE1;c chi&#x1EBF;m &#x111;o&#x1EA1;t v&#xE0; &#x111;&#xE1;nh c&#x1EAF;p t&#xE0;i li&#x1EC7;u r&#x1EA5;t l&#xE0; nguy hi&#x1EC3;m nha.</li>
<li><strong>npm install @hapi/joi --save</strong><br>
Module Joi n&#xE0;y d&#xF9;ng &#x111;&#x1EC3; x&#xE1;c nh&#x1EAD;n d&#x1EEF; li&#x1EC7;u, v&#xED; d&#x1EE5; nh&#x1B0; b&#x1EA1;n khi b&#x1EA1;n nh&#x1EAD;p b&#x1EA1;n nh&#x1EAD;p password b&#x1EAF;t bu&#x1ED9;c ph&#x1EA3;i nh&#x1EAD;p tr&#xEA;n 6 t&#x1EEB; hay l&#xE0; email c&#xE1;c b&#x1EA1;n ph&#x1EA3;i nh&#x1EAD;p &#x111;&#xFA;ng c&#xE1;c ki&#x1EC3;u k&#xED; t&#x1EF1; &#x111;&#x1EC3; t&#x1EA1;o email,..th&#xEC; c&#xE1;c b&#x1EA1;n c&#x1EA7;n ph&#x1EA3;i x&#xE1;c nh&#x1EAD;n cho n&#xF3; b&#x1EB1;ng module joi.</li>
<li><strong>npm install bcryptjs --save</strong><br>
Module d&#xF9;ng &#x111;&#x1EC3; m&#xE3; h&#xF3;a password.</li>
<li><strong>npm install jsonwebtoken --save</strong><br>
Module n&#xE0;y d&#xF9;ng &#x111;&#x1EC3; x&#xE1;c th&#x1EF1;c v&#xE0; t&#x1EA1;o c&#xE1;c private routes.<br>
<strong>V&#xE0; &#x111;&#xE2;y c&#x169;ng l&#xE0; package c&#x1EE7;a m&#xEC;nh khi &#x111;&#xE3; c&#xE0;i &#x111;&#x1EB7;t c&#x169;ng nh&#x1B0; c&#x1EA5;u h&#xEC;nh xong c&#xE1;c npm cho &#x1EE9;ng d&#x1EE5;ng.</strong><br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1581610724/package_tyu0rb.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng NodeJS API X&#xE1;c Th&#x1EF1;c V&#x1EDB;i JWT"></li>
</ul>
<p>Trong th&#x1B0; m&#x1EE5;c &#x1EE9;ng d&#x1EE5;ng c&#x1EE7;a ch&#xFA;ng ta b&#xE2;y gi&#x1EDD; hi&#x1EC7;n c&#xF3; ba file &#x111;&#xF3; l&#xE0; <code>node_modules</code>, <code>package.json</code> v&#xE0; <code>package-lock.json</code></p>
<pre><code>Authentication with JWT
     &#x2514;&#x2500;&#x2500; node_modules
     &#x2514;&#x2500;&#x2500; package-lock.json
     &#x2514;&#x2500;&#x2500; package.json
</code></pre>
<h1 id="btucodethino">B&#x1EAF;t &#x110;&#x1EA7;u Code Th&#xF4;i N&#xE0;o</h1>
<h2 id="thitlpwebserver">Thi&#x1EBF;t L&#x1EAD;p Web Server</h2>
<p>Trong th&#x1B0; m&#x1EE5;c g&#x1ED1;c c&#xE1;c b&#x1EA1;n t&#x1EA1;o cho m&#xEC;nh file app.js, file n&#xE0;y l&#xE0; file ch&#xED;nh d&#xF9;ng &#x111;&#x1EC3; &#x111;i&#x1EC1;u khi&#x1EC3;n m&#x1ECD;i ho&#x1EA1;t &#x111;&#x1ED9;ng ch&#xED;nh c&#x1EE7;a server.</p>
<pre><code>const express = require(&quot;express&quot;);
const app = express();
const bodyParser = require(&apos;body-parser&apos;);
const port = 3333;

// Import routes
const indexUser = require(&quot;./routes/index&quot;)

// G&#x1EED;i y&#xEA;u c&#x1EA7;u ph&#xE2;n t&#xED;ch ki&#x1EC3;u n&#x1ED9;i dung application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: true }))

// G&#x1EED;i y&#xEA;u c&#x1EA7;u ph&#xE2;n t&#xED;ch ki&#x1EC3;u n&#x1ED9;i dung application/json
app.use(bodyParser.json())

// Route middlewares
app.use(&apos;/api/user&apos;,indexUser)

// L&#x1EAF;ng nghe c&#xE1;c requests
app.listen(port, function(){
    console.log(&quot;Server listening port&quot;,+port)
})
</code></pre>
<p>Trong th&#x1B0; m&#x1EE5;c g&#x1ED1;c b&#x1EA1;n t&#x1EA1;o cho m&#xEC;nh th&#x1B0; m&#x1EE5;c <code>routes</code>, trong th&#x1B0; m&#x1EE5;c router c&#xE1;c b&#x1EA1;n t&#x1EA1;o cho m&#xEC;nh file index.js. Ti&#x1EBF;p &#x111;&#x1EBF;n t&#x1EA1;o cho n&#xF3; m&#x1ED9;t Route handlers v&#xE0; th&#x1EED; ch&#x1EA1;y sever xem sau. M&#x1EE5;c &#x111;&#xED;ch &#x111;&#x1EC3; c&#xE1;c b&#x1EA1;n test xem server c&#xF3; ch&#x1EA1;y kh&#xF4;ng nha.</p>
<pre><code>router.get(&apos;/&apos;,function(req, res, next){
res.send(&apos;Hello World&apos;)
})

</code></pre>
<h2 id="thitlpdatabase">Thi&#x1EBF;t L&#x1EAD;p Database</h2>
<p>&#x110;&#x1EC3; m&#xE0; c&#xF3; th&#x1EC3; thi&#x1EBF;t l&#x1EAD;p &#x111;&#x1B0;&#x1EE3;c database th&#xEC; c&#xE1;c b&#x1EA1;n &#x111;&#x103;ng nh&#x1EAD;p t&#xE0;i kho&#x1EA3;n mongodb atlas <a href="https://account.mongodb.com/account/login">t&#x1EA1;i &#x111;&#xE2;y nha</a>. Sau khi c&#xE1;c b&#x1EA1;n b&#x1EA1;n &#x111;&#xE3; c&#xF3; t&#xE0;i kho&#x1EA3;n mongodb atlas th&#xEC; ti&#x1EBF;p &#x111;&#x1EBF;n c&#xE0;i &#x111;&#x1EB7;t c&#x1EA5;u h&#xEC;nh &#x111;&#x1EC3; c&#xF3; th&#x1EC3; k&#x1EBF;t n&#x1ED1;i mongodb atlas v&#x1EDB;i &#x1EE9;ng d&#x1EE5;ng c&#x1EE7;a ch&#xFA;ng ta. &#x110;&#x1EC3; bi&#x1EBF;t th&#xEA;m chi ti&#x1EBF;t c&#xE1;c b&#x1EA1;n xem b&#x1B0;&#x1EDB;c 3 trong b&#xE0;i vi&#x1EBF;t c&#x1EE7;a m&#xEC;nh h&#x1B0;&#x1EDB;ng d&#x1EAB;n deploy project nodejs l&#xEA;n heroku <a href="https://www.thanhlongdev.com/huong-dan-cach-deploy-project-nodejs-len-heroku/">t&#x1EA1;i &#x111;&#xE2;y nha</a>.<br>
Sau &#x111;&#xF3; c&#xE1;c b&#x1EA1;n copy link database mongodb &#x111;&#xE3; t&#x1EA1;o r&#x1ED3;i paste v&#xE0;o project c&#x1EE7;a m&#xEC;nh l&#xE0; &#x111;&#x1B0;&#x1EE3;c nha. C&#xE1;c b&#x1EA1;n t&#x1EA1;o cho m&#xEC;nh m&#x1ED9;t file <code>.env</code> b&#xEA;n trong th&#x1B0; m&#x1EE5;c g&#x1ED1;c.<br>
Trong file n&#xE0;y c&#xE1;c b&#x1EA1;n t&#x1EA1;o m&#x1ED9;t &#x111;&#x1B0;&#x1EDD;ng d&#x1EAB;n l&#xE0; <code>DATABASE_URL=mongodb+srv://long:&lt;password&gt;@cluster0-b7d8c.mongodb.net/test?retryWrites=true&amp;w=majority</code><br>
Trong file app.js c&#xE1;c b&#x1EA1;n khai b&#xE1;o module dotenv v&#x1EDB;i module mongoose v&#xE0; t&#x1EA1;o &#x111;&#x1B0;&#x1EDD;ng d&#x1EAB;n mongodb.<br>
// Khai b&#xE1;o dotenv<br>
<code>require(&apos;dotenv&apos;).config()</code><br>
// path database<br>
<code>var mongoose = require(&apos;mongoose&apos;);</code></p>
<pre><code>// K&#x1EBF;t n&#x1ED1;i database
mongoose.connect(process.env.DATABASE_URL, 
{useNewUrlParser: true, useUnifiedTopology: true}).then(function() {
    console.log(&quot;Successfully connected to the database&quot;);    
}).catch(function(err) {
    console.log(&apos;Could not connect to the database. Exiting now...&apos;, err);
    process.exit();
});
</code></pre>
<p>&#x110;&#x1EC3; bi&#x1EBF;t n&#xF3; &#x111;&#xE3; k&#x1EBF;t n&#x1ED1;i hay ch&#x1B0;a c&#xE1;c b&#x1EA1;n kh&#x1EDF;i &#x111;&#x1ED9;ng l&#x1EA1;i server s&#x1EBD; bi&#x1EBF;t nha.<br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1581776524/Untitled_azwn4b.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng NodeJS API X&#xE1;c Th&#x1EF1;c V&#x1EDB;i JWT"></p>
<h2 id="nhnghaccschemauserchomongoose">&#x110;&#x1ECB;nh Ngh&#x129;a C&#xE1;c Schema User Cho Mongoose</h2>
<p>B&#xEA;n trong th&#x1B0; m&#x1EE5;c g&#x1ED1;c c&#xE1;c b&#x1EA1;n t&#x1EA1;o cho m&#xEC;nh th&#x1B0; m&#x1EE5;c <code>modal</code> b&#xEA;n trong th&#x1B0; m&#x1EE5;c <code>modal</code> c&#xE1;c b&#x1EA1;n t&#x1EA1;o cho m&#xEC;nh file <code>user.modal.js</code>.<br>
Trong file <code>user.modal.js</code> c&#x1EA7;n t&#x1EA1;o m&#x1ED9;t &#x111;&#x1ED1;i t&#x1B0;&#x1EE3;ng book v&#xE0; s&#x1EBD; ch&#x1EE9;a ba thu&#x1ED9;c t&#xED;nh l&#xE0; name, email v&#xE0; password.</p>
<pre><code>const mongoose = require(&quot;mongoose&quot;)

const userSchema = mongoose.Schema({
    name:{required: true, type:String},
    email:{required: true, type:String},
    password:{required: true, type:String},
})
// Bi&#xEA;n d&#x1ECB;ch m&#xF4; h&#xEC;nh t&#x1EEB; schema
module.exports = mongoose.model(&apos;user&apos;, userSchema)
</code></pre>
<p>Tham s&#x1ED1; th&#x1EE9; nh&#x1EA5;t l&#xE0; t&#xEA;n ri&#xEA;ng cho collection s&#x1EAF;p &#x111;&#x1B0;&#x1EE3;c t&#x1EA1;o ra cho m&#xF4; h&#xEC;nh c&#x1EE7;a b&#x1EA1;n, v&#xE0; tham s&#x1ED1; th&#x1EE9; hai l&#xE0; schema m&#xE0; b&#x1EA1;n mu&#x1ED1;n d&#xF9;ng &#x111;&#x1EC3; t&#x1EA1;o ra m&#xF4; h&#xEC;nh.<br>
<em><strong>Sau khi ch&#xFA;ng ta &#x111;&#xE3; setup xong h&#x1EC7; th&#x1ED1;ng th&#xEC; b&#xE2;y gi&#x1EDD; m&#xEC;nh s&#x1EBD; &#x111;i &#x111;&#x1EBF;n t&#x1EEB;ng ch&#x1EE9;c n&#x103;ng c&#x1EE5; th&#x1EC3; nha. Th&#xEC; ch&#x1EE9;c n&#x103;ng &#x111;&#x1EA7;u ti&#xEA;n m&#xEC;nh mu&#x1ED1;n gi&#x1EDB;i thi&#x1EC7;u &#x111;&#x1EBF;n l&#xE0; ch&#x1EE9;c n&#x103;ng &#x111;&#x103;ng k&#xFD;.</strong></em></p>
<h2 id="xlyucungk">X&#x1EED; L&#xFD; Y&#xEA;u C&#x1EA7;u &#x110;&#x103;ng K&#xFD;</h2>
<p>Trong ph&#x1EA7;n x&#x1EED; l&#xFD; y&#xEA;u c&#x1EA7;u &#x111;&#x103;ng k&#xFD; ch&#xFA;ng ta s&#x1EBD; chia l&#xE0;m 3 ph&#x1EA7;n:<br>
Ph&#x1EA7;n 1: T&#x1EA1;o user.<br>
Ph&#x1EA7;n 2: Validate user.<br>
Ph&#x1EA7;n 3: Check email c&#xF3; t&#x1ED3;n t&#x1EA1;i hay kh&#xF4;ng v&#xE0; m&#xE3; h&#xF3;a password.<br>
<strong>Ch&#xFA;ng ta s&#x1EBD; b&#x1EAF;t tay v&#xE0;o l&#xE0;m t&#x1EEB;ng ph&#x1EA7;n lu&#xF4;n nha.</strong></p>
<h3 id="touser">T&#x1EA1;o User</h3>
<p>Trong file <code>index.js</code> n&#x1EB1;m trong th&#x1B0; m&#x1EE5;c <code>routes</code>, c&#xE1;c b&#x1EA1;n khai b&#xE1;o cho m&#xEC;nh modal user l&#xFA;c n&#xE3;y m&#xEC;nh  v&#x1EEB;a t&#x1EA1;o.<br>
<code>const User = require(&quot;../modal/user.modal&quot;)</code><br>
Th&#x1EE9; hai, c&#xE1;c b&#x1EA1;n t&#x1EA1;o cho m&#xEC;nh router <code>Post /register</code>. Trong router n&#xE0;y ch&#xFA;ng ta s&#x1EED; d&#x1EE5;ng &#x111;&#x1EC3; t&#x1EA1;o user c&#x169;ng nh&#x1B0; validate user, hash pass,...<br>
N&#xF3; s&#x1EBD; t&#x1EA1;o m&#x1ED9;t object r&#x1ED9;ng, ch&#x1EE9;a c&#xE1;c d&#x1EEF; li&#x1EC7;u user &#x111;&#x1B0;&#x1EE3;c truy&#x1EC1;n v&#xE0;o. R&#x1ED3;i l&#x1B0;u d&#x1EEF; li&#x1EC7;u v&#xE0;o database &#x111;&#xE3; &#x111;&#x1B0;&#x1EE3;c kh&#x1EDF;i t&#x1EA1;o.<br>
Ch&#xFA;ng ta l&#x1B0;u d&#x1EEF; li&#x1EC7;u c&#x169;ng nh&#x1B0; log ra l&#x1ED7;i trong try{} catch{} nha. N&#x1EBF;u m&#xE0; ch&#xFA;ng ta nh&#x1EAD;p &#x111;&#x1EA7;y &#x111;&#x1EE7; d&#x1EEF; li&#x1EC7;u th&#xEC; n&#xF3; s&#x1EBD; th&#x1EF1;c hi&#x1EC7;n trong h&#xE0;m try r&#x1ED3;i sau &#x111;&#xF3; log ra d&#x1EEF; li&#x1EC7;u c&#x1EE7;a user.<br>
N&#x1EBF;u b&#x1EA1;n kh&#xF4;ng nh&#x1EAD;p &#x111;&#x1EA7;y &#x111;&#x1EE7; d&#x1EEF; li&#x1EC7;u c&#x169;ng nh&#x1B0; c&#xF3; l&#x1ED7;i x&#x1EA3;y ra th&#xEC; n&#xF3; s&#x1EBD; th&#x1EF1;c hi&#x1EC7;n h&#xE0;m catch &#x111;&#x1EC3; log ra l&#x1ED7;i, c&#xE1;c b&#x1EA1;n c&#xF3; th&#x1EC3; test th&#x1EED; trong postman &#x111;&#x1EC3; c&#xF3; th&#x1EC3; hi&#x1EC3;u r&#xF5; h&#x1A1;n.</p>
<pre><code>router.post(&apos;/register&apos;, async function(req, res){

     // T&#x1EA1;o user
     const newuser = new User();
     newuser.name = req.body.name
     newuser.email = req.body.email
     newuser.password = req.body.password
     try{
         const User = await newuser.save()
         res.send(User);
     }catch(err){
         res.status(400).send(err);
     }
})
</code></pre>
<p><strong>Ch&#xFA;ng ta c&#xF9;ng test API n&#xE0;y b&#x1EB1;ng postman &#x111;&#x1EC3; t&#x1EA1;o user th&#x1EED; nha.</strong><br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1581829962/Untitled_e8vmbr.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng NodeJS API X&#xE1;c Th&#x1EF1;c V&#x1EDB;i JWT"></p>
<h3 id="validateuser">Validate User</h3>
<p>Sau khi ch&#xFA;ng ta t&#x1EA1;o user xong th&#xEC; s&#x1EBD; d&#x1EBF;n ph&#x1EA7;n x&#xE1;c nh&#x1EAD;n user. X&#xE1;c nh&#x1EAD;n &#x1EDF; &#x111;&#xE2;y l&#xE0; ch&#xFA;ng ta x&#xE1;c nh&#x1EAD;n &#x111;&#x1EA7;u v&#xE0;o c&#x1EE7;a user. V&#xED; d&#x1EE5; nh&#x1B0;: b&#x1EA1;n nh&#x1EAD;p c&#xF3; &#x111;&#xFA;ng email kh&#xF4;ng, password ph&#x1EA3;i d&#xE0;i h&#x1A1;n 6 k&#xED; t&#x1EF1;,...<br>
Th&#xEC; &#x111;&#x1EC3; x&#xE1;c th&#x1EF1;c nh&#x1B0; v&#x1EAD;y ch&#xFA;ng ta s&#x1EED; d&#x1EE5;ng module <strong>Joi</strong> nha. Module n&#xE0;y m&#xEC;nh &#x111;&#xE3; c&#xE0;i &#x111;&#x1EB7;t &#x1EDF; tr&#xEA;n r&#x1ED3;i &#x111;&#xF3;.<br>
Trong th&#x1B0; m&#x1EE5;c g&#x1ED1;c c&#xE1;c b&#x1EA1;n t&#x1EA1;o cho m&#xEC;nh folder c&#xF3; t&#xEA;n l&#xE0; <code>auth</code> trong th&#x1B0; m&#x1EE5;c &#x111;&#x1ED1; c&#xE1;c b&#x1EA1;n ti&#x1EBF;p t&#x1EE5;c t&#x1EA1;o cho m&#xEC;nh file <code>validation.js</code>.<br>
File <code>validation.js</code> s&#x1EBD; l&#xE0; file m&#xE0; ch&#xFA;ng ta d&#xF9;ng &#x111;&#x1EC3; &#x111;i&#x1EC1;u khi&#x1EC3;n m&#x1ECD;i ho&#x1EA1;t &#x111;&#x1ED9;ng ch&#xED;nh li&#xEA;n quan &#x111;&#x1EBF;n x&#xE1;c nh&#x1EAD;n.<br>
Tr&#x1B0;&#x1EDB;c ti&#xEA;n c&#xE1;c b&#x1EA1;n khai b&#xE1;o cho m&#xEC;nh module <strong>Joi</strong>. C&#xE1;c b&#x1EA1;n c&#xF3; th&#x1EC3; tham kh&#x1EA3;o th&#xEA;m v&#x1EC1; <strong>joi</strong> <a href="https://hapi.dev/family/joi/?v=16.1.7">t&#x1EA1;i &#x111;&#xE2;y</a><br>
Data &#x1EDF; &#x111;&#xE2;y l&#xE0; tham s&#x1ED1; ch&#xFA;ng ta truy&#x1EC1;n v&#xE0;o d&#xF9;ng &#x111;&#x1EC3; x&#xE1;c nh&#x1EAD;n v&#xE0; &#x111;&#xF3; l&#xE0; c&#xE1;c tr&#x1B0;&#x1EDD;ng d&#x1EEF; li&#x1EC7;u nh&#x1B0;: name, email, password.</p>
<pre><code>const Joi = require(&apos;@hapi/joi&apos;);

// Register Validate
const registerValidation = function(data){
    const schema = Joi.object ({
        name: Joi.string()
                 .min(4)
                 .required(),
        email: Joi.string()
                   .email()
                   .min(6)
                   .required(),
        password: Joi.string()
                   .min(6)
                   .required(),
                          
    })
   return  schema.validate(data)
}
module.exports.registerValidation = registerValidation
</code></pre>
<p>&#x110;&#x1EC3; m&#xE0; n&#xF3; c&#xF3; th&#x1EC3; ho&#x1EA1;t &#x111;&#x1ED9;ng &#x111;&#x1B0;&#x1EE3;c ch&#xFA;ng ta c&#x1EA7;n ph&#x1EA3;i import <strong>registerValidation</strong> t&#x1EEB; file <strong>validation.js</strong> v&#xE0;o trong file <strong>index.js</strong> c&#x1EE7;a <strong>routes</strong>.<br>
<code>const {registerValidation} = require(&quot;../auth/validation&quot;)</code><br>
C&#x169;ng trong router  <code>Post /register</code> c&#xE1;c b&#x1EA1;n code th&#xEA;m m&#x1ED9;t &#x111;o&#x1EA1;n m&#xE3; n&#x1EEF;a &#x1EDF; tr&#xEA;n th&#x1EB1;ng t&#x1EA1;o user &#x111;&#x1EC3; c&#xF3; th&#x1EC3; x&#xE1;c nh&#x1EAD;n &#x111;&#x1EA7;u v&#xE0;o cho n&#xF3;.</p>
<pre><code> // Validate user
    const{ error } = registerValidation(req.body);
     if(error) return res.status(400).send(error.details[0].message)
</code></pre>
<p>Data &#x111;&#x1B0;&#x1EE3;c truy&#x1EC1;n v&#xE0;o &#x111;&#xF3; l&#xE0; req.body, n&#x1EBF;u g&#x1EB7;p l&#x1ED7;i th&#xEC; log ra th&#xF4;ng b&#xE1;o.<br>
<strong>Ch&#xFA;ng ta c&#xF9;ng xem th&#x1EED; n&#xF3; x&#xE1;c nh&#x1EAD;n &#x111;&#x1EA7;u v&#xE0;o nh&#x1B0; th&#x1EBF; n&#xE0;o nh&#xE9;</strong><br>
Ch&#xFA;ng ta &#x111;&#x1EC3; &#xFD; trong password m&#xEC;nh ch&#x1EC9; vi&#x1EBF;t 3 k&#xED; t&#x1EF1; th&#xEC; n&#xF3; li&#x1EC1;n log ra th&#xF4;ng b&#xE1;o ngay, ch&#xFA;ng ta &#x111;&#xE3; y&#xEA;u c&#x1EA7;u l&#xE0; password ph&#x1EA3;i 6 k&#xED; t&#x1EF1; tr&#x1EDF; l&#xEA;n m&#x1EDB;i &#x111;&#xFA;ng.<br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1581825635/Untitled_dsnmqr.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng NodeJS API X&#xE1;c Th&#x1EF1;c V&#x1EDB;i JWT"></p>
<h3 id="checkemailctntihaykhngvmhapassword">Check Email C&#xF3; T&#x1ED3;n T&#x1EA1;i Hay Kh&#xF4;ng V&#xE0; M&#xE3; H&#xF3;a Password</h3>
<p>Khi ch&#xFA;ng ta &#x111;&#x103;ng k&#xFD; m&#x1ED9;t t&#xE0;i kho&#x1EA3;n th&#xEC; email l&#xE0; ph&#x1EA7;n quan tr&#x1ECD;ng nh&#x1EA5;t m&#x1ED7;i t&#xE0;i kho&#x1EA3;n s&#x1EBD; c&#xF3; m&#x1ED9;t email ri&#xEA;ng. Name v&#xE0; password c&#xF3; th&#x1EC3; gi&#x1ED1;ng nhau nh&#x1B0;ng email l&#xE0; kh&#xF4;ng bao gi&#x1EDD; gi&#x1ED1;ng nhau &#x111;&#x1B0;&#x1EE3;c.<br>
V&#xEC; th&#x1EBF; ch&#xFA;ng ta c&#x1EA7;n check email user &#x111;&#x1EC3; xem email h&#x1ECD; &#x111;&#x103;ng k&#xFD; c&#xF3; tr&#xF9;ng v&#x1EDB;i email &#x111;&#xE3; &#x111;&#x103;ng k&#xFD; hay ch&#x1B0;a.<br>
C&#x169;ng trong router  <code>Post /register</code> c&#xE1;c b&#x1EA1;n code th&#xEA;m m&#x1ED9;t &#x111;o&#x1EA1;n m&#xE3; &#x1EDF; d&#x1B0;&#x1EDB;i th&#x1EB1;ng x&#xE1;c nh&#x1EAD;n user &#x111;&#x1EC3; c&#xF3; th&#x1EC3; check email c&#xF3; t&#x1ED3;n t&#x1EA1;i hay kh&#xF4;ng.<br>
N&#xF3; s&#x1EBD; t&#xEC;m trong database xem th&#x1EED; th&#x1EB1;ng email m&#xE0; m&#xEC;nh nh&#x1EAD;p n&#xF3; c&#xF3; tr&#xF9;ng v&#x1EDB;i email n&#xE0;o trong database hay kh&#xF4;ng. N&#x1EBF;u c&#xF3; th&#xEC; s&#x1EBD; log ra th&#xF4;ng b&#xE1;o.</p>
<pre><code>     // Ki&#x1EC3;m tra email c&#xF3; t&#x1ED3;n t&#x1EA1;i hay kh&#xF4;ng
     const emailExist = await User.findOne({email: req.body.email});
     if(emailExist) return res.status(400).send(&quot;Email &#x111;&#xE3; t&#x1ED3;n t&#x1EA1;i&quot;)
</code></pre>
<p><strong>Ch&#xFA;ng ta xem th&#x1EED; n&#xF3; ki&#x1EC3;m tra email c&#xF3; t&#x1ED3;n t&#x1EA1;i hay kh&#xF4;ng nh&#x1B0; th&#x1EBF; n&#xE0;o nh&#xE9;</strong><br>
B&#xE2;y gi&#x1EDD; ch&#xFA;ng ta th&#x1EED; &#x111;&#x103;ng k&#xFD; email tr&#xF9;ng v&#x1EDB;i email m&#xE0; m&#xEC;nh &#x111;&#xE3; t&#x1EA1;o r&#x1ED3;i v&#xE0; xem th&#x1EED; k&#x1EBF;t qu&#x1EA3; nha.<br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1581830277/Untitled_epcmkv.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng NodeJS API X&#xE1;c Th&#x1EF1;c V&#x1EDB;i JWT"></p>
<h4 id="mhapassword">M&#xE3; H&#xF3;a Password</h4>
<p>M&#xE3; h&#xF3;a password l&#xE0; ph&#x1EA7;n r&#x1EA5;t l&#xE0; quan tr&#x1ECD;ng v&#xE0; kh&#xF4;ng th&#x1EC3; thi&#x1EBF;u trong m&#x1ED7;i website khi t&#x1EA1;o user. M&#x1EE5;c &#x111;&#xED;ch ch&#xED;nh l&#xE0; b&#x1EA3;o m&#x1EAD;t ng&#x1B0;&#x1EDD;i v&#xED; d&#x1EE5; nh&#x1B0; khi c&#xE1;c hacker t&#x1EA5;n c&#xF4;ng website v&#xE0; l&#x1EA5;y &#x111;&#x1B0;&#x1EE3;c database th&#xEC; h&#x1ECD; s&#x1EBD; kh&#xF4;ng th&#x1EC3; chi&#x1EBF;m &#x111;o&#x1EA1;t &#x111;&#x1B0;&#x1EE3;c t&#xE0;i kho&#x1EA3;n c&#x1EE7;a ch&#xFA;ng ta v&#xEC; password &#x111;&#xE3; &#x111;&#x1B0;&#x1EE3;c m&#xE3; h&#xF3;a.<br>
Trong file <strong>index.js</strong> c&#x1EE7;a <strong>routes</strong> c&#xE1;c b&#x1EA1;n khai b&#xE1;o module <strong>bcrypt</strong> &#x111;&#x1EC3; c&#xF3; th&#x1EC3; hash pass nha.<br>
<code>const bcrypt = require(&quot;bcryptjs&quot;)</code><br>
C&#x169;ng trong router  <code>Post /register</code> c&#xE1;c b&#x1EA1;n code th&#xEA;m m&#x1ED9;t &#x111;o&#x1EA1;n m&#xE3; n&#x1EEF;a &#x1EDF; ph&#xED;a d&#x1B0;&#x1EDB;i th&#x1EB1;ng check email t&#x1ED3;n t&#x1EA1;i nha &#x111;&#x1EC3; c&#xF3; th&#x1EC3; m&#xE3; h&#xF3;a password cho n&#xF3;.<br>
V&#x1EDB;i bcrypt ta c&#x1EA7;n ch&#xFA; &#xFD; t&#x1EDB;i rounds truy&#x1EC1;n v&#xE0;o &#x111;&#x1EC3; sinh salt. V&#x1EDB;i rounds c&#xE0;ng l&#x1EDB;n th&#xEC; c&#xE0;ng b&#x1EA3;o m&#x1EAD;t nh&#x1B0;ng th&#x1EDD;i gian x&#x1EED; l&#xFD; c&#x169;ng m&#x1EA5;t nhi&#x1EC1;u h&#x1A1;n.</p>
<pre><code>     // M&#xE3; h&#xF3;a password
     
     const salt = await bcrypt.genSalt(10);
     const hashPass = await bcrypt.hash(req.body.password, salt)// m&#xE3; h&#xF3;a password truy&#x1EC1;n v&#xE0;o v&#xE0; g&#xE1;n n&#xF3; v&#xE0;o bi&#x1EBF;n hashPass &#x111;&#x1EC3; c&#xF3; th&#x1EC3; l&#x1B0;u pass v&#xE0;o database.
</code></pre>
<p>Trong ph&#x1EA7;n t&#x1EA1;o user c&#xE1;c b&#x1EA1;n thay &#x111;&#x1ED5;i m&#x1ED9;t ch&#xFA;t nha. Thay &#x111;&#x1ED5;i <code>newuser.password = req.body.password</code> th&#xE0;nh <code>newuser.password = hashPass</code> nha &#x111;&#x1EC3; n&#xF3; c&#xF3; th&#x1EC3; l&#x1B0;u pass &#x111;&#xE3; thay &#x111;&#x1ED5;i v&#xE0;o database.<br>
<strong>Ch&#xFA;ng ta c&#xF9;ng xem th&#x1EED; n&#xF3; m&#xE3; h&#xF3;a ra sao nh&#xE9;</strong><br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1581841691/Untitled_qdopsx.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng NodeJS API X&#xE1;c Th&#x1EF1;c V&#x1EDB;i JWT"></p>
<p><em>V&#x1EAD;y l&#xE0; ch&#xFA;ng ta &#x111;&#xE3; xong ph&#x1EA7;n &#x111;&#x103;ng k&#xFD; ti&#x1EBF;p theo l&#xE0; &#x111;&#x1EBF;n ph&#x1EA7;n &#x111;&#x103;ng nh&#x1EAD;p nha.</em></p>
<h2 id="xlyucungnhp">X&#x1EED; L&#xFD; Y&#xEA;u C&#x1EA7;u &#x110;&#x103;ng Nh&#x1EAD;p</h2>
<p>Trong ph&#x1EA7;n &#x111;&#x103;ng nh&#x1EAD;p m&#xEC;nh chia l&#xE0;m 2 ph&#x1EA7;n.<br>
Ph&#x1EA7;n 1: Validate user.<br>
Ph&#x1EA7;n 2: Check email v&#xE0; password.<br>
<strong>Ch&#xFA;ng ta s&#x1EBD; b&#x1EAF;t tay v&#xE0;o l&#xE0;m t&#x1EEB;ng ph&#x1EA7;n lu&#xF4;n nha.</strong></p>
<h3 id="validateuser">Validate User</h3>
<p>Th&#xEC; th&#x1EB1;ng n&#xE0;y c&#x169;ng t&#x1B0;&#x1A1;ng nh&#x1B0; th&#x1EB1;ng x&#xE1;c nh&#x1EAD;n user c&#x1EE7;a &#x111;&#x103;ng k&#xFD; th&#xF4;i, ch&#x1EC9; kh&#xE1;c &#x1EDF; ch&#x1ED5; t&#x1EEB; ba tr&#x1B0;&#x1EDD;ng b&#xE2;y gi&#x1EDD; m&#xEC;nh ch&#x1EC9; x&#xE1;c nh&#x1EAD;n 2 tr&#x1B0;&#x1EDD;ng th&#xF4;i.<br>
C&#x169;ng trong file <strong>validation.js</strong> c&#xE1;c b&#x1EA1;n th&#xEA;m cho m&#xEC;nh ph&#x1EA7;n x&#xE1;c nh&#x1EAD;n user &#x111;&#x1EC3; x&#x1EED; l&#xFD; &#x111;&#x103;ng nh&#x1EAD;p v&#xE0; exports n&#xF3; ra l&#xE0; &#x111;&#x1B0;&#x1EE3;c.</p>
<pre><code>// Login Validate
const loginValidation = function(data){
    const schema = Joi.object ({
        email: Joi.string()
                   .email()
                   .min(6)
                   .required(),
        password: Joi.string()
                   .min(6)
                   .required(),
    })
   return  schema.validate(data)
}
module.exports.loginValidation = loginValidation
</code></pre>
<p>&#x110;&#x1EC3; m&#xE0; n&#xF3; c&#xF3; th&#x1EC3; ho&#x1EA1;t &#x111;&#x1ED9;ng &#x111;&#x1B0;&#x1EE3;c ch&#xFA;ng ta c&#x1EA7;n ph&#x1EA3;i import <strong>loginValidation</strong> t&#x1EEB; file <strong>validation.js</strong> v&#xE0;o trong ph&#x1EA7;n khai b&#xE1;o tr&#x1B0;&#x1EDB;c &#x111;&#xF3; c&#x1EE7;a ch&#x1EE9;c n&#x103;ng &#x111;&#x103;ng k&#xFD;.<br>
<code>const {registerValidation, loginValidation} = require(&quot;../auth/validation&quot;)</code><br>
C&#xE1;c b&#x1EA1;n t&#x1EA1;o cho router <code>Post/login</code> trong router n&#xE0;y ch&#xFA;ng ta s&#x1EBD; s&#x1EED; d&#x1EE5;ng &#x111;&#x1EC3; x&#xE1;c nh&#x1EAD;n user, ki&#x1EC3;m tra email v&#xE0; password.<br>
Data &#x111;&#x1B0;&#x1EE3;c truy&#x1EC1;n v&#xE0;o &#x111;&#xF3; l&#xE0; req.body, n&#x1EBF;u g&#x1EB7;p l&#x1ED7;i th&#xEC; log ra th&#xF4;ng b&#xE1;o.</p>
<pre><code>router.post(&apos;/login&apos;, async function(req, res){
    // Validate user
    const{ error } = loginValidation(req.body);
     if(error) return res.status(400).send(error.details[0].message)
})
</code></pre>
<p><strong>Ch&#xFA;ng ta c&#xF9;ng xem th&#x1EED; n&#xF3; x&#xE1;c nh&#x1EAD;n &#x111;&#x1EA7;u v&#xE0;o khi login nh&#x1B0; th&#x1EBF; n&#xE0;o nh&#xE9;</strong><br>
Ch&#xFA;ng ta &#x111;&#x1EC3; &#xFD; trong password m&#xEC;nh ch&#x1EC9; vi&#x1EBF;t 3 k&#xED; t&#x1EF1; th&#xEC; n&#xF3; li&#x1EC1;n log ra th&#xF4;ng b&#xE1;o ngay, ch&#xFA;ng ta &#x111;&#xE3; y&#xEA;u c&#x1EA7;u l&#xE0; password ph&#x1EA3;i 6 k&#xED; t&#x1EF1; tr&#x1EDF; l&#xEA;n m&#x1EDB;i &#x111;&#xFA;ng.<br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1581844945/Untitled_xndnsq.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng NodeJS API X&#xE1;c Th&#x1EF1;c V&#x1EDB;i JWT"></p>
<h3 id="checkemailvpassword">Check email v&#xE0; password</h3>
<p>&#x110;&#x1EC3; c&#xF3; th&#x1EC3; &#x111;&#x103;ng nh&#x1EAD;p &#x111;&#x1B0;&#x1EE3;c th&#xEC; ch&#xFA;ng ta c&#x1EA7;n ph&#x1EA3;i ki&#x1EC3;m tra email v&#xE0; password m&#xEC;nh &#x111;&#xE3; &#x111;&#x1B0;&#x1EE3;c t&#x1EA1;o hay ch&#x1B0;a v&#xE0; &#x111;&#x103;ng nh&#x1EAD;p th&#xF4;ng tin c&#xF3; ch&#xED;nh x&#xE1;c kh&#xF4;ng.<br>
C&#x169;ng trong router  <code>Post /register</code> c&#xE1;c b&#x1EA1;n code th&#xEA;m m&#x1ED9;t &#x111;o&#x1EA1;n m&#xE3; &#x1EDF; d&#x1B0;&#x1EDB;i th&#x1EB1;ng x&#xE1;c nh&#x1EAD;n user &#x111;&#x1EC3; c&#xF3; th&#x1EC3; check email v&#xE0; password c&#xF3; ch&#xED;nh x&#xE1;c hay kh&#xF4;ng.<br>
Trong ph&#x1EA7;n <strong>ki&#x1EC3;m tra email</strong> c&#xE1;c b&#x1EA1;n s&#x1EBD; t&#xEC;m trong database c&#xF3; email n&#xE0;o tr&#xF9;ng v&#x1EDB;i email m&#xEC;nh nh&#x1EAD;p kh&#xF4;ng, khi ch&#xFA;ng ta s&#x1EED; d&#x1EE5;ng findOne th&#xEC; n&#xF3; s&#x1EBD; log ra to&#xE0;n d&#x1EEF; li&#x1EC7;u c&#x1EE7;a user c&#xF3; email tr&#xF9;ng v&#x1EDB;i email m&#xEC;nh nh&#x1EAD;p. N&#x1EBF;u email nh&#x1EAD;p sai th&#xEC; n&#xF3; s&#x1EBD; log ra th&#xF4;ng b&#xE1;o.<br>
Trong ph&#x1EA7;n <strong>ki&#x1EC3;m tra password</strong> th&#xEC; ch&#xFA;ng ta s&#x1EBD; nh&#x1EAD;p password &#x111;&#x103;ng nh&#x1EAD;p v&#xE0;o v&#xE0; m&#xE3; h&#xF3;a password &#x111;&#xF3; &#x111;i, sau &#x111;&#xF3; ki&#x1EC3;m tra password &#x111;&#xE3; &#x111;&#x1B0;&#x1EE3;c m&#xE3; h&#xF3;a c&#xF3; tr&#xF9;ng v&#x1EDB;i password c&#x169;ng &#x111;&#xE3; &#x111;&#x1B0;&#x1EE3;c m&#xE3; h&#xF3;a v&#xE0; l&#x1B0;u trong database ch&#x1B0;a. N&#x1EBF;u password nh&#x1EAD;p sai th&#xEC; n&#xF3; s&#x1EBD; log ra th&#xF4;ng b&#xE1;o.<br>
C&#xF2;n n&#x1EBF;u t&#x1EA5;t c&#x1EA3; c&#xE1;c tr&#x1B0;&#x1EDD;ng h&#x1EE3;p tr&#xEA;n t&#x1EEB; validate &#x111;&#x1EBF;n check email v&#xE0; password &#x111;&#x1EC1;u ch&#xED;nh x&#xE1;c th&#xEC; s&#x1EBD; log ra th&#xF4;ng b&#xE1;o &quot;B&#x1EA1;n &#x111;&#xE3; &#x111;&#x103;ng nh&#x1EAD;p th&#xE0;nh c&#xF4;ng&quot;.</p>
<pre><code>     // Ki&#x1EC3;m tra email
    const userLogin = await User.findOne({email: req.body.email});
    if(!userLogin) return res.status(400).send(&quot;Kh&#xF4;ng t&#xEC;m th&#x1EA5;y email&quot;)

     // Ki&#x1EC3;m tra password
    const passLogin = await bcrypt.compare(req.body.password, userLogin.password);
    if(!passLogin) return res.status(400).send(&quot;M&#x1EAD;t kh&#x1EA9;u kh&#xF4;ng h&#x1EE3;p l&#x1EC7;&quot;)

     res.send(&quot;B&#x1EA1;n &#x111;&#xE3; &#x111;&#x103;ng nh&#x1EAD;p th&#xE0;nh c&#xF4;ng&quot;)
</code></pre>
<p><strong>Ch&#xFA;ng ta c&#xF9;ng xem th&#x1EED; n&#x1EBF;u ch&#xFA;ng ta &#x111;&#x103;ng nh&#x1EAD;p ch&#xED;nh x&#xE1;c th&#xEC; n&#xF3; s&#x1EBD; hi&#x1EC3;n th&#x1ECB; nh&#x1B0; th&#x1EBF; n&#xE0;o nh&#xE9;, c&#xF2;n c&#xE1;c tr&#x1B0;&#x1EDD;ng h&#x1EE3;p kh&#xE1;c c&#xE1;c b&#x1EA1;n t&#x1EF1; test nha.</strong><br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1581846620/Untitled_dxc6b9.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng NodeJS API X&#xE1;c Th&#x1EF1;c V&#x1EDB;i JWT"></p>
<h2 id="xlxcthcbngjwt">X&#x1EED; L&#xFD; X&#xE1;c Th&#x1EF1;c B&#x1EB1;ng JWT</h2>
<p>JWT l&#xE0; g&#xEC; v&#xE0; c&#xE1;ch ho&#x1EA1;t &#x111;&#x1ED9;ng c&#x1EE7;a n&#xF3; nh&#x1B0; n&#xE0;o m&#xEC;nh &#x111;&#xE3; n&#xF3;i &#x1EDF; ph&#x1EA7;n m&#x1EDF; &#x111;&#x1EA7;u r&#x1ED3;i, gi&#x1EDD; m&#xEC;nh kh&#xF4;ng n&#xF3;i l&#x1EA1;i n&#x1EEF;a m&#xE0; b&#x1EAF;t tay v&#xE0;o l&#xE0;m lu&#xF4;n nha.<br>
Trong ph&#x1EA7;n x&#x1EED; l&#xFD; x&#xE1;c th&#x1EF1;c b&#x1EB1;ng jwt ch&#xFA;ng ta s&#x1EBD; chia l&#xE0;m 3 ph&#x1EA7;n:<br>
Ph&#x1EA7;n 1: T&#x1EA1;o Token.<br>
Ph&#x1EA7;n 2: Verify Token.</p>
<h3 id="totoken">T&#x1EA1;o Token</h3>
<p>&#x110;&#x1EC3; c&#xF3; th&#x1EC3; t&#x1EA1;o &#x111;&#x1B0;&#x1EE3;c token c&#xE1;c b&#x1EA1;n c&#x1EA7;n ph&#x1EA3;i khai b&#xE1;o module JWT m&#xE0; ch&#xFA;ng ta &#x111;&#xE3; c&#xE0;i &#x111;&#x1EB7;t &#x1EDF; tr&#xEA;n r&#x1ED3;i &#x1EA5;y.<br>
<code>const jwt = require(&quot;jsonwebtoken&quot;)</code><br>
V&#x1EAD;y b&#xE2;y gi&#x1EDD; l&#xE0;m th&#x1EBF; n&#xE0;o &#x111;&#x1EC3; c&#xF3; th&#x1EC3; t&#x1EA1;o v&#xE0; assign token. Trong router <code>Post/login</code> c&#xE1;c b&#x1EA1;n thay th&#x1EBF; cho m&#xEC;nh th&#xF4;ng b&#xE1;o n&#xE0;y <code>res.send(&quot;B&#x1EA1;n &#x111;&#xE3; &#x111;&#x103;ng nh&#x1EAD;p th&#xE0;nh c&#xF4;ng&quot;)</code> khi &#x111;&#x103;ng nh&#x1EAD;p th&#xE0;nh c&#xF4;ng. B&#x1EB1;ng m&#x1ED9;t &#x111;o&#x1EA1;n code d&#xF9;ng &#x111;&#x1EC3; t&#x1EA1;o m&#xE3; JWT v&#xE0; g&#x1EED;i v&#x1EC1; cho user.<br>
Trong file <strong>.env</strong> c&#xE1;c b&#x1EA1;n t&#x1EA1;o cho m&#xEC;nh m&#xE3; <strong>secretkey(SECRET_TOKEN)</strong>, m&#xE3; n&#xE0;y ph&#x1EA3;i b&#x1EA3;o m&#x1EAD;t tuy&#x1EC7;t &#x111;&#x1ED1;i n&#xEA;n m&#xEC;nh ph&#x1EA3;i l&#x1B0;u n&#xF3; v&#xE0; bi&#x1EBF;n m&#xF4;i tr&#x1B0;&#x1EDD;ng.<br>
Sau &#x111;&#xF3; ch&#xFA;ng ta c&#xF3; th&#x1EC3; add n&#xF3; v&#xE0;o header v&#x1EDB;i b&#x1EA5;t k&#xEC; lo&#x1EA1;i &#x111;&#x1ECB;nh danh n&#xE0;o m&#xE0; ch&#xFA;ng ta mong mu&#x1ED1;n. N&#xF3;i &#x111;&#x1A1;n gi&#x1EA3;n l&#xE0; token &#x111;&#x1B0;&#x1EE3;c t&#x1EA1;o s&#x1EBD; &#x111;&#x1B0;&#x1EE3;c l&#x1B0;u v&#xE0;o headers.</p>
<pre><code>    // K&#xFD; v&#xE0; t&#x1EA1;o token
   const token = jwt.sign({_id: userLogin._id}, process.env.SECRET_TOKEN)
   res.header(&quot;auth-token&quot;, token).send(token);
</code></pre>
<p><strong>Ch&#xFA;ng ta c&#xF9;ng xem th&#x1EED; n&#xF3; t&#x1EA1;o token nh&#x1B0; th&#x1EBF; n&#xE0;o nh&#xE9;.</strong><br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1581918503/Untitled_ocry60.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng NodeJS API X&#xE1;c Th&#x1EF1;c V&#x1EDB;i JWT"></p>
<p>Sau khi c&#xE1;c b&#x1EA1;n t&#x1EA1;o token xong b&#xE2;y gi&#x1EDD; c&#xE1;c b&#x1EA1;n c&#x1EA7;n ph&#x1EA3;i verify token.</p>
<h3 id="verifytoken">Verify Token</h3>
<p>Trong th&#x1B0; m&#x1EE5;c <strong>auth</strong> c&#xE1;c b&#x1EA1;n t&#x1EA1;o cho m&#xEC;nh th&#xEA;m file <strong>checkToken.js</strong> trong file n&#xE0;y c&#xE1;c b&#x1EA1;n s&#x1EBD; code cho m&#xEC;nh m&#x1ED9;t &#x111;o&#x1EA1;n m&#xE3; d&#xF9;ng &#x111;&#x1EC3; verify Token.</p>
<pre><code>const jwt = require(&quot;jsonwebtoken&quot;)

module.exports = function(req, res, next){
   const token = req.header(&apos;auth-token&apos;); // s&#x1EBD; g&#x1EED;i y&#xEA;u c&#x1EA7;u l&#xEA;n header &#x111;&#x1EC3; t&#xEC;m                                                   token ra r&#x1ED3;i verify. 
   // N&#x1EBF;u b&#x1EA1;n kh&#xF4;ng truy&#x1EC1;n l&#xEA;n token th&#xEC; n&#xF3; s&#x1EBD; g&#x1EED;i th&#xF4;ng b&#xE1;o 
   if(!token) return res.status(401).send(&quot;Vui l&#xF2;ng &#x111;&#x103;ng nh&#x1EAD;p &#x111;&#x1EC3; &#x111;&#x1B0;&#x1EE3;c truy c&#x1EAD;p&quot;)
   try{
        const checkToken = jwt.verify(token, process.env.SECRET_TOKEN) // ki&#x1EC3;m tra token
       req.user = checkToken //l&#x1B0;u token l&#x1EA1;i &#x111;&#x1EC3; c&#xF3; th&#x1EC3; ki&#x1EC3;m tra 
       next()
   }catch(err){
       res.status(400).send(&apos;Token kh&#xF4;ng h&#x1EE3;p l&#x1EC7;&apos;)// th&#xF4;ng b&#xE1;o l&#x1ED7;i khi b&#x1EA1;n nh&#x1EAD;p sai token.
   }
}

</code></pre>
<p>&#x110;&#x1EC3; c&#xF3; th&#x1EC3; s&#x1EED; d&#x1EE5;ng &#x111;&#x1B0;&#x1EE3;c c&#xE1;c b&#x1EA1;n c&#x1EA7;n ph&#x1EA3;i import file <strong>checkToken.js</strong> v&#xE0;o trong file <strong>index.js</strong>.<br>
<code>const verify = require(&quot;../auth/checkToken&quot;) </code><br>
C&#xE1;c b&#x1EA1;n t&#x1EA1;o cho m&#xEC;nh m&#x1ED9;t router <code>Get /</code> &#x111;&#x1EC3; c&#xF3; th&#x1EC3; t&#x1EA1;o cho n&#xF3; m&#x1ED9;t middleware d&#xF9;ng &#x111;&#x1EC3; x&#xE1;c th&#x1EF1;c token c&#xF3; h&#x1EE3;p l&#x1EC7; kh&#xF4;ng.</p>
<pre><code>router.get(&apos;/&apos;, verify, function(req, res){
    res.send(&quot;Ch&#xE0;o m&#x1EEB;ng b&#x1EA1;n &#x111;&#x1EBF;n v&#x1EDB;i website c&#x1EE7;a m&#xEC;nh. Ch&#xFA;c b&#x1EA1;n m&#x1ED9;t ng&#xE0;y vui v&#x1EBB;&quot;)
})
</code></pre>
<p><strong>Ch&#xFA;ng ta th&#x1EED; l&#x1EA5;y token &#x111;&#xE3; t&#x1EA1;o &#x1EDF; tr&#xEA;n &#x111;&#x1EC3; g&#x1ECD;i API <code>Get /</code></strong><br>
C&#xE1;i t&#xEA;n m&#xE0; m&#xEC;nh g&#x1EA1;ch ch&#xE2;n m&#xE0;u &#x111;&#x1ECF; &#x1EA5;y c&#xE1;c b&#x1EA1;n ph&#x1EA3;i nh&#x1EAD;p ch&#xED;nh x&#xE1;c nh&#x1B0; trong code nha<br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1581918417/Untitled_xyhngg.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng NodeJS API X&#xE1;c Th&#x1EF1;c V&#x1EDB;i JWT"></p>
<p><strong>Ch&#xFA;ng ta c&#xF9;ng test th&#xEA;m v&#xE0;i tr&#x1B0;&#x1EDD;ng h&#x1EE3;p kh&#xF4;ng truy&#x1EC1;n m&#xE3; token ho&#x1EB7;c g&#x1EED;i sai m&#xE3; token xem n&#xF3; nh&#x1B0; th&#x1EBF; n&#xE0;o nh&#xE9;</strong><br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1581919046/Untitled_ubdqmf.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng NodeJS API X&#xE1;c Th&#x1EF1;c V&#x1EDB;i JWT"></p>
<p>V&#x1EAD;y l&#xE0; xong r&#x1ED3;i nha, c&#xE1;c b&#x1EA1;n c&#xF3; th&#x1EC3; tham kh&#x1EA3;o code m&#xE0; m&#xEC;nh &#x111;&#xE3; push l&#xEA;n github <a href="https://github.com/long1211/API-Authentication-with-JWT">t&#x1EA1;i &#x111;&#xE2;y nha</a></p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h1 id="likt">L&#x1EDD;i K&#x1EBF;t</h1>
<p>V&#x1EAD;y L&#xE0; Xong b&#xE0;i H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng NodeJS API X&#xE1;c Th&#x1EF1;c V&#x1EDB;i JWT r&#x1ED3;i nh&#xE9;. M&#xEC;nh mong mu&#x1ED1;n sau b&#xE0;i topic n&#xE0;y c&#xE1;c b&#x1EA1;n c&#xF3; th&#x1EC3; n&#x1EAF;m v&#x1EEF;ng th&#xEA;m v&#x1EC1; c&#xE1;c ki&#x1EBF;n th&#x1EE9;c NodeJS, Express, MongoDB v&#xE0; Authentication, JWT,... V&#xE0; c&#xF3; th&#x1EC3; t&#x1EF1; tay m&#xEC;nh l&#xE0;m nh&#x1EEF;ng project kh&#xF4;ng c&#x1EA7;n ph&#x1EA3;i qu&#xE1; &#x111;&#x1EB7;c bi&#x1EC7;t nh&#x1B0;ng n&#xF3; do ch&#xED;nh b&#x1EA1;n l&#xE0;m th&#xEC; c&#x169;ng coi nh&#x1B0; l&#xE0; th&#xE0;nh qu&#x1EA3; trong qu&#xE1; tr&#xEC;nh b&#x1EA1;n h&#x1ECD;c &#x111;&#x1B0;&#x1EE3;c.</p>
<p><strong>N&#x1EBF;u c&#xE1;c b&#x1EA1;n c&#x1EA3;m th&#x1EA5;y b&#xE0;i vi&#x1EBF;t c&#x1EE7;a m&#xEC;nh hay th&#xEC; c&#xE1;c b&#x1EA1;n c&#xF3; th&#x1EC3; &#x1EE7;ng h&#x1ED9; m&#xEC;nh &#x111;&#x1EC3; m&#xEC;nh c&#xF3; th&#xEA;m &#x111;&#x1ED9;ng l&#x1EF1;c &#x111;&#x1EC3; ra nh&#x1EEF;ng b&#xE0;i topic hay v&#xE0; ch&#x1EA5;t l&#x1B0;&#x1EE3;ng h&#x1A1;n &#x1EE7;ng h&#x1ED9; m&#xEC;nh <a href="https://vrdonate.vn/thanhlongdev">t&#x1EA1;i &#x111;&#xE2;y nha</a>.</strong></p>
<p><em><strong>Ch&#xFA;c C&#xE1;c B&#x1EA1;n Th&#xE0;nh C&#xF4;ng!!</strong></em></p>
<!--kg-card-end: markdown--><!--kg-card-begin: html--><iframe src="https://www.facebook.com/plugins/like.php?href=https%3A%2F%2Fwww.thanhlongdev.com%2Fhuong-dan-xay-dung-nodejs-api-xac-thuc-voi-jwt%2F&amp;width=450&amp;layout=standard&amp;action=like&amp;size=large&amp;share=true&amp;height=35&amp;appId=2794898430534168" width="450" height="35" style="border:none;overflow:hidden" scrolling="no" frameborder="0" allowtransparency="true" allow="encrypted-media"></iframe><!--kg-card-end: html--><!--kg-card-begin: html--><div class="fb-comments" data-href="https://www.thanhlongdev.com/huong-dan-xay-dung-nodejs-api-xac-thuc-voi-jwt/" data-width="100%" data-numposts="10"></div><!--kg-card-end: html-->]]></content:encoded></item><item><title><![CDATA[Hướng Dẫn Xây Dựng Web CRUD Books Với NodeJS, Express và MongoDB]]></title><description><![CDATA[<!--kg-card-begin: markdown--><h1 id="giithiuchung">Gi&#x1EDB;i Thi&#x1EC7;u Chung</h1>
<p>H&#xF4;m nay m&#xEC;nh s&#x1EBD; h&#x1B0;&#x1EDB;ng d&#x1EAB;n c&#xE1;c b&#x1EA1;n x&#xE2;y d&#x1EF1;ng m&#x1ED9;t web CRUD Books v&#x1EDB;i NodeJS, Express v&#xE0; MongoDB.<br>
<strong>CRUD</strong></p>]]></description><link>https://www.thanhlongdev.com/huong-dan-xay-dung-web-crud-books-voi-nodejs-express-mongodb/</link><guid isPermaLink="false">5e32daf225f2340001eec2db</guid><category><![CDATA[Lập Trình Web]]></category><dc:creator><![CDATA[Đặng Thanh Long]]></dc:creator><pubDate>Thu, 06 Feb 2020 09:33:30 GMT</pubDate><media:content url="https://digitalpress.fra1.cdn.digitaloceanspaces.com/4tg23ij/2020/02/ukalsvubeuwog27fzguz-1.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h1 id="giithiuchung">Gi&#x1EDB;i Thi&#x1EC7;u Chung</h1>
<img src="https://digitalpress.fra1.cdn.digitaloceanspaces.com/4tg23ij/2020/02/ukalsvubeuwog27fzguz-1.jpg" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Web CRUD Books V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB"><p>H&#xF4;m nay m&#xEC;nh s&#x1EBD; h&#x1B0;&#x1EDB;ng d&#x1EAB;n c&#xE1;c b&#x1EA1;n x&#xE2;y d&#x1EF1;ng m&#x1ED9;t web CRUD Books v&#x1EDB;i NodeJS, Express v&#xE0; MongoDB.<br>
<strong>CRUD l&#xE0; g&#xEC; ?</strong><br>
CRUD c&#xF3; ngh&#x129;a l&#xE0; Create, Read, Update v&#xE0; Delete. B&#xE0;i vi&#x1EBF;t n&#xE0;y m&#xEC;nh s&#x1EBD; h&#x1B0;&#x1EDB;ng d&#x1EAB;n c&#xE1;c b&#x1EA1;n t&#x1EA1;o, &#x111;&#x1ECD;c, c&#x1EAD;p nh&#x1EAD;t v&#xE0; x&#xF3;a d&#x1EEF; li&#x1EC7;u cu&#x1ED1;n s&#xE1;ch,..</p>
<h1 id="mcchbivit">M&#x1EE5;c &#x110;&#xED;ch B&#xE0;i Vi&#x1EBF;t</h1>
<p>Gi&#xFA;p c&#xE1;c b&#x1EA1;n &#xF4;n l&#x1EA1;i c&#xE1;c ki&#x1EBF;n th&#x1EE9;c v&#x1EC1; NodeJS, c&#xE1;ch x&#xE2;y d&#x1EF1;ng c&#x169;ng nh&#x1B0; truy v&#x1EA5;n database MongoDB.<br>
N&#x1EAF;m v&#x1EEF;ng c&#xE1;c ki&#x1EBF;n th&#x1EE9;c v&#xE0; c&#xE1;ch ho&#x1EA1;t &#x111;&#x1ED9;ng v&#x1EC1; Get, Post request.<br>
Sau b&#xE0;i vi&#x1EBF;t n&#xE0;y c&#xE1;c b&#x1EA1;n c&#xF3; th&#x1EC3; t&#x1EF1; x&#xE2;y d&#x1EF1;ng cho m&#xEC;nh m&#x1ED9;t web app t&#x1B0;&#x1A1;ng t&#x1EF1; nh&#x1B0;: todo list,...&#x110;&#xF3; c&#x169;ng l&#xE0; m&#x1ED9;t c&#xE1;ch gi&#xFA;p c&#xE1;c b&#x1EA1;n c&#xF3; th&#x1EC3; n&#x1EAF;m v&#x1EEF;ng c&#xE1;c ki&#x1EBF;n th&#x1EE9;c &#x111;&#x1B0;&#x1EE3;c h&#x1ECD;c.<br>
M&#xEC;nh mong mu&#x1ED1;n c&#xE1;c b&#x1EA1;n &#x111;&#x1ECD;c b&#xE0;i m&#x1ED9;t c&#xE1;ch t&#x1EC9; m&#x1EC9;, &#x111;&#x1ECD;c kh&#xF4;ng l&#x1B0;&#x1EDB;t nha.<br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1581689929/crud-express-mongo_nb5lgy.png" width="700" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Web CRUD Books V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB"></p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h1 id="btuthino">B&#x1EAF;t &#x110;&#x1EA7;u Th&#xF4;i N&#xE0;o</h1>
<h2 id="lntngvwebcrudbooks">L&#xEA;n &#xDD; T&#x1B0;&#x1EDF;ng V&#x1EC1; Web CRUD Books</h2>
<p>Tr&#x1B0;&#x1EDB;c khi c&#xE1;c b&#x1EA1;n l&#xE0;m m&#x1ED9;t c&#xE1;i g&#xEC; &#x111;&#xF3; th&#xEC; tr&#x1B0;&#x1EDB;c h&#x1EBF;t ph&#x1EA3;i h&#xEC;nh th&#xE0;nh &#xFD; t&#x1B0;&#x1EDF;ng, sau &#x111;&#xF3; tri&#x1EC3;n khai &#xFD; t&#x1B0;&#x1EDF;ng. &#x110;i&#x1EC1;u n&#xE0;y gi&#xFA;p c&#xE1;c b&#x1EA1;n l&#xE0;m vi&#x1EC7;c m&#x1ED9;t c&#xE1;ch c&#xF3; logic v&#xE0; khoa h&#x1ECD;c h&#x1A1;n. Tr&#x1B0;&#x1EDB;c h&#x1EBF;t m&#xE0; ch&#xFA;ng ta b&#x1EAF;t tay v&#xE0;o code th&#xEC; m&#xEC;nh s&#x1EBD; gi&#xFA;p c&#xE1;c b&#x1EA1;n n&#x1EAF;m r&#xF5; h&#x1A1;n &#xFD; t&#x1B0;&#x1EDF;ng m&#xEC;nh c&#x1EA7;n l&#xE0;m nha. &#xDD; t&#x1B0;&#x1EDF;ng c&#xE1;i n&#xE0;y c&#x169;ng &#x111;&#x1A1;n gi&#x1EA3;n th&#xF4;i nha.<br>
Ch&#xFA;ng ta mu&#x1ED1;n t&#x1EA1;o book th&#xEC; s&#x1EBD; t&#x1EA1;o ra c&#xE1;c tr&#x1B0;&#x1EDD;ng khi m&#xEC;nh nh&#x1EAD;p d&#x1EEF; li&#x1EC7;u v&#xE0;o th&#xEC; s&#x1EBD; l&#x1B0;u v&#xE0;o database.<br>
Mu&#x1ED1;n hi&#x1EC3;n th&#x1ECB; c&#xE1;c book m&#xE0; m&#xEC;nh &#x111;&#xE3; t&#x1EA1;o th&#xEC; ch&#xFA;ng ta s&#x1EBD; find d&#x1EEF; li&#x1EC7;u trong database sau &#x111;&#xF3; hi&#x1EC3;n th&#x1ECB; ra m&#xE0;n h&#xEC;nh.<br>
Mu&#x1ED1;n c&#x1EAD;p nh&#x1EAD;t book ch&#xFA;ng ta s&#x1EED; d&#x1EE5;ng ID &#x111;&#x1EC3; c&#x1EAD;p nh&#x1EAD;t nha. M&#x1ED7;i book s&#x1EBD; c&#xF3; m&#x1ED7;i id ri&#xEA;ng ch&#xFA;ng ta m&#xE0; mu&#x1ED1;n ch&#x1EC9;nh s&#x1EED;a ch&#x1EC9; c&#x1EA7;n find ID book c&#x1EA7;n ch&#x1EC9;nh s&#x1EED;a d&#x1EEF; li&#x1EC7;u r&#x1ED3;i sau &#x111;&#xF3; l&#x1B0;u l&#x1EA1;i database.<br>
C&#xF2;n mu&#x1ED1;n x&#xF3;a th&#xEC; ch&#x1EC9; c&#x1EA7;n nh&#x1EAD;p ID book mu&#x1ED1;n x&#xF3;a sau &#x111;&#xF3; x&#xF3;a book &#x111;&#xF3; kh&#x1ECF;i database th&#xF4;i.<br>
<em>&#x1EDE; &#x111;&#xE2;y m&#xEC;nh ch&#x1EC9; n&#xF3;i s&#x1A1; qua th&#xF4;i &#x111;&#x1EC3; cho c&#xE1;c b&#x1EA1;n c&#xF3; th&#x1EC3; h&#xEC;nh dung ra &#x111;&#x1B0;&#x1EE3;c m&#xEC;nh c&#x1EA7;n l&#xE0;m g&#xEC; th&#xF4;i nha.</em></p>
<h2 id="citvthitlp">C&#xE0;i &#x110;&#x1EB7;t V&#xE0; Thi&#x1EBF;t L&#x1EAD;p</h2>
<p>Tr&#x1B0;&#x1EDB;c ti&#xEA;n c&#xE1;c b&#x1EA1;n t&#x1EA1;o cho m&#xEC;nh m&#x1ED9;t folder trong folder &#x111;&#xF3; l&#xE0; n&#x1A1;i ch&#x1EE9;a c&#xE1;c th&#x1B0; m&#x1EE5;c v&#xE0; ch&#x1B0;&#x1A1;ng tr&#xEC;nh m&#xE0; ch&#xFA;ng ta d&#xF9;ng &#x111;&#x1EC3; vi&#x1EBF;t cho &#x1EE9;ng d&#x1EE5;ng CRUD books.<br>
<strong>C&#xE0;i &#x111;&#x1EB7;t c&#xE1;c module &#x111;&#x1EC3; thi&#x1EBF;t l&#x1EAD;p &#x1EE9;ng d&#x1EE5;ng</strong><br>
&#x110;&#x1EC3; m&#xE0; c&#xE0;i c&#xE1;c module tr&#x1B0;&#x1EDB;c h&#x1EBF;t c&#xE1;c b&#x1EA1;n ph&#x1EA3;i c&#xE0;i &#x111;&#x1EB7;t NodeJS <a href="https://nodejs.org/en/download/">t&#x1EA1;i &#x111;&#xE2;y</a>.</p>
<ul>
<li><strong>npm install --save express-generator</strong><br>
Module n&#xE0;y n&#xF3; s&#x1EBD; gi&#xFA;p ch&#xFA;ng ta t&#x1EA1;o nhanh khung s&#x1B0;&#x1EDD;n cho &#x1EE9;ng d&#x1EE5;ng.</li>
<li><strong>express --view=pug</strong><br>
N&#xF3; s&#x1EBD; t&#x1EA1;o cho c&#xE1;c b&#x1EA1;n ph&#x1EA7;n view engine v&#xE0; &#x111;&#x1B0;&#x1EE3;c setup l&#xE0; Pug.</li>
<li><strong>npm install nodemon --save</strong><br>
T&#x1EF1; &#x111;&#x1ED9;ng reload l&#x1EA1;i server khi b&#x1EA1;n thay &#x111;&#x1ED5;i code. &#x110;&#x1EC3; kh&#x1EDF;i ch&#x1EA1;y server c&#xE1;c b&#x1EA1;n th&#xEA;m <code>&quot;devStart&quot;: &quot;nodemon app.js&quot;</code> v&#xE0;o file package.json nha. C&#xE1;c b&#x1EA1;n m&#x1EDF; terminal l&#xEA;n sau &#x111;&#xF3; g&#xF5; <code>npm run devStart</code> &#x111;&#x1EC3; kh&#x1EDF;i ch&#x1EA1;y server nha.</li>
<li><strong>npm install mongoose --save</strong><br>
Mongoose l&#xE0; m&#x1ED9;t Object Document Mapper (ODM). &#x110;i&#x1EC1;u n&#xE0;y c&#xF3; ngh&#x129;a l&#xE0; Mongoose cho ph&#xE9;p b&#x1EA1;n &#x111;&#x1ECB;nh ngh&#x129;a c&#xE1;c object (&#x111;&#x1ED1;i t&#x1B0;&#x1EE3;ng) v&#x1EDB;i m&#x1ED9;t schema &#x111;&#x1B0;&#x1EE3;c &#x111;&#x1ECB;nh ngh&#x129;a r&#xF5; r&#xE0;ng.</li>
<li><strong>npm install dotenv --save</strong><br>
Dotenv l&#xE0; m&#x1ED9;t bi&#x1EBF;n m&#xF4;i tr&#x1B0;&#x1EDD;ng d&#xF9;ng &#x111;&#x1EC3; b&#x1EA3;o m&#x1EAD;t c&#xE1;c th&#xF4;ng tin quan tr&#x1ECD;ng nh&#x1B0; username, password, url database,...N&#x1EBF;u ch&#xFA;ng ta kh&#xF4;ng l&#x1B0;u nh&#x1EEF;ng th&#xF4;ng tin m&#x1EAD;t v&#xE0;o file .env th&#xEC; khi push source code l&#xEA;n github th&#xEC; ai c&#x169;ng c&#xF3; th&#x1EC3; v&#xE0;o xem &#x111;&#x1B0;&#x1EE3;c v&#xE0; ai c&#x169;ng bi&#x1EBF;t username, password th&#xEC; s&#x1EBD; b&#x1ECB; ng&#x1B0;&#x1EDD;i kh&#xE1;c chi&#x1EBF;m &#x111;o&#x1EA1;t v&#xE0; &#x111;&#xE1;nh c&#x1EAF;p t&#xE0;i li&#x1EC7;u r&#x1EA5;t l&#xE0; nguy hi&#x1EC3;m nha.</li>
</ul>
<h1 id="btucodethilo">B&#x1EAF;t &#x110;&#x1EA7;u Code Th&#xF4;i L&#xE0;o</h1>
<h2 id="thitlpwebserver">Thi&#x1EBF;t L&#x1EAD;p Web Server</h2>
<p>Trong file app.js c&#xE1;c b&#x1EA1;n b&#x1ECF; cho m&#xEC;nh router user v&#xE0; t&#x1EA1;o c&#x1ED5;ng port cho web server. Trong folder routes c&#xE1;c b&#x1EA1;n c&#x169;ng b&#x1ECF; cho m&#xEC;nh file <code>user.js</code> nha, &#x111;&#xF3; l&#xE0; c&#xE1;c file m&#x1EB7;c &#x111;&#x1ECB;nh khi m&#xEC;nh ch&#x1EA1;y <code>npm install --save express-generator</code> kh&#xF4;ng c&#x1EA7;n thi&#x1EBF;t th&#xEC; m&#xEC;nh b&#x1ECF; nha.</p>
<pre><code>var createError = require(&apos;http-errors&apos;);
var express = require(&apos;express&apos;);
var path = require(&apos;path&apos;);
var cookieParser = require(&apos;cookie-parser&apos;);
var logger = require(&apos;morgan&apos;);

var port = 5555;
var indexRouter = require(&apos;./routes/index&apos;);
var app = express();

// view engine setup
app.set(&apos;views&apos;, path.join(__dirname, &apos;views&apos;));
app.set(&apos;view engine&apos;, &apos;pug&apos;);

app.use(logger(&apos;dev&apos;));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, &apos;public&apos;)));

// setup router
app.use(&apos;/&apos;, indexRouter);

// catch 404 and forward to error handler
.........
.........
.........

// error handler
.........
.........
.........
app.listen(port,function(){
  console.log(&quot;Server listening connect port&quot; + port)
})
module.exports = app;
</code></pre>
<p>Trong th&#x1B0; m&#x1EE5;c router c&#xF3; file index.js, c&#xE1;c b&#x1EA1;n t&#x1EA1;o cho n&#xF3; m&#x1ED9;t Route handlers v&#xE0; th&#x1EED; ch&#x1EA1;y sever xem sau. M&#x1EE5;c &#x111;&#xED;ch &#x111;&#x1EC3; c&#xE1;c b&#x1EA1;n test xem server c&#xF3; ch&#x1EA1;y kh&#xF4;ng nha.</p>
<pre><code>router.get(&apos;/&apos;,function(req, res, next){
res.send(&apos;Hello Everyone&apos;)
})
</code></pre>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1583503302/Untitled_bxahqg.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Web CRUD Books V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB">
<h2 id="thitlpdatabase">Thi&#x1EBF;t L&#x1EAD;p Database</h2>
<p>C&#xE0;i &#x111;&#x1EB7;t mongodb download <a href="https://docs.mongodb.com/manual/administration/install-community/">t&#x1EA1;i &#x111;&#xE2;y</a>, c&#xE1;c b&#x1EA1;n t&#x1EA1;o cho m&#xEC;nh m&#x1ED9;t file <code>.env</code> b&#xEA;n trong th&#x1B0; m&#x1EE5;c g&#x1ED1;c nha. Trong file n&#xE0;y c&#xE1;c b&#x1EA1;n t&#x1EA1;o m&#x1ED9;t &#x111;&#x1B0;&#x1EDD;ng d&#x1EAB;n l&#xE0; <code>DB_URL=mongodb://localhost/CRUD_books</code><br>
Trong file app.js c&#xE1;c b&#x1EA1;n khai b&#xE1;o module dotenv v&#x1EDB;i module mongoose v&#xE0; t&#x1EA1;o &#x111;&#x1B0;&#x1EDD;ng d&#x1EAB;n mongodb.<br>
// Khai b&#xE1;o dotenv<br>
<code>require(&apos;dotenv&apos;).config()</code><br>
// path database<br>
<code>var mongoose = require(&apos;mongoose&apos;);</code><br>
<code>mongoose.connect(process.env.DB_URL,{useNewUrlParser:true, useUnifiedTopology: true });</code><br>
B&#xE2;y gi&#x1EDD; m&#xE0; c&#xE1;c b&#x1EA1;n b&#x1EA1;n mu&#x1ED1;n ch&#x1EA1;y &#x111;&#x1B0;&#x1EE3;c server th&#xEC; ph&#x1EA3;i kh&#x1A1;i ch&#x1EA1;y database nha.<br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1581001869/1_m6u6fk_rmuxe6.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Web CRUD Books V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB"></p>
<h2 id="nhnghaccschemabookschomongoose">&#x110;&#x1ECB;nh Ngh&#x129;a C&#xE1;c Schema Books Cho Mongoose</h2>
<p>B&#xEA;n trong th&#x1B0; m&#x1EE5;c g&#x1ED1;c c&#xE1;c b&#x1EA1;n t&#x1EA1;o cho m&#xEC;nh th&#x1B0; m&#x1EE5;c <code>modal</code> b&#xEA;n trong th&#x1B0; m&#x1EE5;c  <code>modal</code> c&#xE1;c b&#x1EA1;n t&#x1EA1;o cho m&#xEC;nh file <code>book.modal.js</code>.<br>
Trong file <code>book.modal.js</code> c&#x1EA7;n t&#x1EA1;o m&#x1ED9;t &#x111;&#x1ED1;i t&#x1B0;&#x1EE3;ng <code>book</code> v&#xE0; s&#x1EBD; ch&#x1EE9;a ba thu&#x1ED9;c t&#xED;nh l&#xE0; <code>title</code>, <code>description</code> v&#xE0; <code>author</code>.</p>
<pre><code>var mongoose = require(&apos;mongoose&apos;);
var book = new mongoose.Schema({
    title: { type: String, required: true },
    description: { type: String, required: true },
    author: { type: String, required: true }
})
// Bi&#xEA;n d&#x1ECB;ch m&#xF4; h&#xEC;nh t&#x1EEB; schema
module.exports = mongoose.model(&apos;books&apos;, book);
</code></pre>
<p>Tham s&#x1ED1; th&#x1EE9; nh&#x1EA5;t l&#xE0; t&#xEA;n ri&#xEA;ng cho collection s&#x1EAF;p &#x111;&#x1B0;&#x1EE3;c t&#x1EA1;o ra cho m&#xF4; h&#xEC;nh c&#x1EE7;a b&#x1EA1;n, v&#xE0; tham s&#x1ED1; th&#x1EE9; hai l&#xE0; schema m&#xE0; b&#x1EA1;n mu&#x1ED1;n d&#xF9;ng &#x111;&#x1EC3; t&#x1EA1;o ra m&#xF4; h&#xEC;nh.</p>
<h2 id="nhnghaccrouterchocrudbooks">&#x110;&#x1ECB;nh Ngh&#x129;a C&#xE1;c Router Cho CRUD Books</h2>
<p>Trong file <code>index.js</code> n&#x1EB1;m b&#xEA;n trong th&#x1B0; m&#x1EE5;c routes, t&#x1EA1;o c&#xE1;c ph&#x1B0;&#x1A1;ng th&#x1EE9;c &#x111;&#x1EC3; x&#x1EED; l&#xFD; c&#xE1;c ho&#x1EA1;t &#x111;&#x1ED9;ng CRUD. C&#xE1;c b&#x1EA1;n khai b&#xE1;o cho m&#xEC;nh modal c&#x1EE7;a Books nha.<br>
<code>var Book = require(&apos;../modal/book.modal&apos;)</code></p>
<h3 id="tobooks">T&#x1EA1;o Books</h3>
<p><strong>Giao di&#x1EC7;n &#x111;&#x1EC3; t&#x1EA1;o book</strong><br>
Tr&#x1B0;&#x1EDB;c ti&#xEA;n &#x111;&#x1EC3; t&#x1EA1;o book c&#xE1;c b&#x1EA1;n c&#x1EA7;n ph&#x1EA3;i c&#xF3; m&#x1ED9;t giao di&#x1EC7;n &#x111;&#x1EC3; &#x111;i&#x1EC1;n c&#xE1;c th&#xF4;ng tin c&#x1EA7;n c&#xF3; &#x111;&#x1EC3; t&#x1EA1;o book.<br>
Trong th&#x1B0; m&#x1EE5;c <code>views</code> c&#xF3; file <code>index.pug</code>. Trong file &#x111;&#xF3; c&#xE1;c b&#x1EA1;n t&#x1EA1;o cho m&#xEC;nh b&#x1ED9; khung g&#x1ED3;m c&#xF3; form c&#xF3; ch&#x1EE9;a c&#xE1;c th&#x1EBB; label, input &#x111;&#x1EC3; &#x111;i&#x1EC1;n c&#xE1;c th&#xF4;ng tin c&#x1EA7;n c&#xF3; &#x111;&#x1EC3; t&#x1EA1;o book bao g&#x1ED3;m: title, description v&#xE0; author.<br>
C&#xE1;c b&#x1EA1;n nh&#x1EDB; &#x111;i&#x1EC1;n &#x111;&#xFA;ng c&#xE1;c gi&#xE1; tr&#x1ECB; trong thu&#x1ED9;c t&#xED;nh name trong th&#x1EBB; input tr&#xF9;ng v&#x1EDB;i c&#xE1;c thu&#x1ED9;c t&#xED;nh trong file modal nha.</p>
<pre><code>extends layout

block content
  div.title-book
    h1 CRUD BOOKS    

  //- Create books
  div.content_book
    h2 Create Books
    form(action=&quot;/&quot; method=&quot;POST&quot;)
      div
        label(for=&quot;tittle&quot;) Title
        input(type=&quot;text&quot; name=&quot;title&quot; required=&quot;required&quot;)
      div 
        label(for=&quot;tittle&quot;) Description
        input(type=&quot;text&quot; name=&quot;description&quot; required=&quot;required&quot;)
      div 
        label(for=&quot;tittle&quot;) Author
        input(type=&quot;text&quot; name=&quot;author&quot; required=&quot;required&quot;)
      div  
       button(type=&quot;submit&quot;) Create

</code></pre>
<p><strong>Routes Get/</strong><br>
&#x110;&#x1EC3; m&#xE0; c&#xF3; th&#x1EC3; load &#x111;&#x1B0;&#x1EE3;c giao di&#x1EC7;n ra v&#xE0; t&#x1EA1;o book th&#xEC; ch&#xFA;ng ta c&#x1EA7;n ph&#x1EA3;i render n&#xF3; ra b&#x1EB1;ng ph&#x1B0;&#x1A1;ng th&#x1EE9;c <code>Get</code> &#x111;&#xFA;ng kh&#xF4;ng n&#xE0;o.</p>
<pre><code>router.get(&apos;/&apos;, function (req, res, next) {
  res.render(&apos;index&apos;)
});
</code></pre>
<p><strong>Routes Post/</strong><br>
Sau khi ch&#xFA;ng ta &#x111;&#xE3; t&#x1EA1;o giao di&#x1EC7;n cho n&#xF3; xong r&#x1ED3;i th&#xEC; ti&#x1EBF;p &#x111;&#x1EBF;n. Trong th&#x1B0; m&#x1EE5;c <code>routes</code> c&#xF3; file <code>index.js</code>. C&#xE1;c b&#x1EA1;n t&#x1EA1;o cho m&#xEC;nh ph&#x1B0;&#x1A1;ng th&#x1EE9;c <code>POST</code> &#x111;&#x1EC3; khi submit d&#x1EEF; li&#x1EC7;u th&#xEC; n&#xF3; s&#x1EBD; &#x111;&#x1B0;&#x1EE3;c g&#x1EED;i l&#xEA;n server v&#xE0; l&#x1B0;u trong database nha.</p>
<pre><code>// Create books
router.post(&apos;/&apos;, function (req, res, next) {
  var newbook = new Book()
  newbook.title = req.body.title;
  newbook.description = req.body.description;
  newbook.author = req.body.author;
  newbook.save().then(function (err) {
    if (err) { console.log(err) }
  })
  res.redirect(&apos;/&apos;)
})
</code></pre>
<p>M&#xEC;nh gi&#x1EA3;i th&#xED;ch &#x1EDF; &#x111;&#xE2;y m&#x1ED9;t ch&#xFA;t l&#xE0; khi m&#xEC;nh post ng&#x1EA7;m d&#x1EEF; li&#x1EC7;u &#x111;&#x1EC3; t&#x1EA1;o book th&#xEC; n&#xF3; s&#x1EBD; t&#x1EA1;o ra m&#x1ED9;t c&#xE1;i object r&#x1ED7;ng v&#xE0; g&#xE1;n v&#xE0;o bi&#x1EBF;n <strong>newbook</strong>, object r&#x1ED7;ng n&#xE0;y &#x111;&#x1B0;&#x1EE3;c t&#x1EA1;o ra t&#x1EEB; th&#x1EB1;ng <strong>new</strong> th&#xEC; trong object n&#xE0;y s&#x1EBD; ch&#x1EE9;a c&#xE1;c title, description v&#xE0; author m&#xE0; ch&#xFA;ng ta &#x111;&#xE3; req.body &#x111;&#x1EC3; truy xu&#x1EA5;t d&#x1EEF; li&#x1EC7;u. Sau &#x111;&#xF3; l&#x1B0;u n&#xF3; v&#xE0;o database.<br>
<strong>B&#xE2;y gi&#x1EDD; ch&#xFA;ng ta c&#xF9;ng xem th&#x1EED; giao di&#x1EC7;n v&#xE0; nguy&#xEA;n l&#xFD; ho&#x1EA1;t &#x111;&#x1ED9;ng c&#xF3; &#x111;&#xFA;ng nh&#x1B0; ch&#xFA;ng ta mong &#x111;&#x1EE3;i kh&#xF4;ng nha.</strong><br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1583503972/Untitled_doewh2.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Web CRUD Books V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB"></p>
<p>Th&#xEC; nh&#x1B0; ch&#xFA;ng ta &#x111;&#xE3; th&#x1EA5;y th&#xEC; giao di&#x1EC5;n n&#xF3; kh&#xE1; chi l&#xE0; c&#x1EE7; chu&#x1ED1;i b&#x1EDF;i v&#xEC; pug n&#xF3; c&#x169;ng gi&#x1ED1;ng nh&#x1B0; html th&#xF4;i n&#xF3; c&#x169;ng ch&#x1EC9; x&#xE2;y khung s&#x1B0;&#x1EDD;n l&#xE0; ch&#xED;nh th&#xF4;i c&#xF2;n mu&#x1ED1;n &#x111;&#x1EB9;p th&#xEC; ph&#x1EA3;i css cho n&#xF3;. Ph&#x1EA7;n css m&#xEC;nh s&#x1EBD; l&#xE0;m &#x1EDF; ph&#x1EA7;n sau nha.<br>
<strong>B&#xE2;y gi&#x1EDD; c&#xE1;c b&#x1EA1;n xem th&#x1EED; trong database n&#xF3; c&#xF3; l&#x1B0;u l&#x1EA1;i kh&#xF4;ng nha.</strong> N&#x1EBF;u n&#xF3; c&#xF3; l&#x1B0;u th&#xEC; xem nh&#x1B0; ph&#x1EA7;n t&#x1EA1;o book coi nh&#x1B0; ho&#xE0;n th&#xE0;nh &#x111;&#x1B0;&#x1EE3;c 90% r&#x1ED3;i gi&#x1EDD; ch&#x1EC9; c&#xF2;n css cho n&#xF3; th&#xF4;i l&#xE0; &#x1ED5;n &#xE1;p ngay.<br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1583504109/Untitled_ciqmqm.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Web CRUD Books V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB"></p>
<h3 id="cbooks">&#x110;&#x1ECD;c Books</h3>
<p>&#x110;&#x1ECD;c books c&#xF3; ngh&#x129;a l&#xE0; ch&#xFA;ng ta in ra c&#xE1;c d&#x1EEF; li&#x1EC7;u c&#x1EE7;a books m&#xE0; m&#xEC;nh nh&#x1EAD;p v&#xE0; l&#x1B0;u trong database nh&#x1B0;: title, description, author.<br>
<strong>Routes Get/</strong><br>
C&#xE1;c b&#x1EA1;n mu&#x1ED1;n hi&#x1EC3;n th&#x1ECB; ra c&#xE1;c d&#x1EEF; li&#x1EC7;u c&#x1EE7;a book th&#xEC; ch&#xFA;ng ta s&#x1EED; d&#x1EE5;ng ph&#x1B0;&#x1A1;ng th&#x1EE9;c <code>Get</code> . Ch&#xFA;ng ta v&#x1EEB;a Get giao di&#x1EC7;n c&#x169;ng v&#x1EEB;a Get ra d&#x1EEF; li&#x1EC7;u.<br>
C&#xE1;c b&#x1EA1;n find d&#x1EEF; li&#x1EC7;u book trong database ra nha. S&#x1EED; d&#x1EE5;ng async, await &#x111;&#x1EC3; find d&#x1EEF; li&#x1EC7;u.<br>
Async await m&#x1EE5;c &#x111;&#xED;ch ch&#xED;nh c&#x1EE7;a n&#xF3; l&#xE0; chuy&#x1EC3;n b&#x1EA5;t &#x111;&#x1ED3;ng b&#x1ED9; th&#xE0;nh &#x111;&#x1ED3;ng b&#x1ED9;, n&#xF3; s&#x1EBD; ch&#x1EA1;y t&#x1EEB; tr&#xEA;n xu&#x1ED1;ng d&#x1B0;&#x1EDB;i, n&#xF3; s&#x1EBD; find d&#x1EEF; li&#x1EC7;u r&#x1ED3;i m&#x1EDB;i &#x111;&#x1EBF;n vi&#x1EC7;c render.<br>
N&#xEA;n c&#xE1;c b&#x1EA1;n g&#xE1;n cho n&#xF3; m&#x1ED9;t bi&#x1EBF;n &#x111;&#x1EC3; c&#xF3; th&#x1EC3; s&#x1EED; d&#x1EE5;ng &#x111;&#x1EC3; render ra &#x111;&#x1B0;&#x1EE3;c d&#x1EEF; li&#x1EC7;u ra nha.</p>
<pre><code>// Read books
router.get(&apos;/&apos;, async function (req, res, next) {
  let books = await Book.find()
  res.render(&apos;index&apos;, { books: books })
});
</code></pre>
<p><strong>Giao di&#x1EC7;n &#x111;&#x1EC3; &#x111;&#x1ECD;c d&#x1EEF; li&#x1EC7;u c&#x1EE7;a book</strong><br>
Ti&#x1EBF;p &#x111;&#x1EBF;n b&#xE2;y gi&#x1EDD; ch&#xFA;ng ta ph&#x1EA3;i hi&#x1EC3;n th&#x1ECB; d&#x1EEF; li&#x1EC7;u c&#x1EE7;a n&#xF3; ra. Trong th&#x1B0; m&#x1EE5;c <code>views</code> c&#xF3; file <code>index.pug</code> , ch&#xFA;ng ta s&#x1EBD; l&#x1EB7;p qua bi&#x1EBF;n books m&#xE0; m&#xEC;nh &#x111;&#xE3; khai b&#xE1;o trong res.render &#x111;&#x1EC3; c&#xF3; th&#x1EC3; truy v&#x1EA5;n v&#xE0;o database v&#xE0; hi&#x1EC3;n th&#x1ECB; ra ngo&#xE0;i m&#xE0;n h&#xEC;nh.<br>
Trong ph&#x1EA7;n read book c&#xE1;c b&#x1EA1;n hi&#x1EC3;n th&#x1ECB; ra b&#x1ED1;n thu&#x1ED9;c t&#xED;nh nha &#x111;&#xF3; l&#xE0;: title, description, author v&#xE0; id. T&#x1EA1;i sao l&#x1EA1;i hi&#x1EC3;n th&#x1ECB; ra id, m&#x1EE5;c &#x111;&#x1ECB;nh c&#x1EE7;a n&#xF3; hi&#x1EC3;n th&#x1ECB; ra &#x111;&#x1EC3; c&#xF3; th&#x1EC3; l&#x1EA5;y gi&#xE1; tr&#x1ECB; id l&#xE0;m c&#xE1;c ph&#x1EA7;n c&#x1EAD;p nh&#x1EAD;t books v&#xE0; delete books, c&#xE1;c b&#x1EA1;n theo d&#xF5;i c&#xE1;c ph&#x1EA7;n ti&#x1EBF;p theo &#x111;&#x1EC3; bi&#x1EBF;t th&#xEA;m chi ti&#x1EBF;t.</p>
<pre><code>//- Read books
  div.content_book   
    h2 Read Books
    div.list_books
     each book in books
        ul
          li
           span Title:&amp;nbsp
           =book.title
          li
           span Description:&amp;nbsp
           =book.description
          li
           span Author:&amp;nbsp
           =book.author
          li
           span ID:&amp;nbsp
           =book._id 
</code></pre>
<p><strong>Ch&#xFA;ng ta c&#xF9;ng xem th&#x1EED; n&#xF3; c&#xF3; hi&#x1EC3;n th&#x1ECB; d&#x1EEF; li&#x1EC7;u c&#x1EE7;a book ra kh&#xF4;ng nha.</strong><br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1581691343/Untitled_vaujf1.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Web CRUD Books V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB"></p>
<h3 id="cpnhtbooks">C&#x1EAD;p Nh&#x1EAD;t Books</h3>
<p>M&#xEC;nh c&#x169;ng n&#xF3; s&#x1A1; qua nguy&#xEA;n l&#xFD; ho&#x1EA1;t &#x111;&#x1ED9;ng l&#xE0; s&#x1EBD; s&#x1EED; d&#x1EE5;ng id &#x111;&#x1EC3; c&#x1EAD;p nh&#x1EAD;t book, s&#x1EED; d&#x1EE5;ng id nh&#x1B0; th&#x1EBF; n&#xE0;o th&#xEC; &#x111;&#x1A1;n gi&#x1EA3;n th&#xF4;i ch&#xFA;ng ta s&#x1EBD; copy c&#xE1;i id m&#xE0; m&#xEC;nh &#x111;&#xE3; hi&#x1EC3;n th&#x1ECB; ra trong ph&#x1EA7;n <strong>&#x111;&#x1ECD;c books</strong> sao &#x111;&#xF3; d&#xE1;n v&#xE0;o ph&#x1EA7;n <strong>c&#x1EAD;p nh&#x1EAD;t bookks</strong>. sau khi d&#xE1;n v&#xE0;o th&#xEC; ch&#xFA;ng ta s&#x1EBD; ph&#x1EA3;i req.body th&#x1EBB; id &#x111;&#xF3;.<br>
R&#x1ED3;i ti&#x1EBF;p &#x111;&#x1EBF;n s&#x1EBD; find id trong database c&#xF3; tr&#xF9;ng v&#x1EDB;i id m&#xE0; m&#xEC;nh nh&#x1EAD;p kh&#xF4;ng, cu&#x1ED1;i c&#x1EA7;n c&#xE1;c b&#x1EA1;n ch&#x1EC9; c&#x1EA7;n thay &#x111;&#x1ED5;i d&#x1EEF; li&#x1EC7;u r&#x1ED3;i l&#x1B0;u v&#xE0;o database th&#xF4;i.<br>
<strong>Giao di&#x1EC7;n &#x111;&#x1EC3; c&#x1EAD;p nh&#x1EAD;t d&#x1EEF; li&#x1EC7;u book</strong><br>
&#x110;&#x1EC3; m&#xE0; c&#xF3; th&#x1EC3; c&#x1EAD;p nh&#x1EAD;t &#x111;&#x1B0;&#x1EE3;c books th&#xEC; ch&#xFA;ng ta c&#x1EA7;n ph&#x1EA3;i t&#x1EA1;o cho n&#xF3; m&#x1ED9;t c&#xE1;i giao di&#x1EC7;n &#x111;&#x1EC3; c&#xF3; th&#x1EC3; c&#x1EAD;p nh&#x1EAD;t books n&#xF3; c&#x169;ng t&#x1B0;&#x1A1;ng t&#x1EF1; nh&#x1B0; th&#x1EB1;ng <strong>t&#x1EA1;o books</strong> th&#xF4;i ch&#x1EC9; kh&#xE1;c ch&#x1ED7; l&#xE0; th&#xEA;m m&#x1ED9;t tr&#x1B0;&#x1EDD;ng id n&#x1EEF;a th&#xF4;i.<br>
<strong>L&#x1B0;u &#xFD;</strong>: V&#xE0; c&#xE1;c b&#x1EA1;n n&#xEA;n nh&#x1EDB; l&#xE0; trong form th&#xEC; action c&#x1EE7;a th&#x1EB1;ng t&#x1EA1;o books ph&#x1EA3;i kh&#xE1;c th&#x1EB1;ng c&#x1EAD;p nh&#x1EAD;t books v&#xE0; th&#x1EB1;ng x&#xF3;a books nh&#x1EE1; &#x111;&#x1EC3; n&#xF3; kh&#xF4;ng ph&#x1EA3;i b&#x1ECB; tr&#xF9;ng nhau g&#xE2;y nhi&#x1EC5;u lo&#x1EA1;n th&#xF4;ng tin,..</p>
<pre><code>//- Update books        
  div.content_book 
    h2 Update Books
    form(action=&quot;/update&quot; method=&quot;POST&quot;)
      div
        label(for=&quot;tittle&quot;) ID
        input(type=&quot;text&quot; name=&quot;id&quot; required=&quot;required&quot;)
      div
        label(for=&quot;tittle&quot;) Title
        input(type=&quot;text&quot; name=&quot;title&quot; required=&quot;required&quot;)
      div 
        label(for=&quot;tittle&quot;) Description
        input(type=&quot;text&quot; name=&quot;description&quot; required=&quot;required&quot;)
      div 
        label(for=&quot;tittle&quot;) Author
        input(type=&quot;text&quot; name=&quot;author&quot; required=&quot;required&quot;)
      button(type=&quot;submit&quot;) Update   
</code></pre>
<p><strong>Routes Post/update</strong><br>
Sau khi ch&#xFA;ng ta &#x111;&#xE3; t&#x1EA1;o giao di&#x1EC7;n cho n&#xF3; xong r&#x1ED3;i th&#xEC; ti&#x1EBF;p &#x111;&#x1EBF;n. Trong th&#x1B0; m&#x1EE5;c <code>routes</code> c&#xF3; file <code>index.js</code>. C&#xE1;c b&#x1EA1;n t&#x1EA1;o cho m&#xEC;nh ph&#x1B0;&#x1A1;ng th&#x1EE9;c <code>POST/update</code> &#x111;&#x1EC3; khi submit c&#x1EAD;p nh&#x1EAD;t d&#x1EEF; li&#x1EC7;u th&#xEC; n&#xF3; s&#x1EBD; &#x111;&#x1B0;&#x1EE3;c g&#x1EED;i l&#xEA;n server v&#xE0; l&#x1B0;u l&#x1EA1;i trong database nha.<br>
C&#xE1;c ho&#x1EA1;t &#x111;&#x1ED9;ng nh&#x1B0; th&#x1EBF; n&#xE0;o th&#xEC; m&#xEC;nh c&#x169;ng &#x111;&#xE3; n&#xF3;i &#x1EDF; tr&#xEA;n r&#x1ED3;i nha.</p>
<pre><code>// Update books
router.post(&quot;/update&quot;, function (req, res, next) {
  var id = req.body.id;
  Book.findById(id, function (err, book) {
    if (err) { console.log(err) }
    book.title = req.body.title
    book.description = req.body.description
    book.author = req.body.author
    book.save()
  })
  res.redirect(&apos;/&apos;)
})
</code></pre>
<p><strong>B&#xE2;y gi&#x1EDD; c&#xE1;c b&#x1EA1;n th&#x1EED; s&#x1EED;a l&#x1EA1;i books sau &#x111;&#xF3; c&#x1EAD;p nh&#x1EAD;t l&#x1EA1;i xem th&#x1EED; n&#xF3; c&#xF3; thay &#x111;&#x1ED5;i kh&#xF4;ng nha.</strong><br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1583504429/Untitled_drwtul.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Web CRUD Books V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB"></p>
<p>M&#xEC;nh s&#x1EBD; &#x111;&#x1ED5;i author l&#xE0; Long Code R&#x1EA1;o th&#xE0;nh Long Coder, sau &#x111;&#xF3; m&#xEC;nh s&#x1EBD; submit &#x111;&#x1EC3; xem ph&#x1EA7;n <strong>read book</strong> v&#xE0; <strong>database</strong> n&#xF3; c&#xF3; thay &#x111;&#x1ED5;i kh&#xF4;ng nha.<br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1583504611/Untitled_rhoibe.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Web CRUD Books V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB"></p>
<h3 id="xabooks">X&#xF3;a Books</h3>
<p>C&#xE1;ch ho&#x1EA1;t c&#x1EE7;a x&#xF3;a books c&#x169;ng t&#x1B0;&#x1A1;ng t&#x1EF1; nh&#x1B0; c&#x1EAD;p nh&#x1EAD;t books c&#x169;ng s&#x1EED; d&#x1EE5;ng id &#x111;&#x1EC3; x&#xF3;a kh&#xE1;c &#x1EDF; ch&#x1ED7; m&#x1ED9;t th&#x1EB1;ng th&#xEC; c&#x1EAD;p nh&#x1EAD;t c&#xF2;n th&#x1EB1;ng kia l&#xE0; x&#xF3;a m&#xE0; th&#xF4;i.<br>
<strong>Giao di&#x1EC7;n &#x111;&#x1EC3; x&#xF3;a d&#x1EEF; li&#x1EC7;u book</strong><br>
Giao di&#x1EC7;n th&#x1EB1;ng n&#xE0;y c&#x169;ng &#x111;&#x1A1;n gi&#x1EA3;n th&#xF4;i ch&#x1EC9; ch&#x1EE9;a m&#x1ED9;t tr&#x1B0;&#x1EDD;ng id th&#xF4;i nh&#x1B0;ng c&#xE1;c b&#x1EA1;n nh&#x1EDB; r&#x1EB1;ng l&#xE0; action c&#x1EE7;a m&#x1ED7;i th&#x1EB1;ng ph&#x1EA3;i kh&#xE1;c nhau nha.</p>
<pre><code>  //- Delete books     
  div.content_book   
    h2 Delete Books
    form(action=&quot;/delete&quot; method=&quot;POST&quot;)
      div
        label(for=&quot;id&quot;) ID
        input(type=&quot;text&quot; name=&quot;id&quot; required=&quot;required&quot;)
      button(type=&quot;submit&quot;) Delete
</code></pre>
<p><strong>Routes Post/delete</strong><br>
Trong ph&#x1EA7;n n&#xE0;y c&#xE1;c b&#x1EA1;n ch&#x1EC9; c&#x1EA7;n t&#xEC;m trong database c&#xF3; id n&#xE0;o m&#xE0; tr&#xF9;ng v&#x1EDB;i id m&#xE0; m&#xEC;nh nh&#x1EAD;p kh&#xF4;ng sau &#x111;&#xF3; x&#xF3;a th&#xF4;i.</p>
<pre><code>// Delete books
router.post(&quot;/delete&quot;, function (req, res, next) {
  var id = req.body.id
  Book.findByIdAndDelete(id, function (err) {
    if (err) { console.log(err) }
  })
  res.redirect(&apos;/&apos;)
})
</code></pre>
<p><strong>Ch&#xFA;ng ta c&#xF9;ng xem th&#x1EED; trong database n&#xF3; c&#xF3; x&#xF3;a kh&#xF4;ng nha v&#xE0; ph&#x1EA7;n &#x111;&#x1ECD;c books c&#xF3; hi&#x1EC3;n th&#x1ECB; d&#x1EEF; li&#x1EC7;u c&#x1EE7;a books kh&#xF4;ng nha.</strong><br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1581691540/Untitled_upnivy.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Web CRUD Books V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB"></p>
<p><strong>V&#xE0; &#x111;&#xE2;y l&#xE0; k&#x1EBF;t qu&#x1EA3; khi ch&#xFA;ng ta submit x&#xF3;a d&#x1EEF; li&#x1EC7;u books</strong><br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1583504875/Untitled_vxbc62.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Web CRUD Books V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB"></p>
<p>v&#xE0; t&#x1EA5;t c&#x1EA3; &#x111;&#x1EC1;u tr&#x1ED1;ng tr&#x1A1;n trong database c&#x169;ng b&#x1ECB; x&#xF3;a.<br>
<em><strong>V&#x1EAD;y l&#xE0; ch&#xFA;ng ta &#x111;&#xE3; ho&#xE0;n th&#xE0;nh xong c&#xE1;c ch&#x1EE9;c n&#x103;ng CRUD, b&#xE2;y gi&#x1EDD; ch&#xFA;ng ta ch&#x1EC9; c&#x1EA7;n css l&#x1EA1;i cho n&#xF3; n&#x1EEF;a l&#xE0; ok.</strong></em></p>
<h2 id="vitcsschocrudbooks">Vi&#x1EBF;t CSS Cho CRUD Books</h2>
<p>Trong file <code>style.css</code> ch&#xFA;ng ta s&#x1EBD; cho b&#x1ED1;n c&#xE1;i ch&#x1EE9;c n&#x103;ng tr&#xEA;n c&#xF9;ng m&#x1ED9;t h&#xE0;ng b&#x1EB1;ng c&#xE1;ch s&#x1EED; d&#x1EE5;ng float v&#xE0; width.<br>
Ti&#x1EBF;p &#x111;&#x1EBF;n c&#xE1;c b&#x1EA1;n ch&#x1EC9;nh c&#xE1;c m&#xE0;u width c&#x169;ng nh&#x1B0; c&#xE1;c font sao cho &#x111;&#x1EB9;p v&#xE0; ph&#xF9; h&#x1EE3;p nh&#x1EA5;t nha.</p>
<pre><code>* {
  padding: 0;
  margin: 0;
  box-sizing: border-box;
}

html,
body {
  padding: 2rem;
  font-family: tahoma;
}

li {
  list-style: none;
}

label {
  margin-bottom: .2rem;
  font-weight: 700;
  display: block;
}

.content_book {
  width: 25%;
  display: block;
  float: left;
}

.title-book h1 {
  text-align: center;
  color: red;
  margin-bottom: 1.5rem;
}

.content_book h2 {
  color: #006600;
  margin-bottom: .5rem;
}

div {
  margin-bottom: .5rem;
}

input[type=&quot;text&quot;] {
  width: 80%;
  padding: 5px;
  border-radius: 3px;
  outline: none;
  border: 1px solid #a5a5a5;
}

button {
  background: blue;
  cursor: pointer;
  text-transform: uppercase;
  padding: 0.5rem;
  border-radius: 5px;
  color: #fff;
  border: none;
}

.content_book ul {
  background: aqua;
  padding: 0.5rem;
  width: 100%;
  margin-bottom: .5rem;
}

.content_book ul li {
  text-overflow: ellipsis;
  overflow: hidden;
  margin-bottom: .3rem;
}

.content_book ul li span {
  font-weight: bold;
}
.content_book .list_books{
  width: 90%;
  height: 220px;
  overflow-y: scroll;
}
</code></pre>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1580980651/1_rjq0n6.png" width="700" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Web CRUD Books V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB">
<p>C&#xE1;c b&#x1EA1;n s&#x1EBD; th&#x1EA5;y t&#x1EA1;i sao l&#x1EA1;i ph&#x1EA3;i c&#xF3; thanh scroll b&#x1EDF;i v&#xEC; khpi ch&#xFA;ng ta t&#x1EA1;o r&#x1EA5;t nhi&#x1EC1;u books th&#xEC; s&#x1ED1; l&#x1B0;&#x1EE3;ng m&#xE0; render ra r&#x1EA5;t nhi&#x1EC1;u v&#xE0; d&#xE0;i l&#xE0;m cho giao di&#x1EC7;n kh&#xF4;ng &#x111;&#x1B0;&#x1EE3;c &#x111;&#x1EB9;p. V&#xEC; th&#x1EBF; ch&#xFA;ng ta s&#x1EBD; cho height c&#x1ED1; &#x111;&#x1ECB;nh, overflow-y: scroll.<br>
Khi m&#xE0; s&#x1ED1; l&#x1B0;&#x1EE3;ng books v&#x1B0;&#x1EE3;t qua height c&#x1ED1; &#x111;&#x1ECB;nh th&#xEC; s&#x1EBD; xu&#x1EA5;t hi&#x1EC7;n scroll.</p>
<h3 id="reponsivegiaodinchocrudbooks">Reponsive Giao Di&#x1EC7;n Cho CRUD Books</h3>
<p>Trong file <code>layout.pug</code> c&#xE1;c b&#x1EA1;n nh&#x1EDB; add th&#x1EBB; meta n&#xE0;y &#x111;&#x1EC3; n&#xF3; c&#xF3; th&#x1EC3; reponsive giao di&#x1EC7;n nha.<br>
<code>meta(name=&apos;viewport&apos;, content=&apos;width=device-width, initial-scale=1&apos;)</code><br>
<strong>Mobile</strong><br>
Trong file <code>style.css</code> c&#xE1;c b&#x1EA1;n ch&#x1EC9; c&#x1EA7;n cho width:100% cho m&#x1ED7;i ch&#x1EE9;c n&#x103;ng l&#xE0; &#x111;&#x1B0;&#x1EE3;c.</p>
<pre><code>/* Mobile */
@media only screen and (min-width:240px) and (max-width:480px) {
  html,
  body {
      padding: 1rem;
      font-family: tahoma;
  }
  .content_book {
      width: 100%;
      margin-bottom: 2rem;
  }
}
</code></pre>
<p><strong>V&#xE0; &#x111;&#xE2;y l&#xE0; giao di&#x1EC7;n mobile khi ch&#xFA;ng ta &#x111;&#xE3; reponsive nha.</strong><br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1580980754/1_s7ppgj.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Web CRUD Books V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB"></p>
<p><strong>Tablet</strong><br>
Th&#xEC; c&#x169;ng &#x111;&#x1A1;n gi&#x1EA3;n th&#xF4;i trong file <code>style.css</code> c&#xE1;c b&#x1EA1;n ch&#x1EC9; c&#x1EA7;n cho width:50% cho m&#x1ED7;i ch&#x1EE9;c n&#x103;ng l&#xE0; &#x111;&#x1B0;&#x1EE3;c.</p>
<pre><code>/* Tablet */
@media (min-width:480px) and (max-width:768px) {
  .content_book {
      width: 50%;
  }
}
</code></pre>
<p><strong>V&#xE0; &#x111;&#xE2;y l&#xE0; giao di&#x1EC7;n tablet khi ch&#xFA;ng ta &#x111;&#xE3; reponsive nha.</strong><br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1580980883/1_igg4lt.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Web CRUD Books V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB"></p>
<p><em>V&#x1EAD;y l&#xE0; xong r&#x1ED3;i nha, c&#xE1;c b&#x1EA1;n c&#xF3; th&#x1EC3; tham kh&#x1EA3;o code m&#xE0; m&#xEC;nh &#x111;&#xE3; push l&#xEA;n github <a href="https://github.com/long1211/CRUD_Books_NODEJS">t&#x1EA1;i &#x111;&#xE2;y nha</a></em></p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h1 id="likt">L&#x1EDD;i K&#x1EBF;t</h1>
<p>V&#x1EAD;y L&#xE0; Xong b&#xE0;i H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng Web CRUD Books V&#x1EDB;i NodeJS, Express v&#xE0; MongoDB r&#x1ED3;i nh&#xE9;. M&#xEC;nh mong mu&#x1ED1;n sau b&#xE0;i topic n&#xE0;y c&#xE1;c b&#x1EA1;n c&#xF3; th&#x1EC3; n&#x1EAF;m v&#x1EEF;ng th&#xEA;m v&#x1EC1; NodeJS, Express v&#xE0; MongoDB v&#xE0; c&#xF3; th&#x1EC3; t&#x1EF1; tay m&#xEC;nh l&#xE0;m nh&#x1EEF;ng project kh&#xF4;ng c&#x1EA7;n ph&#x1EA3;i qu&#xE1; &#x111;&#x1EB7;c bi&#x1EC7;t nh&#x1B0;ng n&#xF3; do ch&#xED;nh b&#x1EA1;n l&#xE0;m th&#xEC; c&#x169;ng coi nh&#x1B0; l&#xE0; th&#xE0;nh qu&#x1EA3; trong qu&#xE1; tr&#xEC;nh b&#x1EA1;n h&#x1ECD;c &#x111;&#x1B0;&#x1EE3;c.</p>
<p><strong>N&#x1EBF;u c&#xE1;c b&#x1EA1;n c&#x1EA3;m th&#x1EA5;y b&#xE0;i vi&#x1EBF;t c&#x1EE7;a m&#xEC;nh hay th&#xEC; c&#xE1;c b&#x1EA1;n c&#xF3; th&#x1EC3; &#x1EE7;ng h&#x1ED9; m&#xEC;nh &#x111;&#x1EC3; m&#xEC;nh c&#xF3; th&#xEA;m &#x111;&#x1ED9;ng l&#x1EF1;c &#x111;&#x1EC3; ra nh&#x1EEF;ng b&#xE0;i topic hay v&#xE0; ch&#x1EA5;t l&#x1B0;&#x1EE3;ng h&#x1A1;n &#x1EE7;ng h&#x1ED9; m&#xEC;nh <a href="https://vrdonate.vn/thanhlongdev">t&#x1EA1;i &#x111;&#xE2;y nha</a>.</strong></p>
<p><em><strong>Ch&#xFA;c C&#xE1;c B&#x1EA1;n Th&#xE0;nh C&#xF4;ng!!</strong></em></p>
<!--kg-card-end: markdown--><!--kg-card-begin: html--><iframe src="https://www.facebook.com/plugins/like.php?href=https%3A%2F%2Fwww.thanhlongdev.com%2Fhuong-dan-xay-dung-web-crud-books-voi-nodejs-express-mongodb%2F&amp;width=450&amp;layout=standard&amp;action=like&amp;size=large&amp;share=true&amp;height=35&amp;appId=2794898430534168" width="450" height="35" style="border:none;overflow:hidden" scrolling="no" frameborder="0" allowtransparency="true" allow="encrypted-media"></iframe><!--kg-card-end: html--><!--kg-card-begin: html--><div class="fb-comments" data-href="https://www.thanhlongdev.com/huong-dan-xay-dung-web-crud-books-voi-nodejs-express-mongodb/" data-width="100%" data-numposts="10"></div><!--kg-card-end: html-->]]></content:encoded></item><item><title><![CDATA[Hướng Dẫn Xây Dựng RESTful CRUD API Với NodeJS, Express  và MongoDB]]></title><description><![CDATA[<!--kg-card-begin: markdown--><h1 id="giithiuchung">Gi&#x1EDB;i Thi&#x1EC7;u Chung</h1>
<p>H&#xF4;m nay m&#xEC;nh s&#x1EBD; h&#x1B0;&#x1EDD;ng d&#x1EAB;n c&#xE1;c b&#x1EA1;n x&#xE2;y d&#x1EF1;ng m&#x1ED9;t Restful CRUD API v&#x1EDB;i nodejs, express v&#xE0; mongodb.<br>
C&</p>]]></description><link>https://www.thanhlongdev.com/huong-dan-xay-dung-restful-crud-api-voi-nodejs-express-va-mongodb/</link><guid isPermaLink="false">5e2b7beaba3232000183b18e</guid><category><![CDATA[Lập Trình Web]]></category><dc:creator><![CDATA[Đặng Thanh Long]]></dc:creator><pubDate>Mon, 27 Jan 2020 02:03:14 GMT</pubDate><media:content url="https://digitalpress.fra1.cdn.digitaloceanspaces.com/4tg23ij/2020/01/8267.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h1 id="giithiuchung">Gi&#x1EDB;i Thi&#x1EC7;u Chung</h1>
<img src="https://digitalpress.fra1.cdn.digitaloceanspaces.com/4tg23ij/2020/01/8267.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng RESTful CRUD API V&#x1EDB;i NodeJS, Express  v&#xE0; MongoDB"><p>H&#xF4;m nay m&#xEC;nh s&#x1EBD; h&#x1B0;&#x1EDD;ng d&#x1EAB;n c&#xE1;c b&#x1EA1;n x&#xE2;y d&#x1EF1;ng m&#x1ED9;t Restful CRUD API v&#x1EDB;i nodejs, express v&#xE0; mongodb.<br>
C&#xE1;c b&#x1EA1;n c&#x169;ng &#x111;&#xE3; nghe kh&#xE1; nhi&#x1EC1;u v&#x1EC1; rest api hay restful api &#x111;&#xFA;ng kh&#xF4;ng n&#xE0;o. Th&#xEC; h&#xF4;m nay m&#xEC;nh c&#x169;ng s&#x1EBD; h&#x1B0;&#x1EDB;ng d&#x1EAB;n c&#xE1;c t&#x1EA1;o m&#x1ED9;t restful CRUD API.<br>
&#x110;&#x1EC3; c&#xE1;c b&#x1EA1;n hi&#x1EC3;u r&#xF5; h&#x1A1;n m&#xEC;nh s&#x1EBD; gi&#x1EA3;i th&#xED;ch api l&#xE0; g&#xEC;?, rest l&#xE0; g&#xEC;?,...</p>
<h1 id="apilg">API l&#xE0; g&#xEC;?</h1>
<p>API (application programming interface) l&#xE0; giao di&#x1EC7;n d&#xF9;ng &#x111;&#x1EC3; t&#x1B0;&#x1A1;ng t&#xE1;c gi&#x1EEF;a &#x1EE9;ng d&#x1EE5;ng n&#xE0;y v&#x1EDB;i &#x1EE9;ng d&#x1EE5;ng kh&#xE1;c. API c&#xF3; th&#x1EC3; tr&#x1EA3; v&#x1EC1; d&#x1EEF; li&#x1EC7;u m&#xE0; b&#x1EA1;n c&#x1EA7;n cho &#x1EE9;ng d&#x1EE5;ng c&#x1EE7;a m&#xEC;nh &#x1EDF; nh&#x1EEF;ng ki&#x1EC3;u d&#x1EEF; li&#x1EC7;u ph&#x1ED5; bi&#x1EBF;n nh&#x1B0; JSON hay XML. Facebook, google l&#xE0; hai &#x1EE9;ng d&#x1EE5;ng kh&#xE1; quen thu&#x1ED9;c. N&#xF3; c&#xF3; nh&#x1EEF;ng API ri&#xEA;ng &#x111;&#x1EC3; cho ch&#xFA;ng ta s&#x1EED; d&#x1EE5;ng &#x111;&#x1EC3; n&#xF3; c&#xF3; th&#x1EC3; l&#x1EA5;y &#x111;&#x1B0;&#x1EE3;c th&#xF4;ng tin c&#x1EE7;a ng&#x1B0;&#x1EDD;i d&#xF9;ng.</p>
<h1 id="restlg">Rest l&#xE0; g&#xEC;?</h1>
<p>REST l&#xE0; t&#x1EEB; vi&#x1EBF;t t&#x1EAF;t cho REpresentational State Transfer. REST kh&#xF4;ng ph&#x1EA3;i l&#xE0; m&#x1ED9;t chu&#x1EA9;n hay m&#x1ED9;t giao th&#x1EE9;c m&#xE0; n&#xF3; l&#xE0; m&#x1ED9;t ki&#x1EC3;u ki&#x1EBF;n tr&#xFA;c &#x111;&#x1EC3; vi&#x1EBF;t API. M&#x1ED9;t web service l&#xE0; m&#x1ED9;t t&#x1EAD;p h&#x1EE3;p c&#xE1;c giao th&#x1EE9;c v&#xE0; &#x111;&#x1B0;&#x1EE3;c s&#x1EED; d&#x1EE5;ng cho m&#x1EE5;c &#x111;&#xED;ch trao &#x111;&#x1ED5;i gi&#x1EEF;a &#x1EE9;ng d&#x1EE5;ng v&#xE0; h&#x1EC7; th&#x1ED1;ng. Web service d&#x1EF1;a tr&#xEA;n c&#xE1;c ki&#x1EBF;n tr&#xFA;c REST &#x111;&#x1B0;&#x1EE3;c bi&#x1EBF;t nh&#x1B0; RESTful webservice . Nh&#x1EEF;ng webservice n&#xE0;y s&#x1EED; d&#x1EE5;ng ph&#x1B0;&#x1A1;ng th&#x1EE9;c HTTP &#x111;&#x1EC3; tri&#x1EC3;n khai c&#xE1;c &#x111;&#x1ECB;nh ngh&#x129;a ki&#x1EBF;n tr&#xFA;c REST.</p>
<h1 id="restfulapilg">RESTful API l&#xE0; g&#xEC;?</h1>
<p>RESTful API l&#xE0; m&#x1ED9;t ti&#xEA;u chu&#x1EA9;n d&#xF9;ng trong vi&#x1EC7;c th&#x1EBF;t k&#x1EBF; c&#xE1;c API cho c&#xE1;c &#x1EE9;ng d&#x1EE5;ng web &#x111;&#x1EC3; qu&#x1EA3;n l&#xFD; c&#xE1;c resource(t&#xE0;i nguy&#xEA;n). RESTful l&#xE0; m&#x1ED9;t trong nh&#x1EEF;ng ki&#x1EC3;u thi&#x1EBF;t k&#x1EBF; API &#x111;&#x1B0;&#x1EE3;c s&#x1EED; d&#x1EE5;ng ph&#x1ED5; bi&#x1EBF;n nh&#x1EA5;t ng&#xE0;y nay. Tr&#x1ECD;ng t&#xE2;m c&#x1EE7;a REST quy &#x111;&#x1ECB;nh c&#xE1;ch s&#x1EED; d&#x1EE5;ng c&#xE1;c HTTP method (nh&#x1B0; GET, POST, PUT, DELETE...) v&#xE0; c&#xE1;ch &#x111;&#x1ECB;nh d&#x1EA1;ng c&#xE1;c URL cho &#x1EE9;ng d&#x1EE5;ng web &#x111;&#x1EC3; qu&#x1EA3;n l&#xFD; c&#xE1;c resource. RESTful kh&#xF4;ng quy &#x111;&#x1ECB;nh logic code &#x1EE9;ng d&#x1EE5;ng v&#xE0; kh&#xF4;ng gi&#x1EDB;i h&#x1EA1;n b&#x1EDF;i ng&#xF4;n ng&#x1EEF; l&#x1EAD;p tr&#xEC;nh &#x1EE9;ng d&#x1EE5;ng.<br>
<strong>RESTful ho&#x1EA1;t &#x111;&#x1ED9;ng nh&#x1B0; th&#x1EBF; n&#xE0;o?</strong><br>
C&#xF3; 4 ho&#x1EA1;t &#x111;&#x1ED9;ng ch&#x1EE7; y&#x1EBF;u ta c&#xF3; th&#x1EC3; k&#x1EC3; &#x111;&#x1EBF;n khi l&#xE0;m vi&#x1EC7;c v&#x1EDB;i server: l&#x1EA5;y d&#x1EEF; li&#x1EC7;u &#x1EDF; m&#x1ED9;t &#x111;&#x1ECB;nh d&#x1EA1;ng n&#xE0;o &#x111;&#xF3; (JSON), t&#x1EA1;o d&#x1EEF; li&#x1EC7;u m&#x1EDB;i, c&#x1EAD;p nh&#x1EAD;t d&#x1EEF; li&#x1EC7;u, x&#xF3;a d&#x1EEF; li&#x1EC7;u. REST ho&#x1EA1;t &#x111;&#x1ED9;ng ch&#x1EE7; y&#x1EBF;u d&#x1EF1;a v&#xE0;o giao th&#x1EE9;c HTTP. C&#xE1;c ho&#x1EA1;t &#x111;&#x1ED9;ng c&#x1A1; b&#x1EA3;n n&#xEA;u tr&#xEA;n s&#x1EBD; s&#x1EED; d&#x1EE5;ng nh&#x1EEF;ng ph&#x1B0;&#x1A1;ng th&#x1EE9;c HTTP ri&#xEA;ng.</p>
<blockquote>
<p>GET: l&#x1EA5;y d&#x1EEF; li&#x1EC7;u<br>
POST: t&#x1EA1;o m&#x1EDB;i<br>
PUT: c&#x1EAD;p nh&#x1EAD;t (thay &#x111;&#x1ED5;i)<br>
DELETE: X&#xF3;a d&#x1EEF; li&#x1EC7;u</p>
</blockquote>
<p>Nh&#x1EEF;ng ph&#x1B0;&#x1A1;ng th&#x1EE9;c hay ho&#x1EA1;t &#x111;&#x1ED9;ng n&#xE0;y th&#x1B0;&#x1EDD;ng &#x111;&#x1B0;&#x1EE3;c g&#x1ECD;i l&#xE0; CRUD t&#x1B0;&#x1A1;ng &#x1EE9;ng v&#x1EDB;i Create, Read, Update, Delete &#x2013; T&#x1EA1;o, &#x110;&#x1ECD;c, S&#x1EED;a, X&#xF3;a. M&#x1ED7;i ph&#x1B0;&#x1A1;ng th&#x1EE9;c tr&#xEA;n ph&#x1EA3;i &#x111;&#x1B0;&#x1EE3;c API g&#x1ECD;i th&#xF4;ng qua &#x111;&#x1EC3; g&#x1EED;i ch&#x1EC9; th&#x1ECB; cho server ph&#x1EA3;i l&#xE0;m g&#xEC;.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h1 id="mcchcabivit">M&#x1EE5;c &#x110;&#xED;ch C&#x1EE7;a B&#xE0;i Vi&#x1EBF;t</h1>
<p>Th&#xEC; b&#xE0;i vi&#x1EBF;t n&#xE0;y m&#xEC;nh vi&#x1EBF;t nh&#x1EB1;m m&#x1EE5;c &#x111;&#xED;ch l&#xE0; h&#x1B0;&#x1EDB;ng d&#x1EAB;n c&#xE1;c b&#x1EA1;n vi&#x1EBF;t m&#x1ED9;t RESTful API. V&#xE0; gi&#x1EDB;i thi&#x1EC7;u RESTful API l&#xE0; g&#xEC;?<br>
Ch&#xFA;ng ta s&#x1EBD; x&#xE2;y d&#x1EF1;ng m&#x1ED9;t &#x1EE9;ng d&#x1EE5;ng todo list &#x111;&#x1A1;n gi&#x1EA3;n. Ch&#xFA;ng ta s&#x1EBD; x&#xE2;y d&#x1EF1;ng c&#xE1;c API c&#xF2;n &#x111;&#x1EC3; t&#x1EA1;o, li&#x1EC7;t k&#xEA;, ch&#x1EC9;nh s&#x1EED;a v&#xE0; x&#xF3;a todo list.<br>
Gi&#xFA;p c&#xE1;c b&#x1EA1;n hi&#x1EC3;u r&#xF5; h&#x1A1;n v&#x1EC1; RESTful API, CRUD c&#x169;ng nh&#x1B0; &#xF4;n l&#x1EA1;i c&#xE1;c ki&#x1EBF;n th&#x1EE9;c v&#x1EC1; NodeJS, Express v&#xE0; MongoDB.<br>
Gi&#x1EDB;i thi&#x1EC7;u cho c&#xE1;c b&#x1EA1;n c&#xF4;ng c&#x1EE5; Postman d&#xF9;ng &#x111;&#x1EC3; &#x111;&#x1ECD;c API.<br>
M&#xEC;nh vi&#x1EBF;t b&#xE0;i n&#xE0;y kh&#xE1; r&#xF5; r&#xE0;ng v&#xE0; t&#x1EC9; m&#x1EC9; m&#xEC;nh mong c&#xE1;c b&#x1EA1;n &#x111;&#x1ECD;c m&#x1ED9;t c&#xE1;ch &#x111;&#x1EA7;y &#x111;&#x1EE7; nh&#x1EA5;t.<br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1581691856/19b60c23657566e786a9fc9ffdf9c30d_bpo4kg.jpg" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng RESTful CRUD API V&#x1EDB;i NodeJS, Express  v&#xE0; MongoDB"></p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h1 id="btuthino">B&#x1EAF;t &#x110;&#x1EA7;u Th&#xF4;i N&#xE0;o</h1>
<h2 id="citvthitlp">C&#xE0;i &#x110;&#x1EB7;t V&#xE0; Thi&#x1EBF;t L&#x1EAD;p</h2>
<p>Tr&#x1B0;&#x1EDB;c ti&#xEA;n c&#xE1;c b&#x1EA1;n t&#x1EA1;o cho m&#xEC;nh m&#x1ED9;t folder trong folder &#x111;&#xF3; l&#xE0; n&#x1A1;i ch&#x1EE9;a c&#xE1;c th&#x1B0; m&#x1EE5;c v&#xE0; ch&#x1B0;&#x1A1;ng tr&#xEC;nh m&#xE0; ch&#xFA;ng ta vi&#x1EBF;t cho c&#xE1;c API.<br>
<strong>C&#xE0;i &#x111;&#x1EB7;t c&#xE1;c module &#x111;&#x1EC3; thi&#x1EBF;t l&#x1EAD;p ch&#x1B0;&#x1A1;ng tr&#xEC;nh nh&#x1B0;:</strong><br>
&#x110;&#x1EC3; m&#xE0; c&#xE0;i c&#xE1;c module tr&#x1B0;&#x1EDB;c h&#x1EBF;t c&#xE1;c b&#x1EA1;n ph&#x1EA3;i <a href="https://nodejs.org/en/download/">download</a> nodejs.</p>
<ul>
<li>npm install --save express-generator<br>
Module n&#xE0;y n&#xF3; s&#x1EBD; gi&#xFA;p ch&#xFA;ng ta t&#x1EA1;o nhanh khung s&#x1B0;&#x1EDD;n cho &#x1EE9;ng d&#x1EE5;ng.</li>
<li>express --view=pug<br>
N&#xF3; s&#x1EBD; t&#x1EA1;o cho c&#xE1;c b&#x1EA1;n ph&#x1EA7;n view engine v&#xE0; &#x111;&#x1B0;&#x1EE3;c setup l&#xE0; Pug.</li>
<li>npm install nodemon --save<br>
T&#x1EF1; &#x111;&#x1ED9;ng reload l&#x1EA1;i server khi b&#x1EA1;n thay &#x111;&#x1ED5;i code. &#x110;&#x1EC3; kh&#x1EDF;i ch&#x1EA1;y server c&#xE1;c b&#x1EA1;n th&#xEA;m  <code>&quot;devStart&quot;: &quot;nodemon app.js&quot;</code>v&#xE0;o file package.json nha. C&#xE1;c b&#x1EA1;n m&#x1EDF; terminal l&#xEA;n sau &#x111;&#xF3; g&#xF5; <code>npm run devStart</code> &#x111;&#x1EC3; kh&#x1EDF;i ch&#x1EA1;y server nha.</li>
<li>npm install mongoose --save<br>
Mongoose l&#xE0; m&#x1ED9;t Object Document Mapper (ODM). &#x110;i&#x1EC1;u n&#xE0;y c&#xF3; ngh&#x129;a l&#xE0; Mongoose cho ph&#xE9;p b&#x1EA1;n &#x111;&#x1ECB;nh ngh&#x129;a c&#xE1;c object (&#x111;&#x1ED1;i t&#x1B0;&#x1EE3;ng) v&#x1EDB;i m&#x1ED9;t schema &#x111;&#x1B0;&#x1EE3;c &#x111;&#x1ECB;nh ngh&#x129;a r&#xF5; r&#xE0;ng.</li>
<li>npm install dotenv --save<br>
Dotenv l&#xE0; m&#x1ED9;t module t&#x1EA3;i c&#xE1;c bi&#x1EBF;n m&#xF4;i tr&#x1B0;&#x1EDD;ng t&#x1EEB; t&#x1EC7;p .env v&#xE0;o process.env. L&#x1B0;u tr&#x1EEF; c&#x1EA5;u h&#xEC;nh trong .env t&#xE1;ch bi&#x1EC7;t v&#x1EDB;i code &#x111;&#x1EC3; b&#x1EA3;o m&#x1EAD;t th&#xF4;ng tin.</li>
</ul>
<h1 id="btucodethino">B&#x1EAF;t &#x110;&#x1EA7;u Code Th&#xF4;i N&#xE0;o</h1>
<h2 id="thitlpwebserver">Thi&#x1EBF;t l&#x1EAD;p Web Server</h2>
<p>Trong file app.js c&#xE1;c b&#x1EA1;n b&#x1ECF; cho m&#xEC;nh router user v&#xE0; t&#x1EA1;o c&#x1ED5;ng port cho web server. Trong folder routes c&#xE1;c b&#x1EA1;n c&#x169;ng b&#x1ECF; cho m&#xEC;nh file user.js nha, &#x111;&#xF3; l&#xE0; c&#xE1;c file m&#x1EB7;c &#x111;&#x1ECB;nh khi m&#xEC;nh ch&#x1EA1;y <code>npm install --save express-generator</code> kh&#xF4;ng c&#x1EA7;n thi&#x1EBF;t th&#xEC; m&#xEC;nh b&#x1ECF; th&#xF4;i nha</p>
<pre><code>var createError = require(&apos;http-errors&apos;);
var express = require(&apos;express&apos;);
var path = require(&apos;path&apos;);
var cookieParser = require(&apos;cookie-parser&apos;);
var logger = require(&apos;morgan&apos;);

var port = 5000;
var indexRouter = require(&apos;./routes/index&apos;);
var app = express();

// view engine setup
app.set(&apos;views&apos;, path.join(__dirname, &apos;views&apos;));
app.set(&apos;view engine&apos;, &apos;pug&apos;);

app.use(logger(&apos;dev&apos;));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, &apos;public&apos;)));

// setup router
app.use(&apos;/&apos;, indexRouter);

// catch 404 and forward to error handler
.........
.........
.........

// error handler
.........
.........
.........
app.listen(port,function(){
  console.log(&quot;Server listening connect port&quot; + port)
})
module.exports = app;

</code></pre>
<p>Trong th&#x1B0; m&#x1EE5;c router c&#xF3; file index.js, c&#xE1;c b&#x1EA1;n t&#x1EA1;o cho n&#xF3; m&#x1ED9;t Route handlers v&#xE0; th&#x1EED; ch&#x1EA1;y sever xem sau. M&#x1EE5;c &#x111;&#xED;ch &#x111;&#x1EC3; c&#xE1;c b&#x1EA1;n test th&#x1EED; server c&#xF3; ch&#x1EA1;y kh&#xF4;ng nha.</p>
<pre><code>router.get(&apos;/&apos;,function(req, res, next){
res.send(&apos;Hello World&apos;)
})
</code></pre>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1581693185/Untitled_kwghza.png" width="700" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng RESTful CRUD API V&#x1EDB;i NodeJS, Express  v&#xE0; MongoDB">
<h2 id="thitlpdatabase">Thi&#x1EBF;t L&#x1EAD;p Database</h2>
<p>C&#xE0;i &#x111;&#x1EB7;t mongodb <a href="https://docs.mongodb.com/manual/administration/install-community/">download t&#x1EA1;i &#x111;&#xE2;y</a>, c&#xE1;c b&#x1EA1;n t&#x1EA1;o cho m&#xEC;nh m&#x1ED9;t file .env. Trong file n&#xE0;y c&#xE1;c b&#x1EA1;n t&#x1EA1;o cho m&#xEC;nh m&#x1ED9;t &#x111;&#x1B0;&#x1EDD;ng d&#x1EAB;n <code>MONGOURL=mongodb://localhost/todolist</code><br>
Trong file app.js c&#xE1;c b&#x1EA1;n khai b&#xE1;o module dotenv v&#x1EDB;i module mongoose v&#xE0; t&#x1EA1;o &#x111;&#x1B0;&#x1EDD;ng d&#x1EAB;n mongodb<br>
// path database<br>
<code> mongoose.connect(process.env.MONGOURL,{useNewUrlParser:true, useUnifiedTopology: true });</code><br>
B&#xE2;y gi&#x1EDD; m&#xE0; c&#xE1;c b&#x1EA1;n b&#x1EA1;n mu&#x1ED1;n ch&#x1EA1;y &#x111;&#x1B0;&#x1EE3;c server th&#xEC; ph&#x1EA3;i ch&#x1EA1;y database nha.<br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1581692094/3_a57xqh.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng RESTful CRUD API V&#x1EDB;i NodeJS, Express  v&#xE0; MongoDB"></p>
<h2 id="nhnghaschematodolisttrongmongoose">&#x110;&#x1ECB;nh Ngh&#x129;a Schema TodoList Trong Mongoose</h2>
<p>C&#xE1;c b&#x1EA1;n t&#x1EA1;o cho m&#xEC;nh th&#x1B0; m&#x1EE5;c <strong>modal</strong> b&#xEA;n trong th&#x1B0; m&#x1EE5;c g&#x1ED1;c c&#x1EE7;a &#x1EE9;ng d&#x1EE5;ng.<br>
B&#xEA;n trong th&#x1B0; m&#x1EE5;c modal th&#xEC; m&#xEC;nh s&#x1EBD; t&#x1EA1;o m&#x1ED9;t file <strong>todo.modal.js</strong>. &#x110;&#xE2;y c&#x169;ng l&#xE0; ph&#x1EA7;n quan tr&#x1ECD;ng nh&#x1EA5;t trong topic n&#xE0;y, c&#xE1;c b&#x1EA1;n nh&#x1EDB; &#x111;&#x1ECD;c cho k&#x129; nha.</p>
<pre><code>var mongoose = require(&apos;mongoose&apos;)
var todo = new mongoose.Schema({
    todolist:{ type:String, required:true}
  });
 module.exports = mongoose.model(&apos;todolist&apos;, todo);
</code></pre>
<p>Trong file <strong>todo.modal.js</strong> ch&#xFA;ng ta s&#x1EBD; khai b&#xE1;o module mongoose v&#xE0; ch&#xFA;ng ta s&#x1EBD; t&#x1EA1;o cho n&#xF3; m&#x1ED9;t schema &#x111;&#x1EC3; ch&#x1EE9;a fields todolist.</p>
<h2 id="nhngharouterchotodolist">&#x110;&#x1ECB;nh Ngh&#x129;a Router Cho TodoList</h2>
<p>Trong file <strong>index.js</strong> n&#x1EB1;m b&#xEA;n trong th&#x1B0; m&#x1EE5;c <strong>routes</strong>, t&#x1EA1;o c&#xE1;c ph&#x1B0;&#x1A1;ng th&#x1EE9;c &#x111;&#x1EC3; x&#x1EED; l&#xFD; c&#xE1;c ho&#x1EA1;t &#x111;&#x1ED9;ng CRUD. C&#xE1;c b&#x1EA1;n khai b&#xE1;o cho m&#xEC;nh modal c&#x1EE7;a Todo List nha.<br>
<code>var Todo = require(&apos;../modal/todo.modal&apos;)</code></p>
<h3 id="tovlucctodolist">T&#x1EA1;o V&#xE0; L&#x1B0;u C&#xE1;c Todo List</h3>
<p>C&#x169;ng trong file <strong>index.js</strong> th&#xEC; c&#xE1;c b&#x1EA1;n t&#x1EA1;o cho m&#xEC;nh ph&#x1B0;&#x1A1;ng th&#x1EE9;c Post(g&#x1EED;i d&#x1EEF; li&#x1EC7;u t&#x1EEB; client l&#xEA;n server). N&#xF3; s&#x1EBD; t&#x1EA1;o m&#x1ED9;t object r&#x1ED9;ng, ch&#x1EE9;a c&#xE1;c todo list &#x111;&#x1B0;&#x1EE3;c truy&#x1EC1;n v&#xE0;o. R&#x1ED3;i l&#x1B0;u n&#xF3; v&#xE0;o database &#x111;&#xE3; &#x111;&#x1B0;&#x1EE3;c kh&#x1EDF;i t&#x1EA1;o.</p>
<pre><code>// Create TodoList
router.post(&apos;/&apos;, function(req,res,next){
  var newTodo = new Todo()
  newTodo.todolist =  req.body.todolist;
  newTodo.save(function(err,TodoList ){
    if (err)  console.log(err);
    res.json(TodoList)
  })
})
</code></pre>
<h3 id="cttccctodolist">&#x110;&#x1ECD;c T&#x1EA5;t C&#x1EA3; C&#xE1;c Todo List</h3>
<p>C&#x169;ng t&#x1B0;&#x1A1;ng t&#x1EF1; nh&#x1B0; &#x1EDF; tr&#xEA;n m&#xE0; thay &#x111;&#x1ED5;i &#x1EDF; ch&#x1ED7; l&#xE0; thay Get b&#x1EB1;ng Post th&#xF4;i. Th&#xEC; khi s&#x1EED; d&#x1EE5;ng get(&#x111;&#x1ECD;c d&#x1EEF; li&#x1EC7;u t&#x1EEB; server tr&#x1EA3; v&#x1EC1; cho client). Ch&#xFA;ng ta s&#x1EBD; t&#xEC;m trong database todolist c&#xF3; bao nhi&#xEA;u d&#x1EEF; li&#x1EC7;u th&#xEC; s&#x1EBD; tr&#x1EA3; v&#x1EC1; b&#x1EA5;y nhi&#xEA;u d&#x1EEF; li&#x1EC7;u m&#xE0; t&#xEC;m &#x111;&#x1B0;&#x1EE3;c trong database.</p>
<pre><code>// Read TodoList
router.get(&apos;/&apos;, function(req, res, next) {
  Todo.find(function(err, TodoList){
         if(err) console.log(err)
        res.json(TodoList)
  })
});
</code></pre>
<h3 id="cmttodolist">&#x110;&#x1ECD;c M&#x1ED9;t Todo List</h3>
<p>Th&#xEC; &#x1EDF; tr&#xEA;n c&#x1EE7;a ch&#xFA;ng ta l&#xE0; tr&#x1EA3; v&#x1EC1; t&#x1EA5;t c&#x1EA3; c&#xE1;c todo list th&#xEC; b&#xE2;y gi&#x1EDD; ch&#xFA;ng ta s&#x1EBD; tr&#x1EA3;  v&#x1EC1; 1 todo list m&#xE0; th&#xF4;i. Ch&#xFA;ng ta c&#x169;ng s&#x1EED; d&#x1EE5;ng ph&#x1B0;&#x1A1;ng th&#x1EE9;c Get &#x111;&#x1EC3; &#x111;&#x1ECD;c d&#x1EEF; li&#x1EC7;u v&#x1EC1; m&#xE0; th&#xF4;i, nh&#x1B0;ng kh&#xE1;c &#x1EDF; ch&#x1ED7; l&#xE0; ch&#x1EC9; &#x111;&#x1ECD;c 1 todo list m&#xE0; m&#x1ED7;i todo list khi &#x111;&#x1B0;&#x1EE3;c t&#x1EA1;o th&#xEC; s&#x1EBD; c&#xF3; m&#x1ED9;t id ri&#xEA;ng ch&#xFA;ng ta s&#x1EBD; d&#x1EF1;a v&#xE0;o id &#x111;&#x1EC3; Get d&#x1EEF; li&#x1EC7;u c&#x1EE7;a t&#x1EEB;ng todo list nha.</p>
<p>V&#xED; d&#x1EE5;: Khi ch&#xFA;ng ta Get/121312(id) th&#xEC; n&#xF3; s&#x1EBD; t&#xEC;m todo list trong database c&#xF3; id n&#xE0;o m&#xE0; gi&#x1ED1;ng id m&#xE0; router &#x111;&#xE3; get kh&#xF4;ng. N&#x1EBF;u gi&#x1ED1;ng th&#xEC; s&#x1EBD; tr&#x1EA3; v&#x1EC1; k&#x1EBF;t qu&#x1EA3; d&#x1B0;&#x1EDB;i d&#x1EA1;ng json, c&#xF2;n kh&#xF4;ng gi&#x1ED1;ng th&#xEC; s&#x1EBD; log ra l&#x1ED7;i.</p>
<pre><code>router.get(&apos;/:id&apos;, function(req, res, next){
  Todo.findById(req.params.id, function(err, TodoList){
    if (err) console.log(err);
    res.json(TodoList)
  })
})

</code></pre>
<h3 id="cpnhtcctodolist">C&#x1EAD;p Nh&#x1EAD;t C&#xE1;c Todo List</h3>
<p>Mu&#x1ED1;n c&#x1EAD;p nh&#x1EAD;t todo list c&#xE1;c b&#x1EA1;n s&#x1EED; d&#x1EE5;ng method Put nh&#xE9;, th&#xEC; Put c&#xF3; ngh&#x129;a l&#xE0; ghi &#x111;&#xE8;(to&#xE0;n b&#x1ED9;) ho&#x1EB7;c t&#x1EA1;o m&#x1EDB;i 1 resource(t&#xE0;i nguy&#xEA;n). Th&#xEC; c&#xE1;ch ho&#x1EA1;t &#x111;&#x1ED9;ng c&#x1EE7;a th&#x1EB1;ng n&#xE0;y c&#x169;ng d&#x1EF1;a tr&#xEA;n id m&#xE0; th&#xF4;i.<br>
Khi ch&#xFA;ng ta s&#x1EED; d&#x1EE5;ng truy v&#x1EA5;n l&#xE0; findByIdAndUpdate() th&#xEC; n&#xF3; s&#x1EBD; t&#xEC;m trong database xem th&#x1EED; c&#xF3; th&#x1EB1;ng todo list n&#xE0;o c&#xF9;ng id m&#xE0; router &#x111;&#xE3; Put kh&#xF4;ng. N&#x1EBF;u c&#xF3; th&#xEC; b&#x1EA1;n ph&#x1EA3;i s&#x1EBD; thay &#x111;&#x1ED5;i c&#xE1;c gi&#xE1; tr&#x1ECB; m&#x1EDB;i v&#xE0; l&#x1B0;u n&#xF3; l&#x1EA1;i th&#xE0;nh m&#x1ED9;t todo list m&#x1EDB;i.</p>
<pre><code>// Update TodoList
router.put(&apos;/:id&apos;, function(req, res, next){
  var data = {
    todolist:req.body.todolist
}
  Todo.findByIdAndUpdate(req.params.id, data, function(err, TodoList){
    if (err) return next(err);
    res.json(TodoList)
  })
})
</code></pre>
<h3 id="xacctodolist">X&#xF3;a C&#xE1;c Todo List</h3>
<p>Th&#xEC; x&#xF3;a n&#xF3; c&#x169;ng t&#x1B0;&#x1A1;ng t&#x1EF1; nh&#x1B0; c&#x1EAD;p nh&#x1EAD;t th&#xF4;i nh&#x1B0;ng kh&#xE1;c &#x1EDF; ch&#x1ED7; c&#x1EAD;p nh&#x1EAD;t l&#xE0; Put c&#xF2;n x&#xF3;a l&#xE0; Delete. Th&#xEC; ph&#x1B0;&#x1A1;ng th&#x1EE9;c x&#xF3;a n&#xF3; c&#x169;ng d&#x1EF1;a v&#xE0;o id m&#xE0; x&#xF3;a, n&#xF3; c&#x169;ng t&#xEC;m id c&#x1EE7;a todo list n&#xE0;o trong database tr&#xF9;ng v&#x1EDB;i id m&#xE0; router &#x111;&#xE3; delete. N&#x1EBF;u tr&#xF9;ng th&#xEC; x&#xF3;a c&#xF2;n kh&#xF4;ng th&#xEC; log ra l&#x1ED7;i.</p>
<pre><code>// Delete TodoList
router.delete(&apos;/:id&apos;, function(req,res,next){
  Todo.findByIdAndRemove(req.params.id, function (err, TodoList ) {
    if (err) console.log(err);
    res.json(TodoList)
   });
})
</code></pre>
<h2 id="testccrestfulapi">Test C&#xE1;c RESTful API</h2>
<p>Mu&#x1ED1;n test c&#xE1;c RESTful API th&#xEC; ch&#xFA;ng ta s&#x1EED; d&#x1EE5;ng postman nha.</p>
<h3 id="tovlucctodolistsdngpostapi">T&#x1EA1;o V&#xE0; L&#x1B0;u C&#xE1;c Todo List S&#x1EED; D&#x1EE5;ng <code>Post / </code> API</h3>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1581693412/1_pgydrr_zb4ovl.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng RESTful CRUD API V&#x1EDB;i NodeJS, Express  v&#xE0; MongoDB">
<p>V&#xE0; c&#xE1;c b&#x1EA1;n c&#xF3; th&#x1EC3; t&#x1EF1; t&#x1EA1;o cho m&#xEC;nh nh&#x1EEF;ng todo list m&#x1EDB;i nha.</p>
<p><strong>C&#xE1;c b&#x1EA1;n xem th&#x1EED; trong database &#x111;&#xE3; th&#xEA;m todo list m&#xE0; m&#xEC;nh &#x111;&#xE3; t&#x1EA1;o ch&#x1B0;a nha.</strong><br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1581693732/Untitled_bvmevc.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng RESTful CRUD API V&#x1EDB;i NodeJS, Express  v&#xE0; MongoDB"></p>
<h3 id="cttccctodolistsdnggetapi">&#x110;&#x1ECD;c T&#x1EA5;t C&#x1EA3; C&#xE1;c Todo List S&#x1EED; D&#x1EE5;ng <code>Get / </code> API</h3>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1581693897/Untitled_kc8w9j.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng RESTful CRUD API V&#x1EDB;i NodeJS, Express  v&#xE0; MongoDB">
<h3 id="cmttodolistsdnggetidapi">&#x110;&#x1ECD;c M&#x1ED9;t Todo List S&#x1EED; D&#x1EE5;ng <code>Get /:id</code> API</h3>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1581694050/Untitled_guwagm.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng RESTful CRUD API V&#x1EDB;i NodeJS, Express  v&#xE0; MongoDB">
<h3 id="cpnhttodolistsdngputidapi">C&#x1EAD;p Nh&#x1EAD;t Todo List S&#x1EED; D&#x1EE5;ng <code>Put /:id</code> API</h3>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1581694236/Untitled_lthxby.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng RESTful CRUD API V&#x1EDB;i NodeJS, Express  v&#xE0; MongoDB">
<p>&#x110;&#x1EC3; bi&#x1EBF;t n&#xF3; c&#xF3; thay &#x111;&#x1ED5;i hay kh&#xF4;ng c&#xE1;c b&#x1EA1;n s&#x1EED; d&#x1EE5;ng <code>Get /:id</code> &#x111;&#x1EC3; xem th&#x1EED; todo list c&#xF3; thay &#x111;&#x1ED5;i hay kh&#xF4;ng nha.<br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1581694334/Untitled_xbmux2.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng RESTful CRUD API V&#x1EDB;i NodeJS, Express  v&#xE0; MongoDB"></p>
<h3 id="xatodolistsdngdeleteidapi">X&#xF3;a Todo List S&#x1EED; D&#x1EE5;ng <code>Delete /:id</code> API</h3>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1581694458/Untitled_zbvrr0.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng RESTful CRUD API V&#x1EDB;i NodeJS, Express  v&#xE0; MongoDB">
<p>&#x110;&#x1EC3; xem n&#xF3; &#x111;&#xE3; x&#xF3;a hay ch&#x1B0;a c&#xE1;c b&#x1EA1;n s&#x1EED; d&#x1EE5;ng <code>Get /</code> &#x111;&#x1EC3; n&#xF3; hi&#x1EC3;n th&#x1ECB; t&#x1EA5;t c&#x1EA3; c&#xE1;c todo list. N&#x1EBF;u n&#xF3; &#x111;&#xE3; x&#xF3;a r&#x1ED3;i th&#xEC; ch&#x1EC9; hi&#x1EC3;n th&#x1ECB; m&#x1ED9;t todo list m&#xE0; th&#xF4;i.<br>
<img src="https://res.cloudinary.com/dxxbnrmtx/image/upload/v1581694571/Untitled_jgjkzq.png" alt="H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng RESTful CRUD API V&#x1EDB;i NodeJS, Express  v&#xE0; MongoDB"></p>
<p><em>V&#x1EAD;y l&#xE0; xong r&#x1ED3;i nha, c&#xE1;c b&#x1EA1;n c&#xF3; th&#x1EC3; tham kh&#x1EA3;o code m&#xE0; m&#xEC;nh &#x111;&#xE3; push l&#xEA;n github <a href="https://github.com/long1211/ResfulAPI/">t&#x1EA1;i &#x111;&#xE2;y nha</a></em></p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h1 id="likt">L&#x1EDD;i K&#x1EBF;t</h1>
<p>V&#x1EAD;y L&#xE0; Xong b&#xE0;i H&#x1B0;&#x1EDB;ng D&#x1EAB;n X&#xE2;y D&#x1EF1;ng RETSful CRUD API V&#x1EDB;i NodeJS, Express  v&#xE0; MongoDB r&#x1ED3;i nh&#xE9;. M&#xEC;nh mong mu&#x1ED1;n sau b&#xE0;i topic n&#xE0;y c&#xE1;c b&#x1EA1;n c&#xF3; th&#x1EC3; n&#x1EAF;m v&#x1EEF;ng th&#xEA;m v&#x1EC1; NodeJS, Express v&#xE0; MongoDB v&#xE0; bi&#x1EBF;t th&#xEA;m c&#x169;ng nh&#x1B0; hi&#x1EC3;u r&#xF5; h&#x1A1;n v&#x1EC1; RESTful API.</p>
<p><strong>N&#x1EBF;u c&#xE1;c b&#x1EA1;n c&#x1EA3;m th&#x1EA5;y b&#xE0;i vi&#x1EBF;t c&#x1EE7;a m&#xEC;nh hay th&#xEC; c&#xE1;c b&#x1EA1;n c&#xF3; th&#x1EC3; &#x1EE7;ng h&#x1ED9; m&#xEC;nh &#x111;&#x1EC3; m&#xEC;nh c&#xF3; th&#xEA;m &#x111;&#x1ED9;ng l&#x1EF1;c &#x111;&#x1EC3; ra nh&#x1EEF;ng b&#xE0;i topic hay v&#xE0; ch&#x1EA5;t l&#x1B0;&#x1EE3;ng h&#x1A1;n &#x1EE7;ng h&#x1ED9; m&#xEC;nh <a href="https://vrdonate.vn/thanhlongdev">t&#x1EA1;i &#x111;&#xE2;y nha</a>.</strong></p>
<p><em><strong>Ch&#xFA;c C&#xE1;c B&#x1EA1;n Th&#xE0;nh C&#xF4;ng!!</strong></em></p>
<!--kg-card-end: markdown--><!--kg-card-begin: html--><iframe src="https://www.facebook.com/plugins/like.php?href=https%3A%2F%2Fwww.thanhlongdev.com%2Fhuong-dan-xay-dung-restful-crud-api-voi-nodejs-express-va-mongodb%2F&amp;width=450&amp;layout=standard&amp;action=like&amp;size=large&amp;share=true&amp;height=35&amp;appId=2794898430534168" width="450" height="35" style="border:none;overflow:hidden" scrolling="no" frameborder="0" allowtransparency="true" allow="encrypted-media"></iframe><!--kg-card-end: html--><!--kg-card-begin: html--><div class="fb-comments" data-href="https://www.thanhlongdev.com/huong-dan-xay-dung-restful-crud-api-voi-nodejs-express-va-mongodb/" data-width="100%" data-numposts="10"></div><!--kg-card-end: html-->]]></content:encoded></item></channel></rss>