Show loading property on Pageload with nuxt - vue.js

I have a nuxt project that is working well. However on the loading of the page a async method is performed.
import charge from '~plugins/charge'
export default {
asyncData (context, callback) {
const subscription = context.params.id;
charge.getAll(subscription, function(result){
let data = result.data;;
callback(null, data)
});
}
}
My Problem is, that the page stays with until the async operation has been performed. How can i Show a loader until the function returns a result?

There is an official example in Nuxt.js repo. Check out the Custom-Loading example.

Related

Vue2 Composition Api - How do I fetch data from api?

I am using Vue2.6 with composition api.
I need to reroute to different pages depends on an api response.
Can someone please guide me, please?
I tried using onBeforeMount but it renders the UI elements then rerouted to the corresponding page to the api response..so I can see a flash of the wrong UI..
setup() {
const myData = 'myData';
onBeforeMount(async () => {
try {
const results = await fetchData();
// do reroute depends on results response
}
} catch (err) {
console.log(err);
}
});
return {
myData,
};
I also tried adding async in the setup method but it errored saying my ref variables "Property or method "myData" is not defined on the instance but referenced during render."
async setup() {
const myData = 'myData';
onMounted(async () => {
try {
const results = await fetchData();
// do reroute depends on results response
}
} catch (err) {
console.log(err);
}
});
return {
myData,
};
It looks like you're trying to handle routing (re-routing) dynamically from inside a component. I can't see the rest of the apps, so can't speak to the validity of such a solution, but would like you dissuade you from doing that. routing logic should, IMO, not be handled in a component. The components should mostly just handle the template and user interaction. By the time you're rendering a component, that API should have been resolved already.
I would recommend to resolve the API response before the route is
even completed. You or use a navigationGuard to resolve the API during the route execution. This functionality is asynchronous, so you can await the response before proceeding.
Alternatively, if you really want to handle it in the component, you will have that delay while the API is resolving, but you can implement some loader animation to improve the experience.

Rendered hook / serverPrefetch Vue3 SSR

I've been trying to make a Vue3 app work with SSR and I'm stuck in the serverPrefetch part. I want to load some data in the server, save it in the store and pass it to the client but it looks like the rendered hook referred to here: https://ssr.vuejs.org/guide/data.html#final-state-injection is not called anymore (and therefore the server store is not updated after the data fetch). Do you know what the right way to do this with Vue3 is?
This is my server-entry.js
import { _createApp } from "./app";
export default async (context) => {
const { app, router, store } = _createApp();
router.push(context.url); // push router entry
await router.isReady();
context.rendered = () => {
// this is never executed!!!
context.state = store.state; // this gets embedded in the final HTML as window.__INITAL_STATE__
};
return app;
};

Auth0 route guard not working with Nuxt middleware

What is the correct pattern to implement Auth0 route guards in Nuxt?
I've adapted the Auth0 sample code to create the following middleware:
import {getInstance} from '~/plugins/auth';
export default function () {
const authService = getInstance();
const fn = () => {
// If the user is authenticated, continue with the route
if (!authService.isAuthenticated) {
authService.loginWithRedirect({
appState: {targetUrl: 'http://localhost:3000'},
});
}
};
// If loading has already finished, check our auth state using `fn()`
if (!authService.loading) {
return fn();
}
// Watch for the loading property to change before we check isAuthenticated
authService.$watch('loading', loading => {
if (loading === false) {
return fn();
}
});
}
Notice that before the authentication status of Auth0 can be accessed, we must wait for the the instance to finish loading. The Auth0 sample code does this by using $watch.
My middleware code "works" but has the issue of briefly displaying the protected pages before the async $watch triggers. Is there any way to wait and block the route from continuing to render until Auth0 has finished loading and its auth status can be accessed?
I've also tried using almost the exact same code Auth0 provides without my own modifications within the beforeRouteEnter hook of the Nuxt pages. This has the same issue which begs the question as to why the Auth0 example presumably works in VueJS using beforeRouteEnter but not in Nuxt?
Solved it!
A middleware can be asynchronous. To do this return a Promise or use async/await.
https://nuxtjs.org/docs/2.x/directory-structure/middleware/
I simply wrapped my middleware script in a promise. I resolved it if the user is able to pass, otherwise I redirected them to the Auth0 login.
import {getInstance} from '~/plugins/auth';
export default function () {
return new Promise(resolve => {
const authService = getInstance();
const fn = () => {
// If the user is authenticated, continue with the route
if (!authService.isAuthenticated) {
return authService.loginWithRedirect({
appState: {targetUrl: 'http://localhost:3000'},
});
}
resolve();
};
// If loading has already finished, check our auth state using `fn()`
if (!authService.loading) {
return fn();
}
// Watch for the loading property to change before we check isAuthenticated
authService.$watch('loading', loading => {
if (loading === false) {
return fn();
}
});
});
}
It was also important to return the loginWithRedirect to make sure that it didn't go on to resolve the promise outside of the if block.

Accessing Vue Nuxt plugins in layouts using fetch()

Wanted to ask if I am doing this right, it feels clunky. I am accessing a plugin in a Nuxt layout component. I want to dynamically generate content within the layout via the new fetch() api.
async fetch() {
this.notifications = await this.$root.context.app.contentfulClient.getNotifications()
this.treatments = await this.$root.context.app.contentfulClient.getTreatments()
},
It works as expected, but it seems a long handed way of accessing the plugin methods. Is this architecturally bad practice?
Nuxt plugins normally add properties to the Nuxt context, making them available from a component's this without having to explicitly drill into the context like you're doing.
Assuming your plugin injects contentfulClient like this:
// ~/plugins/contentfulClient.js
export default ({ app }, inject) => {
inject('contentfulClient', {
async getNotifications() {/*...*/},
async getTreatments() {/*...*/},
})
}
Then your component could use it like this:
async fetch() {
this.notifications = await this.$contentfulClient.getNotifications()
this.treatments = await this.$contentfulClient.getTreatments()
},

Prevent page rendering before data is returned

I am using Nuxtjs and have a page that returns some data from a vuex store
created () {
this.$store.dispatch('cases/loadcases');
},
How do I get my page to wait until the data has been returned before rendering please?
Many Thanks
You can use nuxt asyncData/fetch methods.
Here some example of page that will be loaded after 10 seconds:
function timeout(ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
export default {
async fetch({ store, redirect }) {
await timeout(10000) // emulate long api call
}
}
You can't. All you can is show some kind of loader (component), or simply not show the component during loading with v-if or v-show directive. That's all.