I got blank when use async setup() in Vue3 with router-view - javascript

When I use async setup () in Vue 3, my component disappears. I used the solution found here:
why i got blank when use async setup() in Vue3 ... it worked, but I have a blank page when I am using the router-view.
<template>
<div v-if="error">{{error}}</div>
<Suspense>
<template #default>
<router-view></router-view>
</template>
<template #fallback>
<Loading />
</template>
</Suspense>
</template>
<script>
import Loading from "./components/Loading"
import { ref, onErrorCaptured } from "vue"
export default {
name: 'App',
components: { Loading },
setup() {
const error = ref(null)
onErrorCaptured(e => {
error.value = e
})
}
}
</script>
main.js:
import { createApp } from 'vue'
import router from "./router"
import App from './App.vue'
createApp(App).use(router).mount('#app')
When I replace router-view with one of my components, it shows up.
Router:
import { createWebHistory, createRouter } from "vue-router";
import Portfolio from "#/views/Portfolio.vue";
import Blog from "#/views/Blog/Blog.vue";
import Detail from "#/views/Blog/Detail.vue";
import NotFound from "#/views/NotFound.vue";
const routes = [
{
path: "/",
name: "Home",
component: Portfolio,
},
{
path: "/blog",
name: "blog",
component: Blog,
},
{
path: "/blog/:slug",
name: "detail",
component: Detail,
},
{
path: "/:catchAll(.*)",
component: NotFound,
},
];
const router = createRouter({
history: createWebHistory(),
routes,
});
export default router;

<Suspense>'s default template should contain an async component (i.e., one with async setup()), but you've put <router-view> in there instead.
You'd have to refactor the <Suspense> into its own wrapper component (e.g., HomeView.vue) that contains the async component, leaving <router-view> itself in App:
<!-- App.vue -->
<template>
<router-view />
</template>
<!-- HomeView.vue -->
<template>
<Suspense>
<template #default>
<MyAsyncComponent />
</template>
<template #fallback>
<Loading />
</template>
</Suspense>
</template>
Then update your router config to use that wrapper:
const routes = [
{
path: '/'
name: 'Home',
component: HomeView
},
//...
]

Vue doc has an example to show how to use <Suspense> with other components
<RouterView v-slot="{ Component }">
<template v-if="Component">
<Transition mode="out-in">
<KeepAlive>
<Suspense>
<!-- main content -->
<component :is="Component"></component>
<!-- loading state -->
<template #fallback>
Loading...
</template>
</Suspense>
</KeepAlive>
</Transition>
</template>
</RouterView>
Ref: https://vuejs.org/guide/built-ins/suspense.html#combining-with-other-components

Related

How to build page not found in vue 3

I'm doing a project with vue 3 and I have a problem with generate a pageNOTfound. So, I'm going to show my code cause I can't see the problem.
Route.js:
import { createRouter, createWebHistory } from "vue-router";
import Home from "#/views/Home.vue";
import NotFound from "#/views/NotFound.vue";
const routes = [
{
path: "/",
name: "Home",
component: Home,
},
{
path: "/:pathMatch(.*)*",
component: NotFound,
},
];
const router = createRouter({
history: createWebHistory(),
routes,
});
export default router;
main.js
import { createApp } from "vue";
import App from "./App.vue";
import router from "./router"; // <---
// estilos app
import "./styles/styles.scss";
createApp(App).use(router).mount("#app");
NotFound.vue
<template>
<h1>404: Lo sentimos, la página que buscas no existe</h1>
</template>
<script>
export default {
name: "NotFound",
};
</script>
<style scoped lang="scss"></style>
App.vue
<template>
<div id="app">
<app-header />
<div class="app-container">
<Home />
</div>
<Footer />
</div>
</template>
<script>
import AppHeader from "#/components/AppHeader.vue";
import Home from "#/views/Home.vue";
import Footer from "#/components/Footer.vue";
export default {
name: "App",
components: {
AppHeader,
Home,
Footer,
},
};
</script>
I can't see where is my problem cause pageNOTfound is not working at this time. I tried a lot of changes but I don't know how can it works.
If you want to have 404 as a completely seperate page, without footer and header, then you need these files:
App.vue
<template>
<router-view></router-view>
</template>
<script>
export default {
name: "App",
};
</script>
Home.vue
<template>
<div>
<app-header />
<div class="app-container">
... other home content here ...
</div>
<Footer />
</div>
</template>
<script>
import AppHeader from "#/components/AppHeader.vue";
import Footer from "#/components/Footer.vue";
export default {
name: "Home",
components: {
AppHeader,
Footer,
},
};
</script>
This way the App.vue does not contain header or footer, but the Home.vue. And the 404 page will be displayed without header and footer.

