Home > Software design >  My component dont update when i call actions of pinia
My component dont update when i call actions of pinia

Time:05-09

I'm currently working on my first vue app, everything is working fine until i cant update my components after form submission. The API has been called but the state has not changed.

This is my store

import {requestGetHistory} from "../service/assign";

export const useHistoryDataStore = defineStore({
  id: "dataStores",
  state: () => [
    {
      dataStores: [],
    },
  ],
  getters: {
    getData: (state) => state.dataStores,
  },
  actions: {
    async setHistoryStore() {
      await requestGetHistory()
        .then((res) => (this.dataStores = res.data.result))
        .catch((e) => console.log(e));
    },
  },
});

Here is my code

emplate>
  <div style="margin: 16px 0 16px 16px">
    <a-button type="primary" v-on:click="openModal"
      >Assign Account to User</a-button
    >
  </div>

  <Suspense>
    <template #fallback>
      <div>Loading...</div>
    </template>
    <template #default>
      <div v-if="showModal">
        <AssignForm />
      </div>
    </template>
  </Suspense>

  <Suspense>
    <template #fallback>
      <SkeletonLoad/>
    </template>
    <template #default>
      <SearchHistory />
    </template>
  </Suspense>
</template>

<script>
import {defineComponent} from "vue";
import AssignForm from "../components/AssignForm.vue";
import SearchHistory from "../components/SearchHistory.vue";
import SkeletonLoad from "../layout/SkeletonLoad.vue";
import {useLayoutStore} from "../stores/layout";
import {storeToRefs} from "pinia/dist/pinia";

export default defineComponent({
  components: {SkeletonLoad, SearchHistory, AssignForm },
  setup() {
    const layoutStore = useLayoutStore();
    const { showModal } = storeToRefs(layoutStore);
    const { openModal } = layoutStore;

    return {
      openModal,
      showModal,
    };
  },
});
</script>

<style scoped>
.ant-table-striped :deep(.table-striped) td {
  background-color: #efefef;
}
</style>

AssignForm.vue When user click submit form will call API history and update new state when submit response return success. I have seen the api called but pinia not update state.

<template>
  <a-card  title="Assign Account to User" type="dashed">
    <a-form
      :model="formState"
      :wrapper-col="wrapperCol"
      @finish="onFinish"
      @finishFailed="onFinishFailed"
    >
      <a-form-item label="Business" v-on:change="openModal">
        <a-radio-group
          v-model:value="formState.business"
          v-on:change="clearForm"
        >
          <a-radio
            value="01"
            name="type"
            >Business 1</a-radio
          >
          <a-radio
            value="02"
            name="type"
            >Business 02</a-radio
          >
        </a-radio-group>
      </a-form-item>

      <div v-if="showModal">
        <a-form-item
          label="Account"
          name="accounts"
          :rules="[
            {
              required: true,
              message: 'Please select accounts!',
              type: 'array',
            },
          ]"
        >
          <a-select
            v-model:value="formState['accounts']"
            mode="multiple"
            allowClear
            style="width: 100%"
            placeholder="Account 1"
          >
            <a-select-option
              v-for="account in accountInBussiness()"
              :key="account.accountId"
              :value="account.accountId   ' / '   account.accountName"
            >
              {{ account.accountId }} / {{ account.accountName }}
            </a-select-option>
          </a-select>
        </a-form-item>
        <a-form-item label="Role">
          <a-select
            v-model:value="formState.role"
            style="width: 120px"
            disabled
          >
            <a-select-option value="view">View</a-select-option>
          </a-select>
        </a-form-item>
        <a-form-item :wrapper-col="{ span: 14, offset: 10 }">
          <a-button type="primary" html-type="submit">Assign</a-button>
          <a-button style="margin-left: 10px" @click="resetForm"
            >Clear
          </a-button>
        </a-form-item>
      </div>
    </a-form>
  </a-card>
</template>

<script>
import Swal from "sweetalert2";
import { defineComponent, onMounted, reactive, ref } from "vue";
import { useAccountDataStore } from "../stores/accountAssign";
import { requestAssignAccount } from "../service/assign";
import { useHistoryDataStore } from "../stores/historyAssign";
import { useUserStore } from "../stores/user";
import { message } from "ant-design-vue";
import { storeToRefs } from "pinia";

