iT邦幫忙

2023 iThome 鐵人賽

DAY 22
0
Vue.js

試試用Vue建立網站吧系列 第 22

Day22-試試Vue3-口袋餐廳選單(5-2)

  • 分享至 

  • xImage
  •  

前置作業1:調用 Pinia store 資料
<script></script> 將 LoginStore.js 檔裡的 useLoginStore 方法取出。透過 computed 監控資料更動時就重新渲染畫面的特性,把 Pinia store 剛更新的會員 name 、 email 、 id 給顯示。再運用 mapState 取用 Pinia store 資料。

前置作業2:取得網路請求 axios 的路徑
created 裡的 apiUserResUrl 與 apiUserResIdUrl 是網路請求的路徑。路徑會在提交表單和畫面下方渲染出的口袋清單被使用,為使這兩個函式能取用該變數(全域變數),將之定義於此。created 是 Vue 生命週期中實例創建完成階段,可訪問 data 、 computed 、 watch、 methods 上的方法和數據。此時可把 apiUserResUrl 與 apiUserResIdUrl 在 data 裡的初始值給重新賦值。

vue 的生命週期介紹可以參考此篇文章

(3-3)動作拆解-表單提交
表單提交只有觸發方法的說明。

1.表單提交的限制

  • 表單中所有欄位必須有值才可提交表單。否則跳出「欄位不可空值!」的警告訊息。

2.導出的資料增加屬性
<script></script> 中資料實體增加以下屬性。

  • 屬性 saveRes 存放要寫回會員餐廳 API 的資料(品牌受眾、品牌名稱、地址)。屬性有 saveBrandName 、 saveType 、 saveAddress 。
  • 屬性 apiUserResUrl 、 apiUserResIdUrl 是網路請求 axios 的路徑。先設定初始值為空字符串,稍後在 created() 會定義其值。

3.當表單按鈕「加入口袋」被操作時

  • 會觸發方法裡的 submitPucket() 函式
    • 禁止按鈕提交的默認(如頁面刷新)行為,使用 event.preventDefault(); 處理。
    • 先判斷所有欄位是否填妥,若有才進行以下動作。若否則跳出警告訊息。
      • 使用 axios.get() 取得會員廳餐 API 資料,回傳的資料為一陣列,取裡面的物件賦值給變數 userData 。
      • 定義變數 newRestaurant 為物件型態,裡面的屬性 brandName 、 address 、 type 要接收資料實體 saveRes 的 saveBrandName 、 saveType 、 saveAddress 屬性值。
      • 避免會員喜愛的餐廳有重複,這邊使用陣列方法 some 檢查會員餐廳 API 中屬性 userRestaurants 裡面是否有已存在的 brandName(品牌名稱)。陣列方法 some 檢查陣列中是否至少有一個元素符合指定條件,若有返回 true ;否則返回 false 。
        • 假設要添加口袋的品牌名稱已存在,畫面跳出「該餐廳已存在!」。若否則將變數 newRestaurant 內容用 push 方法新增資料到會員餐廳 API 中屬性 userRestaurants 裡面。寫回會員餐廳 API 要用 axios.put() 進行網路請求。
    • 表單提交後讓所有欄位重置成預設值。
<template>
  ...
  <form>
    ...
    <div class="d-flex justify-content-end">
      <button
        class="btn btn-lg btn-primary mb-4"
        type="submit"
        @click="submitPucket()">
        加入口袋
      </button>
    </div>
  </form>
  ...
</template>
<script>
import axios from "axios";
import { mapState } from "pinia";

// 定義好的 store 賦值給變數 useLoginStore
// 在元件中引入並呼叫 useLoginStore() 來訪問 store
import { useLoginStore } from "../../components/LoginStore.js";

export default {
  data() {
    return {
      restaurants: [],
      filterRes: {
        filterBrandName: [],
        filterType: [],
        filterAddress: [],
      },
      tempRes: {
        selectBrandName: "",
        selectType: "",
      },
      saveRes: {
        saveBrandName: "",
        saveType: "",
        saveAddress: "",
      },
      ...
      apiUserResUrl: "",
      apiUserResIdUrl: "",
      ...
    };
  }
  methods: {
    ...
    submitPucket() {
      event.preventDefault();

      if (
        (this.saveRes.saveBrandName !== "") &
        (this.saveRes.saveAddress !== "") &
        (this.saveRes.saveType !== "")
      ) {
        axios.get(this.apiUserResUrl)
          .then((res) => {
            // res.data是陣列要變成物件後面才能用push,所以取第一個內容(這裡是物件)
            const userData = res.data[0];
            const newRestaurant = {
              brandName: this.saveRes.saveBrandName,
              address: this.saveRes.saveAddress,
              type: this.saveRes.saveType,
            };

            // 使用陣列方法 some 檢查會員餐廳API是否有已存在的brandName
            const exists = userData.userRestaurants.some(
              (item) => item.brandName === newRestaurant.brandName
            );

            if (!exists) {
              userData.userRestaurants.push(newRestaurant);
              alert("口袋添加成功");
              return axios.put(apiUserResIdUrl, userData);
            } else {
              alert("該餐廳已存在!");
            }
          })
          .catch((error) => {
            console.log(error);
            alert("口袋添加失敗");
          });
      } else {
        alert("欄位不可空值!");
      }
    }

    this.tempRes.selectType = "";
    this.tempRes.selectBrandName = "";
    this.filterRes.filterAddress = "";
  },
  ...
  created() {
      this.apiUserResUrl = `http://localhost:3002/userRes?email=${this.userEmail}`;
      this.apiUserResIdUrl = `http://localhost:3002/userRes/${this.userId}`;
    }
  },
  ...
  // 監聽data
  computed: {
    ...mapState(useLoginStore, {
      // 'name' 是 store 中的狀態名,'userName' 是在組件中的名稱
      userName: (state) => state.name,
      userEmail: (state) => state.email,
      userId: (state) => state.id,
    }),
  },
};
</script>

附上用 axios.put() 回寫到會員餐廳 API 結果。
回寫會員餐廳結果


上一篇
Day21-試試Vue3-口袋餐廳選單(5-1)
下一篇
Day23-試試Vue3-口袋餐廳的口袋清單(1)
系列文
試試用Vue建立網站吧30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言