Getting a console error while trying to migrate a Vue App with VueRouter

I am tying to port a stand alone Vue app into a larger Java Spring web project. The Vue app has Vue router as a dependency. When I try to load the main page, I am getting a [Vue warn]: Error in render: "TypeError: Cannot read property 'to' of undefined". found in ---> <RouterLink>...<AppHeader> at src/views/AppHeader.vue error in the browser console.
The main JSP loads fine, and is using a compiled JS file.
src/main.js
import Vue from 'vue';
import AppLayout from './views/Layout.vue';
import router from './router';
import Vuetify from 'vuetify';
import vueMoment from 'vue-moment';
import VueTippy from 'vue-tippy';
new Vue({
el: '#app',
router,
render: h => h(AppLayout)
});
Vue.use(VueTippy);
Vue.use(Vuetify);
Vue.use(vueMoment);
src/views/AppLayout.vue
<template>
<div id="app">
<app-header></app-header>
<section class="main-section section">
<div class="container content">
<router-view></router-view>
</div>
</section>
<app-footer></app-footer>
</div>
</template>
<script>
import AppHeader from './AppHeader.vue';
import AppFooter from './AppFooter.vue';
export default {
components: {
'app-header': AppHeader,
'app-footer': AppFooter
}
}
</script>
src/router/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import SearchForm from '../views/search/searchform.vue'
Vue.use(VueRouter)
const router = new VueRouter({
mode: 'history',
scrollBehavior: (to, from, savedPosition) => ({ y: 0 }),
routes: [
{ path: '/app/path/search', component: SearchForm },
{ path: '/app/path/new', component: NewReturn },
{ path: '/app/path/home', component: SearchForm },
{ path: '/', redirect: '/app/path/search' },
{ path: '*', component: NotFound }
]
})
export default router
src/views/Appheader.vue
<template>
<div>
<router-link to="/app/path" exact>Search</router-link>
</div>
</template>
It seems like router-link is not working for some reason. I can't seem to figure out how to fix this issue. Anyone know what I am missing?
You don't need an <a> tag inside the router-link, that is rendered by vue when using <router-link>
https://router.vuejs.org/api/#router-link
The undefined 'to' will be your empty href declaration.

How to extract Route Params via Props

I am learning VueJs and trying to understand how to extract route params via props.
I was looking at the following documentation, where it seems to have three options to have this done, but I cannot understand it quite well so far - https://github.com/vuejs/vue-router/tree/dev/examples/route-props.
I have tried adding props: true to my router object array (routes.js file posted below) with no success as well.
As this is vue-cli study project I will post the separate pertinent blocks of code in order to try to illustrate this properly.
Main - App.vue below:
<template>
<div class="container">
<div class="row">
<div class="col-xs-12 col-sm-8 col-sm-offset-2 col-md-6 col-md-offset-3">
<h1>Routing</h1>
<hr>
<app-header></app-header>
<router-view></router-view>
</div>
</div>
</div>
</template>
<script>
import Header from './components/Header.vue'
export default {
components: {
appHeader: Header
}
}
</script>
<style>
</style>
Component - Header.vue below:
<template>
<ul class="nav nav-pills">
<router-link to="/" tag="li" active-class="active" exact><a>Home</a></router-link>
<router-link to="/user/10" tag="li" active-class="active"><a>User 1</a></router-link>
<router-link to="/user/5" tag="li" active-class="active"><a>User 2</a></router-link>
</ul>
</template>
Component - User.vue below:
<template>
<div>
<h1>The User Page</h1>
<hr>
<br>
<p>Route ID: {{id}}</p>
<button class="btn btn-primary" #click="goHome">Go to Home</button>
</div>
</template>
<script>
export default {
data(){
return {
id: this.$route.params.id
}
},
watch: {
'$route'(to, from) {
this.id = to.params.id;
}
},
methods: {
goHome(){
this.$router.push('/')
}
}
}
</script>
main.js below:
import Vue from 'vue'
import VueRouter from 'vue-router'
import App from './App.vue'
import {routes} from "./routes";
Vue.use(VueRouter)
export const router = new VueRouter({
routes,
mode: 'history'
})
new Vue({
el: '#app',
router,
render: h => h(App)
})
routes.js below (located at SRC folder):
import User from './components/user/User.vue'
import Home from './components/Home.vue'
export const routes = [
{path: '', component: Home},
{path: '/user/:id', component: User}
]
Do I need to also set Props at User.vue component as well in order to make it work and quit using watch?
In other words, I would like to see my user route being listened at <p>Route ID: {{id}}</p> from this hardcoded 10 to 5 using this new method which I cannot understand, mentioned at the top of this post.
Could anyone please walk me through this issue in this specific situation?
Thanks in advance to all.
According to the docs on passing Props to Route components, you can decouple it, with the props option on the router config.
import User from './components/user/User.vue'
import Home from './components/Home.vue'
export const routes = [
{path: '', component: Home},
{path: '/user/:id', component: User, props: true}
]
<template>
<div>
<h1>The User Page</h1>
<hr>
<br>
<p>Route ID: {{id}}</p>
<button class="btn btn-primary" #click="goHome">Go to Home</button>
</div>
</template>
<script>
export default {
props: ['id'],
methods: {
goHome() {
this.$router.push('/')
}
}
}
</script>

