VUEJS vue-router access router from nested routes - javascript

I have problem to access route object from nested views. Here is the simplified code:
main.js
import Vuetify from 'vuetify'
import VueRouter from 'vue-router'
import Vuetify from 'vuetify'
Vue.use(VueRouter)
Vue.use(Vuetify)
const router = new VueRouter({
routes : [
{path : '/contacts', component: Contacts,
children: [
{
path: ':id',
component: ContactDetails
}
]
},
],
mode: 'history'
})
new Vue({
el: '#app',
render: h => h(App),
router
})
ContactDetails.vue
<template>
<v-btn icon dark class="mr-3" #click.native="editContact">
<v-icon>edit</v-icon>
</v-btn>
</template>
<script>
export default {
data : () => ({
}),
methods: {
editContact: ()=>{
console.log('edit contact');
this.$router.go(-1) //this gives an error
}
},
}
</script>
It says "router is undefined", when I use
this.$router.go(-1)
from main routes (aka /contacts), it works. I tried all of the below code on the child:
router.go(-1)
$router.go(-1)
this.$router.go(-1)
this.router.go(-1)
this.$parent.$router.go(-1)
None of them works. Is there a way to reach to router object from nested routes? Or should I emit an event to parent and change view from there?

I have found an error in your code - it's in ()=>{...} function :)
Using an arrow function you are addressing ContactDetails-component this (object) and it does not contain any $router indeed. After you change an arrow function to function() {} your code will work as expected, because Vue rebinded to its instance where the $router is declared.
Now, lets look at this working copy (codepen) of your code:
Vue.use(VueRouter)
let ContactDetails = {
mounted() {
console.log('ContactDetails mounted...');
},
methods: {
editContact: function() {
console.log('edit contact');
this.$router.go(-1) //this DOES NOT give an error ANYMORE
}
},
template: `<button #click="editContact">edit</button>`,
}
let Contacts = {
components: {ContactDetails},
mounted() {
console.log('Contacts mounted...');
},
template: `Contacts... <ContactDetails></ContactDetails>`,
};
const router = new VueRouter({
mode: 'hash',
routes : [{
path : '/contacts',
component: Contacts,
children: [{
path: 'id',
component: ContactDetails
}]
}],
});
const vm = new Vue({
el: '#app',
components: {
Contacts,
ContactDetails,
},
router
});
vm.$router.push("/contacts/id");
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue-router/3.0.2/vue-router.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<router-view></router-view>
</div>

Related

Why is my Vue navbar changing the route but not updating the router-view?

I'm using Vue to make a single-page application and I have a navbar and have set up Vue-Router. For some reason, every time after the first time I use the navbar, the route changes but the router-view does not. Here's the code from NavBar.vue:
<template>
<div id="app">
<v-toolbar id="navbar" app color="#330066" dark>
<v-toolbar-side-icon></v-toolbar-side-icon>
<v-toolbar-title id="appname">{{ appname }}</v-toolbar-title>
<v-spacer></v-spacer>
<span :key="item.link" v-for="item in items" class="nav-elt">
<router-link active-class="nav-elt-active" tag="span" :to="item.link">
{{ item.title }}
</router-link>
</span>
</v-toolbar>
</div>
</template>
<script>
export default {
name: "NavBar",
props: {
appname: String,
},
data() {
return {
items: [
{ title: "Home", link: "/" },
{ title: "Search", link: "/search" },
],
};
},
};
</script>
And here's from App.vue:
<template>
<v-app>
<v-main>
<NavBar appname="Newsfacts" />
<router-view />
</v-main>
</v-app>
</template>
<script>
import NavBar from "./components/NavBar";
export default {
name: "App",
components: {
NavBar,
},
data() {
return {};
},
};
</script>
Here's from router/index.js:
import Vue from 'vue';
import Router from 'vue-router';
import Home from '../views/Home.vue';
import Search from '../views/Search.vue';
Vue.use(Router);
export default new Router({
mode: "history",
routes: [
{
path: "/",
name: "Home",
component: Home
},
{
path: "/search",
name: "Search",
component: Search
}
]
});
If you need anything else, the full code is on my github, and a demo is at a netlify site
The link attribute inside the array of items should contain a '/' at the beginning of every route.
So, it should look like this:
data() {
return {
items: [
{ title: "Home", link: "/home" },
{ title: "Search", link: "/search" },
],
};
},
Also, it is probable that the component is not being rendered because you are using <v-btn/> for routing, instead of <router-link/>.
I recommend you use <router-link/> instead of <v-btn/> for navigation in order to support all the features provided by Vue Router like history mode, base, etc.
In case you necessarily need the v-btn, I think you can wrap the <router-link/> inside the button or viceversa.
For more information about Vue Router and <router-link/>, check out this link:
https://router.vuejs.org/api/#router-link
where is your vue router component definitions?
e.g
const FooHome= { template: '<div>Home</div>' }
const Search= { template: '<div>Search</div>' }
const routes = [
{ path: '/', component: Home},
{ path: '/search', component: Search}
]
const router = new VueRouter({
routes
})
const app = new Vue({
router
}).$mount('#app')
Turns out I was returning an empty dictionary in a few data() functions, and that caused the app to break. Thanks to #inked6233 on the Vue Land discord for helping me find that!