export default defineComponent({
  name: "AssignForm",
  setup() {
    const useAccount = useAccountDataStore();
    const historyData = useHistoryDataStore();
    const userStore = useUserStore();

    onMounted(() => {
      useAccount.setDataStore();
    });

    const { getData: accounts } = storeToRefs(useAccount);
    const { getBmIds: bmIds } = storeToRefs(userStore);

    const formState = reactive({
      business: "",
      accounts: [],
      role: "VIEW",
    });

    const resetForm = () => {
      formState.business = "";
      formState.accounts = [];
      formState.role = "VIEW";
      showModal.value = false;
    };

    const clearForm = () => {
      formState.accounts = [];
      formState.role = "VIEW";
    };

    const accountInBussiness = () => {
      if (formState.business === "01") {
        return accounts.value.filter(
          (account) => account.bmId === "123"
        );
      } else if (formState.business === "02") {
        return accounts.value.filter(
          (account) => account.bmId === "456"
        );
      }
    };

    const onFinishFailed = (errorInfo) => {
      console.log("Failed:", errorInfo);
      message.warning("Failed", 3);
    };

    const onFinish = async () => {
      await requestAssignAccount(formState)
        .then((res) => {
          Swal.fire({
            title: "Susscess!",
            text: res.data.result,
            icon: "success",
            confirmButtonColor: "#3085d6",
          }).then(async () => {
            clearForm();
            await historyData.setHistoryStore();         **<- This code dont work**
          });
        })
        .catch((e) => {
          console.log(e);
        });
    };

    let showModal = ref(false);
    const openModal = () => {
      showModal.value = formState.business.length > 0;
    };

    return {
      formState,
      onFinish,
      resetForm,
      openModal,
      showModal,
      clearForm,
      accounts,
      accountInBussiness,
      onFinishFailed,
      userStore,
      bmIds,
    };
  },
});
</script>

Component need update:

<template>
  <a-typography-title :level="2">History</a-typography-title>
  <div >
    <a-auto-complete
      style="width: 500px"
      v-model:value="searchField"
      :options="getListAccountName"
      :filter-option="filterOption"
    >
      <a-input-search
        v-model:value="searchField"
        placeholder="Search by account name or account id"
        enter-button
        style="margin: 0 0 10px 0"
      />
    </a-auto-complete>
  </div>

  <AssignHistory :history-data="filteredData()" />
</template>

<script>
import { useHistoryDataStore } from "../stores/historyAssign";
import AssignHistory from "./AssignHistory.vue";
import { storeToRefs } from "pinia/dist/pinia";
import {ref} from "vue";

export default {
  name: "SearchHistory",
  components: { AssignHistory },
  async setup() {
    const historyData = useHistoryDataStore();
    await historyData.setHistoryStore();

    const { getData: dataStores } = storeToRefs(historyData);
    const searchField = ref("");

    const filterOption = (input, option) => {
      return option.value.toUpperCase().indexOf(input.toUpperCase()) >= 0;
    };

    const getListAccountName = ref([]);

    await dataStores.value?.forEach((data) => {
      if (getListAccountName.value.indexOf(data.account)) {
        getListAccountName.value.push({
          value: data.account,
        });
      }
    });

    getListAccountName.value = getListAccountName.value.filter(
      (item, index, self) => {
        return self.findIndex((i) => i.value === item.value) === index;
      }
    );

    const filteredData = () => {
      return dataStores.value?.filter((data) => {
        return data.account
          .toLowerCase()
          .includes(searchField.value.toLowerCase());
      });
    };

    return {
      filteredData,
      dataStores,
      filterOption,
      getListAccountName,
      searchField,
    };
  },
};
</script>

<style scoped></style>

I have tried many ways but it is not working, can someone help me where am I going wrong?

CodePudding user response:

This line runs only once, it won't run when state is updated.Please check life cycle of vue3.

await dataStores.value?.forEach((data)...

May be you can use with subcribe of pinia

CodePudding user response:

Define a computed property:

const filteredData = computed(() => {
      return dataStores.value?.filter((data) => {
        return data.account
          .toLowerCase()
          .includes(searchField.value.toLowerCase());
      });
    });
  • Related