# 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的部份:

**▎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的部份):

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

****
## 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/)

****
## 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)

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

老師這裡實作,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。(如下所示)

* **修正後的code:**
因此我們只要做一件事情,就是在`productPrice`前方加上一個加號,可以將型態轉成數字。這個加號叫做unary plus,可以參考[MDN的介紹](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Unary_plus)。

```javascript!
cart.totalPrice = cart.totalPrice + +productPrice;
```
如下所示,就成功以數字來相加兩個商品的價錢了。

****
## 9-124. Using Query Params
> 參考資料:[Express官方文件_req.query](https://expressjs.com/zh-tw/api.html#req.query)
> 
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(路由參數)

再額外複習一個!可參考[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的身份存在。
```
****