Trying to make a VueJS API call with axios to get json in a component named prijzen

I am new to Vue and am trying to load in json data from a REST API called JSON placeholder. I get the error:
"Uncaught ReferenceError: Prijzen is not defined
at eval (cjs.js?!./node_modules/babel-loader/lib/index.js!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/views/layout/Prijzen.vue?vue&type=script&lang=js&:16)
at Module../node_modules/cache-loader/dist/cjs.js?!./node_modules/babel-loader/lib/index.js!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/views/layout/Prijzen.vue?"
So after i got this i tried looking at index.js but prijzen is added there.. the code looks like this:
import Vue from 'vue'
import Router from 'vue-router'
// Containers
const TheContainer = () => import('#/containers/TheContainer')
// Views
const Dashboard = () => import('#/views/Dashboard')
const Prijzen = () => import('#/views/layout/Prijzen')
const Login = () => import('#/views/layout/Login')
Vue.use(Router)
export default new Router({
mode: 'hash', // https://router.vuejs.org/api/#mode
linkActiveClass: 'open active',
scrollBehavior: () => ({ y: 0 }),
routes: [
{
path: '/',
redirect: '/dashboard',
name: 'Home',
component: TheContainer,
children: [
{
path: 'dashboard',
name: 'Dashboard',
component: Dashboard
},
{
path: '/login',
name: 'Login',
component: Login
},
{
path: '/layout/prijzen',
name: 'Prijzen',
component: Prijzen
}
]
},
]
})
So prijzen is fine here. At least it looks fine to me. This is how the prijzen component looks:
<template>
<div id="Prijzen">
{{ prijs }}
</div>
</template>
<script>
import axios from 'axios';
import PrijsItem from './PrijsItem.vue';
export default {
name: 'Prijzen',
components: {
PrijsItem
},
props: ["PrijsItem"]
}
</script>
I have used {{ prijs }} in the template and in my main.js file it is being mentioned with my axios get request as you can see here:
import 'core-js/stable'
import Vue from 'vue'
import CoreuiVue from '#coreui/vue/src'
import App from './App'
import router from './router/index'
import { iconsSet as icons } from './assets/icons/icons.js'
import store from './store'
Vue.use(CoreuiVue)
new Vue({
el: '#app',
router,
store,
//CIcon component documentation: https://coreui.io/vue/docs/components/icon
icons,
template: '<App/>',
components: {
App,
Prijzen
},
new:({
let: '#Prijzen',
data () {
return {
prijs: null
}
},
mounted () {
axios
.get('https://jsonplaceholder.typicode.com/posts')
.then(response => (this.prijs = response))
}
})
})
Is the Prijzen.vue file definitely in the views/layout directory? That error looks like it might be caused by not being able to find the file where you've told it to look.
A different issue:
{{ prijs }}
Is in the template, but prijs is not defined. Also PrijsItem component has been imported but not used which will sometimes throw linting errors.

How to pass app data to a VueRouter component

