vue-router: browser attempts to open <router-link> as a local file - javascript

I'm new to Vue-router and can't figure out what's gone awry. Clicking on a navigation link causes the desired component to be displayed for an instant, but then the browser tries to open the component as if it were a file.
For example, clicking on the "Badger!" link results in the browser attempting to open a local file named file:///home/travis/.../prototype/dist/badger which of course results in a file not found error.
Any insights on this? I've tried to follow existing examples carefully.
main.js:
import Vue from 'vue';
import App from './App.vue';
import VueRouter from 'vue-router';
import Badger from './component/Badger.vue';
import Grid from './component/Grid.vue';
Vue.use(VueRouter);
const router = new VueRouter({
mode: 'history',
base: __dirname,
routes: [
{ path: '/badger', component: Badger },
{ path: '/grid', component: Grid },
]
});
new Vue({
el: '#app',
router,
render: h => h(App),
});
App.vue
<template>
<div id="app">
<ul>
<li>
<router-link to="/badger">Badger!</router-link>
</li>
<li>
<router-link to="/grid">Data!</router-link>
</li>
</ul>
<router-view></router-view>
</div>
</template>
<script>
export default {
mounted() {
console.log('mounted App component')
},
data() {
// ...
}
},
}
</script>
<style>
// ...
</style>

When the router is in history mode, the build artifacts must be delivered to the browser from an http server, as #bigless mentioned.
If your workflow requires opening the build artifact from the local filesystem, that can be done if you remove these lines from the router declaration:
mode: 'history',
base: __dirname,
This will put you in "hash mode" (the default state). Your artifact can then be loaded either from an http server or from the local filesystem.
Relevant docs: https://router.vuejs.org/guide/essentials/history-mode.html

Related

How to make the vue router link connect to the vue component?

I am very new to the Vue framework, as well as Javascript, but am currently building a site using Vue and I want to have some links at the top of my site that the user can navigate to. I have tried using the Vue Router (https://router.vuejs.org/guide/#javascript) in order to make these links. At this point, I just want to make a little 'About Us' section that the user can navigate to. But, despite the URL changing accordingly to 'localhost:8080/#/about_us', the Vue component that I have associated with the link will not show up.
I have structured my code in the main.js as such:
import Vue from 'vue'
import VueRouter from 'vue-router'
import App from './App.vue'
Vue.config.productionTip = false
export const eventBus = new Vue();
Vue.use(VueRouter);
const AboutUs = {template: '<div>about_us</div>'};
const route = [{path:'/about_us', component: AboutUs}];
const router= new VueRouter({route});
new Vue({
render: h => h(App),
router
}).$mount('#app')
And then I have my app.vue designed as (note: I reduced much of the code to its essentials for brevity):
import AboutUs from './components/AboutUs.vue'
import { eventBus } from './main.js'
export default {
data(){
return {
films: []
}
},
components: {
"about-us": AboutUs
},
mounted(){
fetch('https://ghibliapi.herokuapp.com/films')
.then(res => res.json())
.then(films => this.films = films)
.catch(error=> console.log(error))
}
}
</script>
body {
background-color: deepskyblue;
}
<h1>Ghibli Fandom Extravaganza</h1>
<nav>
<li><router-link to="/about_us">About us </router-link></li>
<router-view></router-view>
</nav>
<p>List of Ghibli Movies: <films-list :films="films"/></p>
<film-detail />
At this point, my AboutUs component is only a very basic Vue that shows some information about the site in some simple HTML tags. But although the link is active and does work, the information from the Vue is not displayed, while the other Vue components continue to show, which indicates that maybe they are not connected? I have tried to follow the tutorial in the Vue Router site, but I don't think that I understand the mechanics of how the code actually works. Can anybody recommend me any corrections?
UPDATE:
Here is the code to my AboutUs.vue
<template>
<div>
<h1>This site is for examining the movies of Studio Ghibli</h1>
</div>
</template>
<script>
export default {
name: 'about-us'
}
</script>
<style scoped>
</style>
I think there is no need to import 'aboutus' component. You can just write like this <router-link to="about_us">About us </router-link>
and in the main.js declare the route like this
const route = [{path:'/about_us',name:'about_us', component: () => import("path to about us file")}];
The code samples you provided are a bit confusing, you should simply pass an imported view straight in to the component property of a router entry.
Where you have done:
const AboutUs = {template: '<div>about_us</div>'};
Replace that line with:
import AboutUs from './components/AboutUs.vue'
I can't figure out from your sample, when and what the relevance of components: {"about-us": AboutUs }, it is not needed.
Here is a sample of my setup:
router.js
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'index',
component: () => import('../components/views/welcome')
},
{
path: '/about-us',
name: 'about-us',
component: () => import('../components/views/about-us')
}
]
const router = new VueRouter({
mode: 'history',
routes
})
export default router
main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
Vue.config.productionTip = false
new Vue({
router,
render: h => h(App)
}).$mount('#app')
App.vue
<template>
<v-app v-cloak>
<router-link :to="{ name: 'index' }">Welcome</router-link>
<router-link :to="{ name: 'about-us' }">About Us</router-link>
<router-view></router-view>
</v-app>
</template>
<script>
export default {
name: 'App'
}
</script>
components/views/about-us.vue
<template>
<div>This is the About Us page!</div>
</template>
<script>
export default {
name: 'about-us'
}
</script>
This sample uses History Mode
Other things to note
When routing, mounted is unreliable, instead you should place any fetch logic into it's own method when calling any :
methods: {
fetch () {
// https://github.com/axios/axios
axios.get('https://ghibliapi.herokuapp.com/films').then( ... )
}
}
Call this.fetch method in both beforeRouteUpdate and beforeRouteEnter instead of mounted, you can't even rely on created when it comes to views handled by vue-router.
Axios is suggested instead of native fetch because axios provides more functionality, features and browser compatibility.
In about-us.vue you add these Navigation Guards like so:
<template>
<div>This is the About Us page!</div>
</template>
<script>
export default {
name: 'about-us'
methods: {
fetch () {
axios.get('https://ghibliapi.herokuapp.com/films').then( ... )
}
}
// Will fire if you are already on the view but a parameter changes (dynamic routing)
beforeRouteUpdate(to, from, next) {
this.fetch()
next()
},
// Will fire when you enter the view
beforeRouteEnter(to, from, next) {
this.fetch()
next()
},
}
</script>
Both should be added, understand that they won't fire at the same time, only one of them will execute fetch once when relevant.
This will resolve any issues you would otherwise encounter with Dynamic Routing should you ever use them.
Folder Structure
src/
+ App.vue
+ main.js
+ router.js
+ vue.config.js
+ assets/
+ logo.png
+ components/
+ views/
+ welcome.vue
+ about-us.vue
Hope this clears up the setup requirement for you.

