產品列表篇
- 使用 Bootstrap Tables 製作產品列表
- 使用 Bootstrap Modal 完成新增、修改、刪除產品等功能
關於 Modal 的內容,這裡是直接使用六角學院提供的模板
1. 製作產品列表 (Tables)
限制表格寬度
使用 Boostrap Tables 製作產品列表時,可以只調整 "要限制寬度" 的 th
,剩下的 th
會自動調整。
以這邊來說,產品名稱最需要空間,所以其他部分都限制寬度,把最多的剩餘空間通通給產品名稱。
<thead>
<th width="100">分類</th>
<th>產品名稱</th>
<th width="120">原價</th>
<th width="120">售價</th>
<th width="100">是否啟用</th>
<th width="120">編輯</th>
</thead>
使用 v-for 製作 tr
使用 v-for
時一律都建議加上唯一的 key
值。
<tbody>
<tr v-for="(item) in products" :key="item.id"></tr>
</tbody>
getProducts 事件與 init 初始化
透過 getProducts()
事件,從資料庫取得產品資料,再把資料呈現於畫面上。
// 取得產品資料
getProducts() {
// 加上 admin 才是管理者使用的
const api = `${process.env.APIPATH}/api/${process.env.CUSTOMPATH}/admin/products`;
const vm = this;
console.log(process.env.APIPATH, process.env.CUSTOMPATH);
this.$http.get(api).then(response => {
console.log(response.data);
// 存回 vm.products
vm.products = response.data.products;
console.log(vm.products);
});
},
接著再加上 created
的 Hook,讓網頁自動觸發 getProducts
事件,達到初始化 (init) 的效果。
created() {
this.getProducts();
}
2. 新增、編輯產品 (Modal)
在開始製作前,要先在 data
中新增 tempProduct
綁定所有的欄位後,用 POST
將 tempProduct
裡的資料新增到資料庫,這樣才能與資料庫的資料同步更新。
productModal
將 tempProduct
的資料與 Modal 裡的各個輸入欄位做 v-model
綁定。
大致上會有以下幾種欄位:
// 圖片網址 (input)
v-model="tempProduct.imageUrl"
// 圖片 (img)
:src="tempProduct.imageUrl"
// 標題 (input)
v-model="tempProduct.title"
// 分類 (input)
v-model="tempProduct.category"
// 單位 (input)
v-model="tempProduct.unit"
// 原價 (input)
v-model="tempProduct.origin_price"
// 售價 (input)
v-model="tempProduct.price"
// 產品描述 (textarea)
v-model="tempProduct.description"
// 說明內容 (textarea)
v-model="tempProduct.content"
// 是否啟用 (checkbox)
v-model="tempProduct.is_enabled"
:true-value="1" // 產品如果為啟用:is_enabled == 1
:false-value="0"
Button trigger productModal
原本畫面上的 Button 是透過 data-toggle="modal" data-target="#productModal"
來打開 Modal,
但是這裡要改為使用我們自訂的 Method openModal
來打開 Modal。
元件頁面要記得
import
jQuery:import $ from "jquery"
<!-- 建立新商品 Button -->
<button class="btn btn-primary" @click="openModal(true)">建立新產品</button>
<!-- 編輯 Button -->
<button class="btn btn-sm btn-outline-primary" @click="openModal(false, item)">
編輯
</button>
openModal 事件
- 按下按鈕後,等 AJAX 完成才開啟 Modal
- 透過 .modal('show') 開啟 Modal:
$("#productModal").modal("show")
- 新舊判斷:決定開啟的 Modal 是新增還是編輯功能
透過 isNew
判斷 openModal
事件是要建立新商品,還是編輯舊的商品。
若為新增,就會將 tempProduct
清空,以便新增資料到資料庫。
若為編輯,則將該 item
的值寫給 tempProduct
,待編輯後新增至資料庫。
openModal(isNew, item) {
// 新舊判斷
if (isNew) {
// 如果是新增
this.tempProduct = {}; // tempProduct = 空物件
this.isNew = true; // 代表是"新的"
} else {
// this.tempProduct = item; // 物件傳參考特性
this.tempProduct = Object.assign({}, item); // (ES6) 將 item 的值寫到一個空物件 (而且可以避免傳參考的特性之問題)
this.isNew = false;
}
$("#productModal").modal("show"); // 延後到這裡才打開 Modal
},
為避免物件傳參考的特性,這裡使用了 ES6 的 Object.assign() 語法來複製物件
updateProduct 事件
最後,當我們按下 productModal 裡的"確認"按鈕時,就會觸發 updateProduct
事件。
<button type="button" class="btn btn-primary" @click="updateProduct">
確認
</button>
如同 openModal
事件,這邊也會做新舊判斷!
關閉 Modal 的方式也改用 .modal('hide') 方法,而非原先 Button 上的 data-dismiss
屬性。
- 新增與編輯的 API 不同
- 新增產品的 HTTP 行為是
post
,編輯是用put
- 編輯產品時,
tempProduct
要符合 API 規範的格式
updateProduct() {
// 商品建立
let api = `${process.env.APIPATH}/api/${process.env.CUSTOMPATH}/admin/product`;
const vm = this;
let httpMethod = "post";
if (!vm.isNew) {
// 如果不是新的,是"修改",就改 api
api = `${process.env.APIPATH}/api/${process.env.CUSTOMPATH}/admin/product/${vm.tempProduct.id}`; // :id => ${vm.tempProduct.id}
// HTTP 行為也要改為 put
httpMethod = "put";
}
console.log(process.env.APIPATH, process.env.CUSTOMPATH);
// 符合格式 data : {...}
this.$http[httpMethod](api, { data: vm.tempProduct }).then(response => {
console.log(response.data);
if (response.data.success) {
// 如果新增成功,就把 Modal 關閉
$("#productModal").modal("hide");
// 並且再重新取得一次遠端的資料 (更新畫面)
vm.getProducts();
} else {
// 如果新增失敗,做一樣的動作,但是再補上 console.log
$("#productModal").modal("hide");
vm.getProducts();
console.log("新增失敗");
}
});
},
3. 刪除產品 (Modal)
最後剩下刪除產品的部分了,這裡跟新增、編輯產品很類似,也是使用 Button 配上 Modal,再觸發刪除的事件來完成整個功能。
Button trigger delProductModal
點擊產品列表中的刪除按鈕,觸發 openDelModal
事件來打開 delProductModal。
<button class="btn btn-sm btn-outline-danger" @click="openDelModal(item)">
刪除
</button>
openDelModal 事件
要特別注意,刪除產品這邊只要用 this.tempProduct = item
即可。
openDelModal(item) {
this.tempProduct = item;
$("#delProductModal").modal("show");
},
之前在編輯產品那邊,之所以會寫 this.tempProduct = Object.assign({}, item)
,
是因為將 item
的值寫到空物件裡面,可以避免 this.tempProduct
與 item
之間的傳參考特性,
所以才會使用 ES6 的 Object.assign({}, item)
。
delProductModal
打開刪除 Modal 後,會詢問是否要刪除,點擊確認刪除就會觸發 deleteProduct
事件。
<button type="button" class="btn btn-danger" @click="deleteProduct">
確認刪除
</button>
deleteProduct 事件
deleteProduct()
是透過 API 路徑裡的產品 ID,即 ${vm.tempProduct.id}
,來判斷要刪除的產品是哪一個。
deleteProduct() {
const vm = this;
const api = `${process.env.APIPATH}/api/${process.env.CUSTOMPATH}/admin/product/${vm.tempProduct.id}`;
console.log(process.env.APIPATH, process.env.CUSTOMPATH);
this.$http.delete(api).then(response => {
console.log(response.data);
if (response.data.success) {
// 如果刪除成功,就把 Modal 關閉,並更新遠端資料與畫面
$("#delProductModal").modal("hide");
vm.getProducts();
} else {
// 如果刪除失敗,一樣關閉 Modal 與更新畫面,但是再補上 console.log
$("#delProductModal").modal("hide");
vm.getProducts();
console.log("刪除失敗");
}
});
}
完成上述的三個功能,大概就完成產品列表的部分囉!
後記:HTTP Method 整理
我們常見的 HTTP Method 就是 get
與 post
,而這次製作編輯產品功能時是使用 put
,製作刪除功能時則是使用到了 delete
。
在本文的最後,我們就來整理一下這次用到的這四種 HTTP Method 吧!
其實有很多種 Method,但其中有六種是與網頁資料有關的 HTTP Method,分別是:
head
、get
、post
、delete
、put
、patch
get
:取得想要的資料post
:新增一項資料,如果已存在,會新增一個新的資料(結果總共會有兩筆資料)put
:新增一項資料,如果已存在,會直接覆蓋過去(結果仍然只有一筆資料)delete
:刪除資料
所以不同的 Method 會對同一件事情做不同的操作,我們再以本文中的各種針對產品的操作功能為例:
get
:取得產品列表post
:新增產品put
:編輯產品delete
:刪除產品
以上資源是我自己整理過後的筆記,若有錯誤歡迎隨時和我聯繫