I am using VueRouter to load templates depending on the URL. When I try to use a property defined in app.data in the components, I receive a [VueWarn] Property or method "role" is not defined.
How can I pass every data property to the child components?
This is my script:
const Home = { template: '<p>home page, {{role}}</p>' }
const NotFound = { template: '<p>Page not found</p>' }
const routes = [
{path: '/', component: Home}
{path: '*', component: NotFound}
]
Vue.use(VueRouter)
var app = new Vue({
el: '#app',
data: {
role: 0,
cookiesAlert: true
},
router: new VueRouter({routes})
})
I think your router construction options are not set properly. Usually, I prefer to use 'named routes', therefore what I will set is:
const router = new VueRouter({
routes: [
{ name: 'role', path: '/:role', component: User },
{ path: '*', component: Home }
]
})
And if I don't understand your question wrong, what you want to do is pass the 'data' in parent components to child components via url and read the data in child component?
const User = {
template: '<div><br/>Role read from url is {{ $route.params.role }}</div>'
}
const Home = {
template: '<div><br/>Welcome</div>'
}
const router = new VueRouter({
routes: [
{ name: 'role', path: '/:role', component: User },
{ path: '*', component: Home }
]
})
new Vue({
router,
el: '#app',
data: {
role: 'default role'
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue-router/3.0.2/vue-router.min.js"></script>
<div id="app">
The role is (Please change the 'role' value and click on '/User' link): <input v-model="role" type="text" /> <br/>
<router-link :to="{ name: 'role', params: { role: role }}">User</router-link>
<router-link to="/">Home</router-link>
<router-view></router-view>
</div>
Or if you don't want to use $route.params.role, what I will do is to set the 'props' in router config options to be true.
When props is set to true, the route.params will be set as the component props.
const router = new VueRouter({
routes: [
{ name: 'role', path: '/:role', component: User, props: true },
{ path: '*', component: Home }
]
})
And bind to the 'props' inside child components.
const User = {
props: ['role'],
template: '<div><br/>Role read from url is {{ role }}</div>'
}

Vue / vue-router scoping

import ExpenseView from './path'
import template from './path'
const MainComponent = new Vue({
el: '#app',
data: {
expense: [{ description: 'expense description', amount: 14.99, _id: 'l;dkfjg;ladfjg;klafjg;l' }],
},
router: new VueRouter({
routes: [
{ path: '/dash', component: ExpenseView, props: { default: true, expenses: MainComponent.expense } },
]
}),
template,
created() {...},
methods: {...},
computed: {...}
})
My goal is to have the router listen to the data in MainComponent but there are scoping issues - MainComponent is not defined.
Is there a way to get the router listening to the data in MainComponent with the way this is structured?
You can see the following example
//you can try the following code
//index.js
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
import RSSFeed from '#/components/RSSFeed.vue'
export default new Router({
routes: [
{
path: '/rss-feed',
name: 'RSSFeed',
component: RSSFeed,
props: { authorName: 'Robert' }
},
]
})
//RSSFeed.vue
<template>
<ol id="feed">
{{authorName}}
</ol>
</template>
<script>
import Post from './Post'
export default {
props: ['authorName'],
data () {
return {
items: [
{
"title":"Vuejs Nodejs",
"pubDate":"20-07-2018",
"description":"Leading vuejs nodejs",
"link":"https://hoanguyenit.com"
}
],
errors: []
}
}
}
</script>
Example
//in router
const router = new VueRouter({
routes: [
{ path: 'YOUR__PATH', component: Home, props: { authorName: 'Robert' } }
]
})
//in Home.vue
//And inside the <Home /> component,
var Home = Vue.extend({
props: ['authorName'],
template: '<p>Hey, {{ authorName }}</p>'
});

Trouble getting data from root Vue instance with vue-router

I load all of my data in the root Vue instance and im trying to access them in my router.
How can I access the data in my root instance within my router? All the this.a.app or this.app answers i found online weren’t the solution.
Router.js:
import Vue from 'vue'
import Router from 'vue-router'
import Login from '../components/login'
import Container from '../components/container'
Vue.use(Router)
export default new Router({
mode: 'history',
routes: [{
path: '/login',
name: 'Login',
component: Login,
props: { test: **<data from my Vue root instance>** }
},
{
path: '/products',
name: 'Container',
component: Container,
children: [{
path: 'flavor',
component: Login
},
{
path: 'storage',
component: Login
},
{
path: 'network',
component: Login
}
]
}
]
})
Main.js:
import router from './router’
var vm = new Vue({
el: ‘#app’,
router,
template: ‘’,
components: {
App
},
data() {
return {
modal: ‘’
I would avoid sharing the data using the router instance.
I personally like to have a store file, which contains data I want to share between my components.
export default {
state: {
counter: 0
}
}
And in your component you can import the file:
import store from '../store'
export default {
data () {
return {
sharedState: store.state
}
}
}
Changes to sharedState will also be passed to other components.
Source: https://skyronic.com/2016/01/03/vuex-basics-tutorial / Solution 2

Categories

Resources