Reinit javascript function when change view in vue js

I am kinda new in vue.js
I have a laravel app with vue.js. When hp is loading script also loading all elements are initialised (owl carousel, rev slider etc), but when i click other route contact or about and come back to hp the sliders or other related to js doesnt load .
routes.js
import VueRouter from 'vue-router';
import Home from './components/views/Home.vue';
import About from './components/views/About.vue';
import Contact from './components/views/Contact.vue';
let routes = [
{ path: '/', component: Home },
{ path: '/about', component: About },
{ path: '/contact', component: Contact },
{ path: '/notes', component: Notes }
];
export default new VueRouter({
routes,
linkActiveClass: 'active'
});
and app.js
import router from './routes';
import './components';
const app = new Vue({
el: '#app',
router
});
Is there a way to run the functions to load carousels etc each time i change view ?
On mounted trigger you can add your custom js for each component
<script>
export default {
mounted () {
}
}
</script>
if anyone stumbles upon this and still looking for a way to do it, this is how I managed to do this. wrap the <route-view/> in a <transition> which you can control with css and call a method on enter which calls the function you want.
this will call the function as soon as the component is loaded in the DOM on every route change
<transition name="slide" v-on:enter="reInitJS">
<router-view></router-view>
</transition>
<script>
//import the wanted function
import {init} from './main';
export default {
name: 'App',
methods: {
reInitJS(){
//call the function
init();
}
}
}
</script>

VUE JS Relative Path Issue

