Getting data from independent child component to other components with router - javascript

I'm fairly new to Vue, which is why I can't ignore my feeling that I'm doing something wrong.
I have an independent component inside a view component, which has to emit data to other components.
The project has the following components: App, Navbar, Home, Statistics, Table and Search.
The Search component is used inside the Home component. It contains an <input> to let the user input his account name.
The Table component is used inside the Statistics component. It shows a table based on the input from the Search component.
+-- App
| +-- Navbar
| +-- Home
| +-- ---- Search
| +-- Statistics
| +-- ---- Table
My main App.vue contains the router-view:
<template>
<div id="app">
<Navbar></Navbar>
<div class="container">
<router-view></router-view>
</div>
</div>
</template>
Two of them are main view components, which have a fixed route: Home & Statistics.
The routes (router.js) are the following:
export default new Router({
routes: [{
path: '/',
name: 'home',
component: Home
},
{
path: '/statistics',
name: 'statistics',
component: Statistics
}
]
})
The Navbar component contains the router-links to the view components:
<template>
<div id="navbar">
<nav>
<ul>
<li class="active"><router-link to="/">Home</router-link></li>
<li><router-link to="/statistics">Statistics</router-link></li>
</ul>
</nav>
</div>
</template>
Now: What is the right way to get the data from the independent child component Search to my other independent child component Table?
The logical way would be Search-> Home -> App -> Statistics -> Table.
I already tried to use an event bus with $emit and $on, but it seems like the data can't connect to each other with the router inbetween.
Right now, I have a const in my main.js to store this global user data:
export const store = new Vue({
data: {
username: ''
}
})
which I import everywhere I need it, but I highly doubt that this is the right way to do it.
I also thought about using props for my Table component, but I would need to pass my data from App to Statistics to Table which would work, but feels like a lot of boilerplate. Also: I need to get the username to the App before I can do that anyways, which is what I don't know how to do proberly.
Thanks in advance.

It's OK to use a global store as you are doing, the docs even have a guide on how to do so: https://v2.vuejs.org/v2/guide/state-management.html#Simple-State-Management-from-Scratch
If you want a more structured way of doing this, look into Vuex, which is also written by the Vue team: https://vuex.vuejs.org/
Vuex integrates nicely into the Vue devtools and sidesteps the import/passing problems you're describing (because it is a plugin injected via Vue.use, then $store is available in every Vue)

Related

vue.js: How to specify which child component to use?

In my app there are generic and brand specific components. Let's say I have 2 brand specific components Product_brand_A.vue and Product_brand_B.vue, which I would like to display in a list. The parent component ProductList.vue is generic (used for both brands).
What are my options in ProductList.vue to specify which child component to use?
// ProductList.vue (generic)
import Product from 'Product.vue' // importing won't do
var ProductList = {
components: {
Product
},
...
}
I don't want to import both child components and decide at run time, it should be a build time solution.
I think that it's better to use slots api here. Here's example of usage of the list component:
<ProductList :items="someProductsBrandA">
<template v-slot:item="props">
<Product_brand_A product="props.product">
</Product_brand_B>
</template>
</ProductList>
This way you can add as much different product components as you want in the future. You can check the slot API here: https://v2.vuejs.org/v2/guide/components-slots.html
If you don't want to import both subcomponents then you would probably need to use dynamic importing:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#Dynamic_Imports
Then you could dynamically import the subcomponent you need based on some prop that you pass to the parent (ProductList.vue).

Vue js invalid router after login

