---
# System prepended metadata

title: NodeJS(Max)第 9 節： Dynamic Routes & Advanced Models
tags: [Node.js, Udemy]

---

# NodeJS(Max)第 9 節： Dynamic Routes & Advanced Models

> Udemy課程：[NodeJS - The Complete Guide (MVC, REST APIs, GraphQL, Deno)
](https://www.udemy.com/course/nodejs-the-complete-guide/)

`20231216Sat.~20231218Mon.`

:::danger
9-119 req.params
9-124 req.query

9-122 form的用法
:::

## 9-119. Extracting Dynamic Params
想讓router接收動態的資料，而Express router可以幫助我們接收動態資料，透過關鍵詞`:變數名稱`，用冒號加上變數名稱即可成功（變數名稱即我們的動態資料，例如說id）

:::success
注意！有兩個path路徑假如都為products，只是其中一個後面放動態資料，一個放一般的route，要記得把一般的route優先擺放在前面。

因為若是動態擺在前面，則express會把一般route也認作是動態資料的其中一筆資料，也就不會去執行一般的route了。

正確方法如下所示：
```javascript!
//一般route > 擺前面！才不會被動態的吃掉
router.get('/products/delete', 這裡是middleware的位置);
//動態route ":productId"
router.get('/products/:productId', 這裡是middleware的位置);
```
:::

除了需要express router中的關鍵字「冒號&變數名稱」外，還需要在controller中利用"request.params"物件。

> 可以參考[Express官方文件](https://expressjs.com/en/guide/routing.html)Route parameters的部份：
![2023-12-16 16-16-05 的螢幕擷圖](https://hackmd.io/_uploads/ryvbT05Lp.png)

**▎routes/shop.js**

我們首先在routes底下的`shop.js`中定義路徑，其中運用到了「路由參數（Route parameters）」，也就是先前提到的express roter關鍵字`:變數名稱`：
```javascript!
router.get('/products/:productId', shopController.getProduct);
```

**▎controllers/shop.js**

接著來到controllers底下的`shop.js`中，透過request的params物件，得到route parameter相對應的key（此處想取得的key就是productId），而我們要的就是該key的值。
```javascript!
exports.getProduct = (req, res, next) => {
    const prodId = req.params.productId;
    res.redirect("/");
}
```

:::info
所以再複習一次，request的params物件中，會抓取所有的路由參數（route parameters），將路由參數的名稱作為key存放在裡頭。（可參考前面的到的網站[Express官方文件](https://expressjs.com/en/guide/routing.html)Route parameters的部份）：

![2023-12-16 16-57-05 的螢幕擷圖](https://hackmd.io/_uploads/B1UdLJjLa.png)

我覺得光是這張圖就超級清楚！
:::

![image](https://hackmd.io/_uploads/SJkKE1iL6.png)

****

## 9-120. Loading Product Detail Data
> 參考資料：[JavaScript 陣列處理方法 [filter(), find(), forEach(), map(), every(), some(), reduce()]](https://www.casper.tw/javascript/2017/06/29/es6-native-array/)

![image](https://hackmd.io/_uploads/rkXJpJiU6.png)

****

## 9-122. Passing Data with POST Requests

> 1. [W3C對form的定義](https://www.w3.org/TR/html401/interact/forms)（含form裡的tag：input, textarea...）
> 2. [[Node.js] HTML Form如何設計、GET和POST方法的不同、如何透過express req.query, req.body取得資料](https://johnnychang25678.medium.com/node-js-html-form%E5%A6%82%E4%BD%95%E8%A8%AD%E8%A8%88-get%E5%92%8Cpost%E6%96%B9%E6%B3%95%E7%9A%84%E4%B8%8D%E5%90%8C-%E5%A6%82%E4%BD%95%E9%80%8F%E9%81%8Eexpress-req-query-req-body%E5%8F%96%E5%BE%97%E8%B3%87%E6%96%99-fa43bd73909d)

![image](https://hackmd.io/_uploads/rkOLiToLT.png)

上方圖片提到的，input的name attribute，在傳送資料時會變成資料的key-value pair，而如果我們想讀取它，就是利用req.body取得這對key-value。

![image](https://hackmd.io/_uploads/ryNDsasLp.png)

老師這裡實作，Add to cart這個按鈕也能有POST request的方法，就是一樣建立form表單，只是將input給hidden起來。

:::success
補充！

若method使用POST，則可以透過req.body物件中取input的name，來獲得input的value。

例如上方input name為productId，若我們想獲得input value(即商品的id編號)，則可以透過`req.body.productId`
:::

```javascript!
<%- include('../includes/add-to-cart.ejs', {product: product}) %>
```
在ejs中，可以用`{}`來裝一些local variable，讓那些local variable可以傳至其他ejs檔案中使用。

****

## 9-123. Adding a Cart Model
* **原先的code:**
    ```javascript!
    cart.totalPrice = cart.totalPrice + productPrice;
    ```

    但會造成相加的時候，是以String的特興趣相加，例如說一個物品標價300，則照上方code去相加兩個相同物品的標價，會變成"300300"，而非我們希望的600。（如下所示）

    ![2023-12-17 15-46-07 的螢幕擷圖](https://hackmd.io/_uploads/ByLU_mh86.png)

* **修正後的code:**
    因此我們只要做一件事情，就是在`productPrice`前方加上一個加號，可以將型態轉成數字。這個加號叫做unary plus，可以參考[MDN的介紹](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Unary_plus)。
    ![2023-12-17 15-58-22 的螢幕擷圖](https://hackmd.io/_uploads/H1G4cX28a.png)

    ```javascript!
    cart.totalPrice = cart.totalPrice + +productPrice;
    ```

    如下所示，就成功以數字來相加兩個商品的價錢了。
    ![2023-12-17 15-57-47 的螢幕擷圖](https://hackmd.io/_uploads/SJRWcQhL6.png)

****

## 9-124. Using Query Params
> 參考資料：[Express官方文件_req.query](https://expressjs.com/zh-tw/api.html#req.query)
> ![2023-12-17 16-34-47 的螢幕擷圖](https://hackmd.io/_uploads/rk_t7EhLp.png)


query指的網址中？（問號）之後的那串字串，而req.query是一個物件，用來收集所有route中的query字串。

:::info
req.query跟[9-119](https://hackmd.io/@noz915/rJ8_M0cLp)的req.params用法頗像的。
差別在於：
`>` req.query抓取的是URL中的query(即問號之後的字串)
```
Request URL: http://......?edit=true&title=new
req.query: { "edit": "true", "title": "new" }
```
`>` req.params抓取的是URL中的route parameters(路由參數)

![2023-12-16 16-57-05 的螢幕擷圖](https://hackmd.io/_uploads/B1UdLJjLa.png)

再額外複習一個！可參考[19-122](https://hackmd.io/@noz915/rJ8_M0cLp#9-122-Passing-Data-with-POST-Requests)
`>` req.body抓取的是input中的name attribute，在傳送表單時，會成為資料的一組key-value pair。
:::

```!
[註] 上方藍色區塊中req.query的部份，"edit": "true"要注意只能用"true"，不能用true，這是為了確保"true"能一直以String的身份存在。
```

****