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());
});
});