I have a vuejs simple project and deploy it on my hosting.
first is I build it on production mode using:
npm run build
then I have a url which is www.sample.com/vue-project/ and I put the production version of my vuejs project there. when I visit the link everything behaves okay. When I click on the menu to add blogs it changes the url to this link www.sample.com/vue-project/add and it loads the right component. however, when I press f5 on the page gives 404 error. don't know why though.
and when I visit this link https://epm.sg/vue-project/#/add it gives me the right component. but as you can see on my Routes Option I put it on history mode.
Here's my code.
main.js
import VueResource from 'vue-resource'
import VueRouter from 'vue-router'
import Routes from './routes'
Vue.use(VueResource);
Vue.use(VueRouter);
Vue.url.options.root = 'https://sample-proj.firebaseio.com/';
const router = new VueRouter({
base:'/vue-project/',
routes:Routes,
mode: 'history',
});
routes.js
import showBlogs from './components/showBlogs.vue';
import addBlog from './components/addBlog.vue';
import singleBlog from './components/singleBlog.vue';
export default [
{
path: "/",
component: showBlogs
},
{
path: "/add",
component: addBlog
},
{
path: "/blog/:id",
component: singleBlog
}
];
navbar.vue
<template>
<nav>
<ul>
<li><router-link to="/" exact>Blog</router-link></li>
<li><router-link to="/add" exact>Add New Blog</router-link></li>
</ul>
</nav>
</template>
<script>
export default {
}
</script>
thanks in advance.

Random loading errors with vue-material components

I started playing with Vue.js and VueMaterial this week. It's really fun and totally new for me as I didn't do Javascript for years (Native Android being my cup of tea).
I am currently stuck with a very strange issue that I would say related to my lack of knowledge with the framework lifecycle.
Issue
The first time I am loading/refreshing manually the project in Chrome, it fails loading the VueMaterial components for some reason, and I get the message below:
Unknown custom element: md-toolbar - did you register the component correctly? For recursive components, make sure to provide the "name" option.
I get this message with every single VueMaterial components I use in the project (md-whiteframe, md-input-container, and so on).
And the result appears as below:
Now, if I specifically change the URL in chrome by giving the path of another component (e.g. Home), then some components are correctly displayed (except the toolbar for some reason).
I go back (with Chrome), and land on the first component, except that now, everything is displayed correctly, still except the toolbar (see below).
On certain occasion (really rare and completely randomly, the Toolbar is displayed correctly.
Context
I installed vue-cli via npm and built the scaffold with the webpack template, then installed VueMaterial with npm as well.
Code
Below, some bits of the code.
main.js
import Vue from 'vue'
import App from './App'
import router from './router'
import VueMaterial from 'vue-material'
import 'vue-material/dist/vue-material.css'
Vue.config.productionTip = false
let colorPrimary = {
color: 'red',
hue: 700,
hexa: '#D32F2F'
}
let colorAccent = {
color: 'yellow',
hue: 600,
hexa: '#FDD835'
}
new Vue({
el: '#app',
router,
template: '<App/>',
components: { App }
})
Vue.use(VueMaterial)
Vue.material.registerTheme('default', {
primary: colorPrimary,
accent: colorAccent,
warn: colorPrimary,
background: 'white'
})
Vue.material.setCurrentTheme('default')
App.vue
<template>
<div id="app">
<toolbar></toolbar>
<router-view></router-view>
</div>
</template>
<script>
import Toolbar from './components/Toolbar';
export default {
components: {
Toolbar
},
name: 'app'
}
</script>
<style src="./styles/general.css"></style>
Toolbar.vue (custom component)
<template>
<div id="toolbar">
<md-toolbar class="md-primary">
<h2 class="md-title" style="flex: 1">Firebucket</h2>
</md-toolbar>
</div>
</template>
<script>
export default {
name: 'toolbar'
}
</script>
<style scoped src="../styles/toolbar.css"></style>
Login.vue
<template>
<div id="login" class="bg-primary">
<md-whiteframe md-elevation="2" id="login-form">
<span class="md-title text-primary">{{wording.login}}</span>
<md-input-container>
<label>{{wording.username}}</label>
<md-input></md-input>
</md-input-container>
<md-input-container>
<label>{{wording.password}}</label>
<md-input></md-input>
</md-input-container>
<router-link id="login-button" tag="md-button" to="XX" class="md-raised md-primary">{{wording.login}}</router-link>
<br />
<md-button class="md-primary">{{wording.createAccount}}</md-button>
</md-whiteframe>
</div>
</template>
<script>
export default {
name: 'login',
data () {
return {
wording: {
login: 'Login',
createAccount: 'Create an account',
username: 'Username',
password: 'Password'
}
}
}
}
</script>
<style scoped src="../styles/login.css"></style>
router.js
import Vue from 'vue'
import Router from 'vue-router'
import Login from './pages/Login'
import Home from './pages/Home'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/home',
name: 'home',
component: Home
},
{
alias: '/',
path: '/login',
name: 'login',
component: Login
}
]
})
--
Again, web development is not my thing, I've heard a lot of good thing about Vue.js so I wanted to give it a try. But sorry if I am missing something really obvious.
I really can't wrap my head around the fact that it's not working the first time but working fine when I go back...
PS: the router-link (in Login.vue) doesn't work neither, nothing happens when I tap the button, but I guess that's a different issue.
Any idea anyone? General feedback on the code posted above is more than welcome so I can improve it.
The code is available on GitHub, if that can help.
Thanks a lot!
You are adding the VueMaterial plugin after you create your Vue. Instead, add it before.
Vue.use(VueMaterial)
Vue.material.registerTheme('default', {
primary: colorPrimary,
accent: colorAccent,
warn: colorPrimary,
background: 'white'
})
Vue.material.setCurrentTheme('default')
new Vue({
el: '#app',
router,
template: '<App/>',
components: { App }
})