I'm totally new to vue and I've built small vue app in codesandbox:
https://codesandbox.io/s/vue-template-fjd4i
And I have problems with routing, so, how to reproduce it:
click Login and provide any credentials
So now you are on Board page
Click Statistics page
And I get Signup page instead of Statistics, why? I don't understand
I'm using EventBus to refresh navbar after login event-bus.js:
// EventBus.js
import Vue from "vue";
export default new Vue();
When I'm logged (on Board page) and I click on Statistics I can see wrong route in router/index.js beforeEach func:
router.beforeEach((to, from, next) => {
console.log("///////");
console.log(from);
console.log(to);
console.log(next);
console.log("///////");
So i'm getting Signup route in to variable instead of Statistics. Can please anybody help?
This will happen If your route definition uses async loading import(...), and you named the chunks the same. Check the comment that declares the names in your routes.
Also, make sure your Statistics route really does return the correct component. Did you cut-and-paste?
The problem was in <a> tags, don't know why, but kill vue routing, so I changed this:
<router-link v-if="is_logged" tag="li" :to="{ name: 'Statistics' }">
<a>Statistics</a>
</router-link>
to this:
<li v-if="is_logged"><router-link tag="a" :to="{ name: 'Statistics' }">
Statistics
</router-link></li>

Vue with dynamic routes and components

Trying to build a test app to see if Vue is a suitable replacment for our AngularJS app. Trying to learn Vue at the same time.
After the user logs in we fetch some roles for that user. Base off those roles is how the menu gets built.
User1 { Role1, Role2, Role3}
In theory
User2 {Role1, Role3}
So Role1 would have a path of /start/page1 and page1 (component) and two child components.
Same with Role2 path of /start/page2 and page2 would have components on it.
I don't really want to build the routes until I know which roles the user has.
I'm using quasar-framework.org and using the menu slide out. Trying to create a menu on the fly. Seems like I need the components to already be imported?
I'm able to build the menu by looping through the roles and setting up a list of menus.
Trying to build the routes on the fly using this.$router.addRoutes(newRoute);
To do that I need the component to already be imported.
The Quasar way is load the components on the fly I guess.
In router.js
function loadPage (component) {
return () => import(`../../pages/${component}.vue`)
}
I can't seem to use that function in a method section.
Is this possible in Vue?
Take a look at vue-router lazy loading documentation and Quasar lazy loading documentation
You can't do it in a method, but if the user permission don't match the route permissions the component is never loaded, which is basically what you want.
Example
const routes = [
{
path: '/some-page-protected',
component: () => import('pages/SomePage'),
meta: {role: 'admin'}
}
]
Or
const SomePage = () => ('pages/SomePage')
const routes = [
{
path: '/some-page-protected',
component: SomePage,
meta: {role: 'admin'}
}
]

Vue - Passing same data from one component to many component

I have the following code.
main.js
new Vue({
el: '#app',
template: '<App/>',
components: { App }
})
App.vue
<template>
<div id="app">
// this does not pass the data to the component
<basics :resume="resume"></basics>
<education :resume="resume"></education>
// this gets the value from the json file
{{resumeData.name}}
{{resumeData.education}}
</div>
</template>
<script>
import Basics from './components/Basics.vue'
import Education from './components/Education.vue'
import Resume from '../resume.json'
export default {
name: 'app',
data() {
return {
resumeData: Resume
}
},
components: {
Basics,
Education
}
}
</script>
/components/Basics.vue
<template>
<div>
<p>Basics</p>
// this does not get the value from the json file
{{resumeData.name}}
</div>
</template>
/components/Education.vue
<template>
<div>
<p>Education</p>
{{resumeData.education}}
</div>
</template>
How do I pass the data from one component to another such that all the different vue components is reading data from the same json file without inserting the code import Resume from '../resume.json in each component?
I hope you understand my question.
A more common / standard way is just use props. Or you have to import the json in all your components.
If you have many components and really don't want to pass the same prop several times, there is tricky solution: inject the data to the Vue.prototype globally:
Vue.prototype.$resume = {
name: 'foo',
education: 'bar',
...
}
with this, all your components can access it via this.$resume. But use it wisely.
If you have other similar cases, you probably should go for vuex.
In vue.js course you can solve this in 3 different ways.
Use props to pass data in Basics and Education
Vuex
Event box

How can I get vue-router data into the parent template?

I have 2 route components:
1) A people product list component 2) A product detail component
The list shows the products and then there is a router-link to that product using history in the router definition/scope.
What I am trying to achieve is to get the data from the parent list routes into the child detail product template.
So I am working with vuex as I am storing the data in the store method. Below is the gist example with the setup I have got.
https://gist.github.com/mdunbavan/5cb756ff60e5c5efd4e5cd332dcffc04
The PeopleListing component works well and when clicking the router link it goes to the correct url and the data in the vue debug looks okay for vuex as below:
state:Object
currentProduct:undefined
products:Array[0]
route:Object
from:Object
fullPath:"/products/copy-of-long-shirt-dress-tudor"
hash:""
meta:Object (empty)
name:"product"
params:Object
path:"/products/copy-of-long-shirt-dress-tudor"
query:Object (empty)
What I am trying to do is basically render the data so it shows the router data within the homepage still and not look like it is going to another page which is what it is doing at the moment. The journey I am looking to create is as follows:
1) index page renders the PeopleListing
2) when clicking the it opens some animation within that template
3) the animation then renders the data from that clicked route such as '/products/the-product-title'
On point 3) we have to try and get all data attributes from that object.
Is it possible with the setup that I have got in my gist?
Thanks in advance!!
'product/:handle' is a child route for the '/' route, as you want to nest them.
Your router should look like this.
As you want to pass data to your route using params.
When props is set to true, the route.params will be set as the component props.
const router = new VueRouter({
mode: 'history',
routes: [
{ path: '/', component: PeopleListing,
children: [
{ name: 'product', path: '/products/:handle', component: ProductDetail, props: true }
]
},
]
});

Categories

Resources