How to deal with fragment GET parameters in Vue Router? - vue.js

After trying a backend implementation of Gitlab's OAuth using Web Application Flow, I'm trying out Implicit Grant in my Vue frontend.
The access code that the API sends me is in fragment url parameter format. Which means it uses the hash symbol #foo=bar&moo=var instead of standard ?foo=bar&moo=var which conflicts with the default Vue Router configuration.
After trying history mode in the Vue Router, which dosent use the # in his urls, I can access the Vue Router parameter with $route.hash. My current problem is that I have to split and trim the parameters myself with something like the following:
const params = this.$route.hash.split('&').map(part => part.replace(/#/, ''));
const parsedParams = {};
params.forEach(param => {
const parts = param.split('=');
parsedParams[parts[0]] = parts[1];
});
which outputs { foo: "bar", moo: "var" }
Is there a better or more standart way to deal with fragment parameters in VueRouter? If not, is there a standart solution to this outside of Vue?

It seems to me that my code snippet is a good enough solution, although I was expecting some support for OAuth standarts in vue. Maybe my expectations are too high?
This is what I ended up using
const parsedParams = {};
this.$route.hash.split('&')
.map(part => part.replace(/^#/, ''))
.forEach(param => {
const parts = param.split('=');
parsedParams[parts[0]] = parts[1];
});
you can also uri decode your parameters directly from within this loop using
parsedParams[parts[0]] = decodeURIComponent(parts[1]);

Related

Svelte Dynamic Route Param - Passing Multiple Params?

Is there a way to pass multiple params into a dynamic route?
For example I have a search result page that is looping through results
{#each results as result}
<a href="../book/{result.key}">
{result.title}
</a>
{/each}
I am passing the key to a [slug] route and I am using the key to call an API.
My end goal is to have the result.title be the dynamic route param, but I also want to pass the result.key so I am able to call the API.
This post: Passing mulitple parameters to dynamic route in Svelte is over a year old and I was wondering if there is now a way to do this and I would like to keep the route as /title instead of /title/key or /key/title as suggested in that post.
You will have to embed both of them somehow in the URL. Perhaps a construction like /book/<title>?key=<key> would do for you ? I notice that would be the 'other option' from the post you linked, but the answer there is outdated.
Nowadays you would either in +page.sveltejs or +page.server.js do
export const load = (async ({ params, url }) => {
const title = params.title;
const key = url.searchParams.get('key');
}
But here you would have to be aware that key could be empty.
One last option (that I personally don't like) is to have the urls in the form of /book/<title>-<key>, this is something you sometimes see with product sites.
In this case your file will be called /book/[title]-[key]/+page.svelte
And you just extract the params as normal:
export const load = (async ({ params }) => {
const { key, title } = params;
}

migrating from global mixins in vue2 to global composables in vue3

I"m porting my new app from vue2 to vue3. Since mixins are not recommended way of reusing code in vue3, Im trying to convert them into composable.
I've 2 mixins (methods) __(key) and __n(key, number) in mixins/translate.js which will translate any word into the app's locale.
module.exports = {
methods: {
/**
* Translate the given key.
*/
__(key, replace = {}) {
// logic
return translation
}
Now this is how I converted it as
Composables/translate.js
export function __(key, replace = {}) {
// logic
return translation
}
and since I need these functions to be accessbile in every component without explicitly importing. I'm importing it in app.js
import {__, __n} from '#/Composables/translate.js';
Questions
__() is not accessible in every component. How to make this function accessible in every component without explicit import
Is this the right of doing things?
These functions are required essentially in every component, declaring them in every component is impractical.
#1, You can put it into the globalProperties object
import {__, __n} from '#/Composables/translate.js';
const app = createApp(AppComponent);
app.config.globalProperties.__ = __;
app.config.globalProperties.__n = __n;
#2, though opinion based, importing for every component that needs it would be my preferred way.

Business logic in Vue 3 + Pinia

Let's say I have a simple webshop application using Vue 3. Whenever the user adds an item to the cart, I store it locally in Pinia and I send this event information to the backend as well.
By default what I would do is I would add a action to the Pinia store like addItemToCart() which would update the local cartItems reactive variable and would also send the request to the backend like POST http://localhost/api/update-cart.
My idea is to introduce a service layer into my application.
I would create a service like:
const useCartService = () => {
const cartStore = useCartStore()
const updateCartApi = useUpdateCartApi()
const addItemToCart = async (item) => {
cartStore.loading = true
await updateCartApi.mutate(item)
cartStore.items.push(item)
cartStore.loading = false
}
return {
loading: cartStore.loading,
addItemToCart,
}
}
Would it make sense to separate the business logic from the Pinia store like this? Is it considered as a anti-pattern, or is this approach commonly used in Vue?

Aggrid vue i18n: Grid header name not translated without refresh after change language

I'm using i18n for localization in my project but whenever i change the language, all page's translate is okay except grid header names! Its getting normal when i refresh the page.How can fix this situation without refresh ?
You can fix this by calling the refreshHeader function on the reader API.
try this :
this.gridApi.refreshHeader();
where the gridApi is the API object you get from the onGridReady event params.
EDIT, how to get the gridApi :
the gridApi u get from the params of the onGridReady method being called by the AgGrid component.
if you are using reactJs, an attribute named onGridReady in your agGrid component would accept that function.
onGridReady = params => {
this.gridApi = params.api
this.gridColumnApi = params.columnApi
...
}
If you are using headerName, maybe try to use computed() function to get ColDef
Ex:
const colDef = computed(() => // coldef here)

Watch for URL query parameter in Vuex store

I am using Nuxt.js with Vuex and I would like to trigger a mutation when somebody enters in my web with a certain parameter (ex: https://example.com/?param=abc), and pass the parameter to a state.
I tried to check the documentation of the watchQuery property https://nuxtjs.org/api/pages-watchquery, but there’s no examples about how to do this, I just found this How to watch on Route changes with Nuxt and asyncData but I can’t see any way of how to write an action in Vuex store with watchQuery.
I tried writing:
actions: {
watchQuery: true,
asyncData ({ query, app }) {
const { start } = query
const queryString = start ? `?start=${start}` : ''
return app.$axios.$get(`apps/${queryString}`)
.then(res => {
commit('setParam',res.data);
})
},
}
But that syntax is not allowed.
Any help would be welcome, thanks in advance!
From my understanding watchQuery sets a watcher for query string, meaning it's waiting for the query to change while the page is already rendered making it possible to call methods like asyncData() again.
Since you only want to save a certain parameter when the user enters the page and then pass the paramater to a state you just need to move your asyncData method to a page from which you want to get the parameter, you will also need to extract store and query from the context automatically passed into asyncData and then using the store and query save the query parameter into your state.
Here is a simple demonstrantion
// Your page from which you want to save the param
export default {
asyncData({store, query}) { // here we extract the store and query
store.state.somethingForSavingTheParam = query.nameOfTheParamYouWantToSave
// instead of using store.state you could use store.commit(...) if that's what you want
}
}