Unknown custom element: <router-link> in VueJS

I have attempted to extract my navigation logic in to a sub component, the structure is as follows:
App.vue -- Header.vue --- Navigation.vue
I am attempting to use the attribute in Navigation.vue but am recieving the following error:
Unknown custom element: <router-link> - did you register the component correctly? For recursive components, make sure to provide the "name" option.
Here is my app so far, pretty simple an basic.
main.js
require('bootstrap-sass/assets/stylesheets/_bootstrap.scss')
// require('bootstrap-sass/assets/javascripts/bootstrap.js')
require('./assets/sass/app.scss')
import Vue from 'vue'
import VueRouter from 'vue-router'
import VueMoment from 'vue-moment'
import VueResource from 'vue-resource'
import { configRouter } from './routes'
import App from './App'
// Debug mode
Vue.config.debug = true
// Devtools enabled
Vue.config.devtools = true
// Silence logs and warnings
Vue.config.silent = false
// install router
Vue.use(VueRouter)
// install vue-moment filter
Vue.use(VueMoment)
// install resource
Vue.use(VueResource)
// create router
var router = new VueRouter({
history: true,
saveScrollPosition: true
})
// configure router
configRouter(router)
/* eslint-disable no-new */
// new Vue({
// el: 'body',
// components: { App, router }
// })
router.start(App, '#app')
App.vue
<template>
<div>
<site-header></site-header>
<router-view></router-view>
</div>
</template>
<script>
import SiteHeader from './components/Header'
export default {
components: {
SiteHeader
}
}
</script>
Header.vue
<template>
<header class="masthead container-fluid">
<div class="row">
<!-- Branding -->
<div class="col-md-3"> </div>
<!-- / Branding -->
<!-- Primary Navigation -->
<navigation></navigation>
<!-- / Primary Navigation -->
<!-- Actions -->
<div class="col-md-3"> </div>
<!-- / Actions -->
</div>
</header>
</template>
<script>
import Navigation from './Navigation'
export default {
components: {
Navigation
},
data () {
return {
msg: 'Hello World!'
}
}
}
</script>
Navigation.vue
<template>
<div class="col-md-6">
<ul class="primary-navigation list-inline list-unstyled">
<li> <router-link to="/about">About</router-link> </li>
<li> TEST </li>
<li> TEST </li>
<li> TEST </li>
</ul>
</div>
</template>
<script>
import VueRouter from 'vue-router'
export default { components: { VueRouter } }
</script>
What am I doing wrong?
Versions: vue 1.0.28 & vue-router 0.7.13
From vue-router docs: http://router.vuejs.org/en/essentials/getting-started.html
// 3. Create the router instance and pass the `routes` option
// You can pass in additional options here, but let's
// keep it simple for now.
const router = new VueRouter({
routes // short for routes: routes
})
I believe the routes need to be passed when you are creating the router instance. I don't really know what your configRouter(router) does, but you can keep things simple till it starts working. After that, you can start modularizing your components and configs.
Also, I am not sure about router.start, it is not specified anywhere in the docs that I can find. The router docs recommend this simple method to create the root instance of your app:
// 4. Create and mount the root instance.
// Make sure to inject the router with the router option to make the
// whole app router-aware.
const app = new Vue({
router
}).$mount('#app')
Probably your app is not router-aware yet, as mentioned in the comments above (from docs, not from me!). This could be a reason for getting that router-link error. Can you try the simpler methods as recommended by the docs?
By the way, which versions of Vue and Vue-Router are you using? If it is not the current versions (vue 2.0.3 and vue-router 2.0.1), then please ignore my answer above.

Categories

Resources