Dynamically decide when to use vue router - vue.js

I have a big web application which I am building with vuejs and laravel.
Along the way, I have to switch between
<router-link></router-link> and <a></a> tags
so I build a template that I have a link on it I want it to automatically detect if vue <router-view></router-view>
is available otherwise just use the normal href tag
The below code is the function I have assigned to the click function but it turns out not to be working
try {
this.$router.push("/cart");
} catch (error) {
window.location.href = "/cart";
}
}
My question is
is there any way I can dynamically detect the presence of vue router and as well decide on which tag to use.
Either
window.location.href
or
this.$router.push()

Related

How to use Vue hooks inside a custom plugin?

I am writing custom plugin and need to create CSS custom properties from inside of it. In SPA mode everything is fine, but SSR mode is where the troubles coming. What I need is just to put my method inside of a mounted() hook. Is it possible?
export default {
install(app, options) {
createCSSVariables()
function createCSSVariables(options) {
const root = document.documentElement // this can't be working on server side :(
root.style.setProperty('--font-family', options.font_family)
root.style.setProperty('---accent', options.colors.accent)
}
}
}
I am using nuxt and could just use 'client' flag in plugin, but since it is for UI library, this will not help much - in this scenario all the elements would flicker right after mount

Initate Session on page load

I have a requirement where I need to set Global Axios header and refresh session(Calling multiple Api's). In vuejs we would have a App.vue which is the entry point for our application we would do these types of processing in that.
App.vue
export default {
async created(){
await this.$store.dispatch('initateSession');
}
}
The benefits of doing this is that this is called only once(not on every route change), and on every page load, I am looking to implement the same functionlity in Nuxt.
Now as we dont have any App.vue in case of Nuxt one solution that i could think off is to create a middleware for this , which can work but that will be called on every route change I dont want that, does anyone know any workaround for it?
Instead of middleware you can create a plugin:
plugins/session.js:
window.onNuxtReady(() => {
// Do something
})
And then add it to the plugins section inside nuxt.config.js.

Recommended way of waiting on an Apollo query before rendering the next page?

When using the Apollo module in a Nuxt app, the default behavior when changing routes is to render the new page immediately, before data has been fetched via Apollo.
This results in some pretty janky rendering experiences where the page does a partial render and very soon after completes rendering with data from the server, making everything on the page shift due to the changing size of components that now have data. This looks pretty bad because the data actually comes back fairly quickly, so it would be fine to wait for the data to return before rendering the new route.
What's the recommended way of waiting on the Apollo queries on a page (and its subcomponents) to complete before rendering the page?
(There's a related question that's not specific to Nuxt, but I'm not sure how to translate the recommendation to a Nuxt app.)
I'd love to see a code example of using beforeRouteEnter to fetch data via Apollo and only entering the route once the data is fetched.
Haven't used this module before, but it should be like any other async action you want to perform before page rendering in Nuxt.
It only depends if you want to pre-fill the store:
https://github.com/nuxt-community/apollo-module#nuxtserverinit
https://nuxtjs.org/guide/vuex-store/#the-nuxtserverinit-action
or only one page:
https://github.com/nuxt-community/apollo-module#asyncdatafetch-method-of-page-component
https://nuxtjs.org/guide/async-data
You can use async/await or promises if you have more than one request before page should be rendered.
When async actions are finished, Nuxt starts rendering the page. This works for SSR and if you navigate to pages on the client (nuxtServerInit will only fire once when real request is made, not when navigating on client side).
Side note: beforeRouteEnter is usually used, to validate params and check if the route is allowed.
did you try disabling the prefetch?
prefetch: false
The best approach is to use the loading attribute:
<template>
<div v-if="!this.$apollo.loading">
Your product: {{product}}
</div>
</template>
<script>
export default {
name: "Product",
apollo: {
product: {
query: productQuery,
variables() {
return {
productId: this.productId
}
}
}
}
}
</script>
I'm unfamiliar with Apollo, but I think this is what you are looking for:
// Router.js
beforeRouteEnter(to, from, next)
{
executeSomeApolloPromise().then((data) => {
// The promise has now been complete; continue to the component.
next((vm) => {
// You have access here to the component instance via `vm`.
// Note that `beforeRouteEnter` is the only guard that has this.
vm.someApolloData = data;
});
});
}
See https://router.vuejs.org/guide/advanced/navigation-guards.html#per-route-guard

Nuxt JS LocalStorage in Universal mode not working

I'm working on a Nuxt JS application which utilises LocalStorage. When compiling in SPA mode it functions correctly, however I need to switch my project to universal mode to get my SEO meta titles and descriptions to work when generating my project, after switching I get an error on a few pages which utilise LocalStorage:
localStorage is not defined
Has anyone got any suggestions to fix this?
You don't have localStorage because there is no such thing in Node.js environment. You also don't have window and document objects.
https://ssr.vuejs.org/guide/universal.html#access-to-platform-specific-apis
Nuxt.js uses Vue SSR under the hood.
However, you still have a store (Vuex). And it will be synchronized between node and browser.
I needed data to persist between sessions for GDPR. You can use the mounted life cycle event and wait for window.localStorage to be available. Then assign it to a data property and add a v-if in a wrapper tag so the page doesn't start rendering before localeStorage is available. I'm doing this with a static nuxt build:
<div v-if="localStorageReady">
Awesome stuff here...
</div>
data() {
return {
localStorageReady: false,
}
},
mounted() {
if (window.localStorage) {
this.localStorageReady = true
}
}

Vue instance inside another Vue instance

I’m integrating Vue with a CMS called AEM thats works basically as component base system like Vue works too. But instead of having a webpack and imports of .vue files, every component on this CMS is a new Vue instance (new Vue({…})). So on my page I have a lot of Veu instances that communicate with each other using the same store (vuex).
This is actually working fine, but I have a scenario when I need a CMS component inside another. Since both this components are a unique vue instance and the “el” property from the parent includes the “el” from the child, the child component doesn’t work.
I know that this is not the expected use of this lib, but is there any way that I can tell or share the same “context” on both vue instances or even another approach for this scenario.
Thx,
Alexandre.
There should be only one instance of Vue.
I suggest you to create single empty Vue instance inside the body tag
All your existent Vue instances transform into components
Register all components in the root Vue instance
With this approach it will be fine to nest one component into another
You should use only one Vue instance as #shrpne mentioned.
If you keep instantiating Vue instances for every component, you'll run into issues while debugging or with component communication and overall this becomes very missy and you miss out on parent-child communication and inheritance provided by Vue.
I don't know about your Vue architecture, but I am currently working on a manual for working with Vue in AEM.
The basic premise is to use Vue's inline-template and vanilla-js, No typescript, nodeJS build, jsx or anything else at build time, just vanilla-js so that when your page is loaded and even before your js bundle is present, the DOM is already there, you just need to mount components by instantiating one Vue instance that will mount all components. This is also great for SEO (unless you plan to server-side render Vue components in java... which is possible theoretically, but good luck!)
Here is a sample AEM/Vue component:
<simple-counter inline-template>
<button v-bind:style="style" v-on:click="add">${properties.clicksText || 'clicks: '} {{ counter }}</button>
</simple-counter>
the JS:
notice how it does not have a template in the JS, because it's inlined above
Vue.component('simple-counter', {
data: function() {
return {
counter: 0,
style: {
color: 'red',
width: '200px'
}
}
},
methods: {
add: function() {
this.counter = this.counter + 1;
this.style.color = this.style.color == 'red' ? 'green' : 'red';
}
}
})
You can build more AEM components in this fashion, then at the end of your clientlib when all your Vue components have been registered, you can run:
new Vue({ el: '#app'})
This, off course, assumes that your page body or some other parent element has the id: app.
The second part of this, how do you enable re-mount of components after authoring dialog is submitted, you could just refresh the page.
I have a question about how we can re-mount components without refreshing the page here
The basic idea is to add an afteredit event to the component and run a new Vue instance only on the newly mutated component... still working on that
Solution:
Replace all new Vue(...) stuff into Vue.component(...) Vue.extend(...) etc for better interface management.
Only use ONE Vue instance witch is new Vue({...options})
Slice your vuex store into modules.
Google teacher knows everything.