Vue Material Tabs not showing content

The program must shows the page when that is selected from tab using Vue Material Tab. I've configured routes and installed dependencies but when I click on the tab not is showed. The code have two Vue components to test two screens content. The ideia is show a row like toolbar at top of view and populate it with tabs. The two screens are Menu and Home.
App.vue
<template>
<div>
<md-tabs md-sync-route>
<md-tab id="tab-home" md-label="Home" to="/components/Home" exact></md-tab>
<md-tab id="tab-pages" md-label="Pages" to="/components/Menu"></md-tab>
</md-tabs>
<router-view/>
</div>
</template>
<script>
export default {
name: 'App',
}
</script>
index.js
import Vue from 'vue'
import Router from 'vue-router'
import Home from '#/components/Home'
import Menu from '#/components/Menu'
import VueMaterial from 'vue-material'
import 'vue-material/dist/vue-material.min.css'
import 'vue-material/dist/theme/default.css'
Vue.use(VueMaterial)
Vue.use(Router)
export default new Router({
mode: 'history',
routes: [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/Home',
name: 'Home',
component: Home
},
{
path: '/Menu',
name: 'Menu',
component: Menu
},
]
})
Menu.vue
<template>
<div>
<h1>Menu</h1>
</div>
</template>
<script>
export default {
name: 'Menu'
}
</script>
Home.vue
<template>
<div>
<h1>Home</h1>
</div>
</template>
<script>
export default {
name: 'Home',
}
</script>
Yo don't have routes with path /components/Home and /components/Menu in your router config. So provide correct path's.
<md-tab id="tab-home" md-label="Home" to="/Home" exact></md-tab>
<md-tab id="tab-pages" md-label="Pages" to="/Menu"></md-tab>

Not loading vue file in Laravel 5.7 application

working with laravel 5.7 and vue.js my
app.js file is as following,
require('./bootstrap');
window.Vue = require('vue');
import VueRouter from 'vue-router'
Vue.use(VueRouter)
let routes = [
{ path: '/dashboard', component: require('./components/Dashboard.vue') },
{ path: '/profile', component: require('./components/Profile.vue') }
]
const router = new VueRouter({
routes // short for `routes: routes`
})
Vue.component('example-component', require('./components/ExampleComponent.vue').default);
const app = new Vue({
el: '#app',
router
});
and I need link following link with vue file
<router-link to="/dashboard" class="nav-link">
and Dashboard.vue file is like this
<template>
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card card-default">
<div class="card-header">Dashboard Component</div>
<div class="card-body">
I'm an example component.
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
mounted() {
console.log('Component mounted.')
}
}
</script>
but when I click above link to dashbord.vue file it is not loading. only display url in the address bar. my console error is as following
[Vue warn]: Failed to mount component: template or render function not defined. found in ---> <Anonymous> <Root>
how can fix this error
You need add App.vue
<template>
<div>
<router-link to="/dashboard" class="nav-link">Dashboard</router-link>
</div>
</template>
<script>
export default {
// some code here if needed
}
</script>
and then use it in main.js
require('./bootstrap'); // maybe better use import "./bootstrap"
import Vue from 'vue';
import VueRouter from 'vue-router';
import App from "./App.vue";
import Dashboard from './components/Dashboard.vue';
import Profile from './components/Profile.vue';
import ExampleComponent from './components/ExampleComponent.vue';
Vue.use(VueRouter)
window.Vue = Vue; // why you do that???
let routes = [
{ path: '/dashboard', component: Dashboard },
{ path: '/profile', component: Profile }
]
const router = new VueRouter({
routes // short for `routes: routes`
});
Vue.component('example-component', ExampleComponent);
new Vue({
router,
render: (h) => h(App)
}).$mount('#app');

Categories