Catch Axios exception in Vuex store and throw it to Vue.js method - vue.js

How to catch axios exceptions in vuex store and throw it to vue.js method ? My goal is to get this exception to be able to reset computed values bound to input using this.$forceUpdate().
In my method, I have this:
methods: {
mymet: _.debounce(
function(table, id, key, event) {
const value = event.target.value;
this.$store.dispatch('UPDATE_TRANSACTIONS_ITEM', { table, id, key, value }).then(response => {
event.target.classList.remove("is-invalid")
event.target.classList.add("is-valid")
}, error => {
console.error("Got nothing from server. Prompt user to check internet connection and try again")
this.$forceUpdate();
})
}, 500
)
}
In my vuex store, I have this:
const actions = {
UPDATE_TRANSACTIONS_ITEM ({ commit }, data) {
let company = {
[data.key]: data.value
}
axios.put(`/api/companies/${data.id}`, { company }).then( function ( response ) {
commit('SET_TRANSACTIONS_ITEM_UPDATE', { profile: data })
}).catch(function (error) {
throw error
})
}
}
const mutations = {
SET_TRANSACTIONS_ITEM_UPDATE (state, { profile }) {
state.company_data[profile.key] = profile.value
},
}

You need to make the actual action function asynchronous.
If you have the ability to use async functions, you can just await the axios call, and let the error bubble up (no need to throw anything in the action itself):
const actions = {
async UPDATE_TRANSACTIONS_ITEM ({ commit }, data) {
let company = {[data.key]: data.value};
await axios.put(`/api/companies/${data.id}`, { company }).then(() => {
commit('SET_TRANSACTIONS_ITEM_UPDATE', { profile: data })
});
}
}
Otherwise, you'll need to return a Promise and catch the error and pass it to the reject handler:
const actions = {
UPDATE_TRANSACTIONS_ITEM ({ commit }, data) {
return new Promise((resolve, reject) => {
let company = {[data.key]: data.value};
axios.put(`/api/companies/${data.id}`, { company }).then(() => {
commit('SET_TRANSACTIONS_ITEM_UPDATE', { profile: data });
resolve();
}, (error) => reject(error));
});
}
}

Related

Urql config with guest token for SSG on next js

So I have a project using the latest Next js 13, React 18, Urql 3, and using typescript
Currently, I have issues when trying to query the urql from the getstaticprops function. My urql request needs a guest token, and I'm storing the token on session storage(other suggestions ?).
It has no issue when the query is running on the client, but I have it when querying inside the function.
My concern is related to the token reading, so the server cannot read the session storage value.
I'm asking what is the better and simplest way to make this work.
Does use cookies to store guest tokens will make this work?
Or the configuration that doesn't work?
This is my current config for urql.ts
import {
createClient,
ssrExchange,
dedupExchange,
cacheExchange,
fetchExchange,
} from "urql";
import { GRAPH_URL } from "#lib/constant/env";
import type { TypedDocumentNode } from "#urql/core";
const isServerSide = typeof window === "undefined";
const ssrCache = ssrExchange({
isClient: !isServerSide,
});
const client = createClient({
url: GRAPH_URL,
exchanges: [dedupExchange, cacheExchange, ssrCache, fetchExchange],
fetchOptions: () => {
const token = sessionStorage.getItem("accessToken");
return {
headers: {
authorization: token ? `Bearer ${token}` : "",
},
};
},
});
const query = async (
query: TypedDocumentNode<any, object>,
variables?: Record<string, string | string[] | unknown>
) => {
try {
const response = await client.query(query, variables as any).toPromise();
return response;
} catch (error) {
if (error instanceof Error) console.error(error.message);
}
};
const mutation = async (
mutation: TypedDocumentNode<any, object>,
variables?: Record<string, string | string[] | unknown>
) => {
try {
const response = await client
.mutation(mutation, variables as any)
.toPromise();
return response;
} catch (error) {
if (error instanceof Error) console.error(error.message);
}
};
export { client, query, mutation, ssrCache };
And this some of the code for the blog index page
export const getStaticProps = async () => {
await fetchArticlesSummary();
return {
props: {
urqlState: ssrCache.extractData(),
},
revalidate: 600,
};
};
export default withUrqlClient(() => ({
url: GRAPH_URL,
}))(BlogPage);
This is for the fetchArticlesSummary
export const fetchArticlesSummary = async () => {
try {
const {
data: { listArticles },
}: any = await query(getListArticle);
return listArticles.items;
} catch (error) {
return {
notFound: true,
};
}
};
I also doing a setup on _app.tsx
export default function App({ Component, pageProps }: AppProps) {
if (pageProps.urqlState) {
ssrCache.restoreData(pageProps.urqlState);
}
return (
<Provider value={client}>
<Component {...pageProps} />
</Provider>
);
}
Thank you
I have followed urql documentation about server-side configuration and many others but still don't have any solutions.

