Vue Router within a component

Published 1 year ago by joseph127

So this is something I hadn't thought about doing before, but actually needed to for a project I am working on. So instead of having a single page app with vue router. 90% of the app will be standard laravel code, only certain pages will contain a vue router. Sounds simple enough I thought?

This is the approach I decided to take.

app.js

require('./bootstrap');

//Global components
Vue.component('header-component', require('./components/Header.vue'));
Vue.component('project-component', require('./components/Project.vue'));
Vue.component('sidebar-component', require('./components/Sidebar.vue'));

Vue.component('landing-page', require('./pages/Landing.vue'));
Vue.component('register-page', require('./pages/Register.vue'));
Vue.component('project-page', require('./pages/Project.vue'));


/**
 * Define the main application, this is where all the vue
 * components, pages and modals etc will be initiated into
 */
const app = new Vue({
    el: 'body',
});

/**
 * Define the router. The router will act as a seemless
 * transition between the projects/modals. The reason
 * for this is to allow transitions between pages.
 */
const router = new VueRouter({
    hashbang: false,
    history: true,
    suppressTransitionError: false
});

//Enable HTML5 mode
router.mode = 'html5';

//Map out the routes
router.map({
    '/:team': {
        name: 'team',
        component: Vue.component('project-page'),

        subRoutes: {
            '/:project': {
                name: 'project',
                component: Vue.component('project-page'),
                subRoutes: {
                    '/:screen': {
                        name: 'screen',
                        component: Vue.component('project-page'),
                    }
                },
            },
        },
    },
});

//Start the router
router.start(Vue.component('project-component'), '#project');

the view

<component is="project-component" inline-template v-cloak>
    <section class="container-project" id="project">
        <router-view></router-view>
    </section>
</component>

The strange thing is, everything works as expected. All the $route.params variables come through from the routes setup, and the template of "project-component" is displaying for the correct routes. But I am having a console error of:

<router-view> can only be used inside a router-enabled app.

upon googling this, I only found situations where vue router was initiated on the root app. in which case a simple Vue.extend does the trick. So whats the best way for going about this? And maybe shed some light on why this error is occurring?

christopher

You should bind the Vue Instance to an Element like <div> or <section> not to the whole <body>. Furthermore if you are using Subroutes the <router-view> should be also inside the nested Component - In this case project-page.

Take also a look at the Vue Router Docs: http://router.vuejs.org/en/essentials/nested-routes.html

diegones

Seems your missing Vue.use(VueRouter)

Ricardogolez

try my package its already complete. https://fagray.github.io/vuejs2-laravel53-starter/

joseph127

@diegones This has already been initiated in the bootstrap.js and @Ricardogolez unfortunately the requirements for this project is vue 1.0 but took a look at your git repo... looks alright man! Good work.

@diegones bootstrap.js


window._ = require('lodash');

/**
 * We'll load jQuery and the Bootstrap jQuery plugin which provides support
 * for JavaScript based Bootstrap features such as modals and tabs. This
 * code may be modified to fit the specific needs of your application.
 */

window.$ = window.jQuery = require('jquery');

/**
 * Vue is a modern JavaScript library for building interactive web interfaces
 * using reactive data binding and reusable components. Vue's API is clean
 * and simple, leaving you to focus on building your next great project.
 */

window.VueResource = require('vue-resource');
window.VueRouter = require('vue-router');

window.Vue = require('vue');
Vue.use(VueResource);
Vue.use(VueRouter);
Vue.config.silent = true;

/**
 * We'll register a HTTP interceptor to attach the "CSRF" header to each of
 * the outgoing requests issued by this application. The CSRF middleware
 * included with Laravel will automatically verify the header's value.
 */

Vue.http.interceptors.push((request, next) => {
    request.headers['X-CSRF-TOKEN'] = Laravel.csrfToken;
    next();
});

io
io
1 year ago (17,450 XP)

I'm dealing with the same problem. If someone manages to solve this, post the solution please.

guc43
guc43
1 year ago (9,140 XP)

I had the same issue. Take a look at this repo. Its using Vue v1 and it worked fine for me.

https://github.com/TahaSh/spa-forum/blob/master/resources/assets/js/main.js

io
io
1 year ago (17,450 XP)

I think I found the correct way to do things:

In my index.blade.php:

@section('content')
    <div id="app"></div>
@stop

In app.js:

const Router = Vue.component('router', require('./components/Router.vue'));
const Container = Vue.component('container', require('./components/Container.vue'));
const Navigation = Vue.component('navigation', require('./components/Navigation.vue'));
const Home = Vue.component('home', require('./components/Home.vue'));

const app = new Vue({
    el: 'body'
});

var router = new VueRouter({
    hashbang: true,
    history: true
});

router.mode = 'html5';

router.map({
    '/': {
        name: 'home',
        component: Home
    }
});

router.redirect({
    '*': '/'
});

router.start(Router, '#app');

In my Router.vue:

<template>
    <div>
        <container></container>
        <router-view></router-view>
    </div>
</template>

<script>
    import Container from './Container.vue';

    export default {
        data () {
            return {

            }
        },
        components:{
            'container': Container
        }
    }
</script>

Doing it like this seems to work nicely

Please sign in or create an account to participate in this conversation.