Vue test method function which changes data

I just want to test a particular function that changes the data of the Vue component and doesn't return anything
data() {
return {
collections: [],
inlineSubtitle: '',
loading: false,
}
},
async loadcsv(element) {
const reader = new FileReader()
const file = element[0].file
this.toggleLoading()
reader.onload = async (e) => {
try {
const results = e.target.result
let resultSplit = results.split('\n')
let table = resultSplit.join('\n')
const rows = await d3.csvParse(table)
await Promise.all(
rows.map(async (row) => {
if (!(this.getSerial(row).length == 12)) {
if (!this.getName(row)) {
throw `Please enter Serial number`
}
if (!row.country) {
throw `Country for ${this.getName(
row,
)} is empty.`
}
//Adding row to collections
}
} catch (err) {
this.toggleLoading()
this.collections = []
this.inlineNotification('error', 'Unable to process CSV', `${err}.`)
}
I want to check in the unit test if the length of the collection array increase upon the right csv input or if there's an error if the notification fails
describe('ModalAddCollectionCSV', () => {
it('Test load csv function', async () => {
const localVue = createLocalVue()
const wrapper = mount(ModalAddCollectionCSV, {
localVue,
propsData: {
visible: true,
},
})
const fileDict = [{ file: new Blob([wrongDateFormat], { type: 'text/csv;charset=utf-8;' }) }]
await wrapper.vm.loadcsv(fileDict)
expect(wrapper.vm.inlineSubtitle).toContain('Error')
})
})

Vue JS - How to get function result in methods()

i'm trying to use this kind of structure.
I have my axios calls in a service file and then call them in vue files.
So i have this js file
const DashboardService = {
getStationList() {
let url = '/api/stations/list'
ApiService.get(url) //ApiService is an Axios wrapper
.then(response => {
console.log(response.data) //data are logged, function is called
response.data
})
}
}
export default DashboardService
Then in the Vue File i have this:
import DashboardService from '#/_services/admindashboard.service'
export default {
methods: {
getMarkers() {
let result = DashboardService.getStationList()
console.log(result) //undefined
}},
mounted() {
this.getMarkers()
}
}
I can't understand why result is undefined because che getStationList() function gets called... when the component is mounted the functions should have returned the response... how can i solve this situation?
getStationList is an async function, so you'll need to await it's result (or use then). For example:
async mounted() {
this.markers = await DashboardService.getStationList();
},
Also see this question for more details.
Next, you are missing a return in the implementation of getStationList.
const DashboardService = {
getStationList() {
const url = '/api/stations/list';
ApiService.get(url).then(response => {
return response.data;
});
},
};
or perhaps:
const DashboardService = {
async getStationList() {
const url = '/api/stations/list';
try {
const response = await ApiService.get(url);
return response.data;
} catch (error) {
console.error(error);
return [];
}
},
};
The result is undefined because getStationList is not returning anything.
You can consider turning your api call into an async function that returns the result.
const DashboardService = {
async getStationList() {
let url = '/api/stations/list';
return ApiService.get(url);
}
}
export default DashboardService
And in your component
methods: {
async getMarkers() {
let result = await DashboardService.getStationList();
console.log(result);
}
},
If you don't want to use the async await syntax. You can return a the promise from your service and utilize the result on your component, as so:
methods: {
getMarkers() {
DashboardService.getStationList().then(result => {
console.log(result);
});
}
},

async/await actions in Vuex

I am wondering how to use async/await actions in Vuex. The docs provide this syntax as an example:
actions: {
async actionA ({ commit }) {
commit('gotData', await getData())
},
async actionB ({ dispatch, commit }) {
await dispatch('actionA') // wait for `actionA` to finish
commit('gotOtherData', await getOtherData())
}
}
Following this example, I have:
import Vue from 'vue';
import Vuex from 'vuex';
import * as firebase from 'firebase';
Vue.use(Vuex);
export const store = new Vuex.Store({
state: {
// other state vars here
resource: null
},
mutations: {
// saveValues
setResource(state, payload) {
state.resource = payload;
}
},
actions: {
async getResource({ commit, dispatch }) {
var resource
console.log('resource1: ' + resource)
Vue.http.get('https://mysite/api/getResource')
.then((response) => {
console.log('get resource')
var data = response.body;
resource = data.access_resource;
console.log('resource2: '+ resource)
commit('setResource', resource);
var foo = store.getters.resource;
console.log('resource3: ' + foo);
}, (error) => {
console.log(error);
});
},
async getSomeApi({ commit, dispatch }) {
console.log('getting api');
await dispatch('getResource');
var resource = store.getters.resource;
console.log('resource4: ' + resource);
Vue.http.get('https://somesite/api/someapi?resource=' + resource)
.then((response) => {
console.log("got something from somesite")
var data = response.body;
// do something with data -> payload
dispatch('saveValues', payload);
}, (error) => {
console.log(error);
});
}
},
getters: {
resource(state) {
return state.resource;
}
}
});
However, even following the syntax example found in the docs, when I run this code, the async/await seem to be completely ignored. When I look at the logs, I see, in the following order:
getting api
resource1: undefined
resource4: null
get resource
resource2: <expected-value>
resource3: <expected-value>
I expect the console.log statements to print out in numerical order. I would appreciate if someone could clarify what I am doing wrong.
You're not awaiting the Vue.http.get() promise in the getResource() method, so await dispatch('getResource') will resolve before the HTTP request has resolved.
Trimmed down:
async getResource() {
let response
try {
response = await Vue.http.get('https://mysite/api/getResource')
} catch (ex) {
// Handle error
return
}
// Handle success
const data = response.body
}

Using promise with GraphRequestManager

Does anyone have an example on how to use promise with GraphRequestManager?
I get Cannot read property then of undefined error in my action creator.
function graphRequest(path, params, token=undefined, version=undefined, method='GET') {
return new Promise((resolve, reject) => {
new GraphRequestManager().addRequest(new GraphRequest(
path,
{
httpMethod: method,
version: version,
accessToken: token
},
(error, result) => {
if (error) {
console.log('Error fetching data: ' + error);
reject('error making request. ' + error);
} else {
console.log('Success fetching data: ');
console.log(result);
resolve(result);
}
},
)).start();
});
}
I call the above using my action creator
export function accounts() {
return dispatch => {
console.log("fetching accounts!!!!!!");
dispatch(accountsFetch());
fbAPI.accounts().then((accounts) => {
dispatch(accountsFetchSuccess(accounts));
}).catch((error) => {
dispatch(accountsFetchFailure(error));
})
}
}
I get 'Success fetching data:' in the console along with the result before the error. So the API call is made successfully. The error is after fetching the accounts in fbAPI.accounts().then((accounts) which I think is due to GraphRequestManager returning immediately instead of waiting.
I have a solution for you.
My provider look like this :
FBGraphRequest = async (fields) => {
const accessData = await AccessToken.getCurrentAccessToken();
// Create a graph request asking for user information
return new Promise((resolve, reject) => {
const infoRequest = new GraphRequest('/me', {
accessToken: accessData.accessToken,
parameters: {
fields: {
string: fields
}
}
},
(error, result) => {
if (error) {
console.log('Error fetching data: ' + error.toString());
reject(error);
} else {
resolve(result);
}
});
new GraphRequestManager().addRequest(infoRequest).start();
});
};
triggerGraphRequest = async () => {
let result = await this.FBGraphRequest('id, email');
return result;
}
That works great ! I let you adapt my solution to your system.