passing data between components with vue-router - vue.js

There a re quite a few question with kind of a similar title to mine, but that is where my problem lies. Let's take a very common case where i'm building a recipe book.
i'm looping over my recipes and creating a link to the Recipe.vue component:
<router-link v-for="recipe in recipes" :to="{path: `/recipe/${recipe.title}`">
<a>{{recipe.id}}</a>
</router-link>
now from what i understand there are few solutions:
1. setting props:true and pass a prop:
<router-link v-for="recipe in recipes" :to="{name: 'Recipe', params: {recipe}}">
<a>{{recipe.title}}</a>
</router-link>
set Recipe as child component and pass the data as a regur parent=>child data transfer
use Vuex and state management to then "withdraw" the data from the store in the Recipe component
pass id to the Recipe component and then when its mounted() execute an http request to get the data of the specific item.
I'm finding it hard to understand what is considered best practice here and what should i choose for my production env.
the voice inside me says that number 3 - state management is an overkill and #4 is an unnecessary api call since i already have the data i need.
Any advice on which method should i use in the basic case of: first component is a list of recipes and then navigate from it to a component with single purpose of displaying the recipe data?

Related

Vue Router cancelling route

When I click on a link in my Vue app, it returns to the initial route where it is coming from.
I do not seem to have found this error/bug anywhere and currently do not know what to do
<router-link to="/user/info" >
Information
</router-link>
<router-link to="/user/loan" >
Loans
</router-link>
<router-link to="/user/documents" >
Documents
</router-link>
If I click on Loans, it goes back to Information, if I click Documents, it goes back to Information
If I had to guess, it sounds like the issue might be with the routes you've setup and not with the links themselves.
I'd check them to see if the paths you define in the VueRouter match the ones used in your router-link elements. You can find more info about defining routes in the vue-router documentation.

Vue: communicating parameters from app to component and back, using computed properties

Sorry for the beginner question (I'm fairly sure this will be a duplicate, but I actually can't figure out what terms to use in order to find it). I just started with Vue.
I am just getting started with Vue, and following this course (https://www.vuemastery.com/courses/intro-to-vue-js/communicating-events). In this problem, there is (and here I don't know the term, so I'm going to go with...) app-level data parameter called cart. cart is an array which holds the id of each item a user has added to cart.
The problem tells us to add a button to remove items from the cart.
I ran into problems trying to create a computed property, which would allow me to hide the "remove" button in the event the selected item is not in the cart (eg. `
Communicating data from the app-level (the cart array), to the component-level (to a computed property in the product component), so that I could use something like :hidden="!inCart" on the "Remove from Cart" button, which is itself defined in the component. inCart would be a computed value here.
Communicating the selected product from the component to the app-level, computing inCart at the app level, then using the computed value at the component-level.
Either way, I can't seem to figure out how to do this in the way I would want to, which would look something like how v-bind operates. Namely, I think I may be able to hack together a solution using methods (which I believe have to be triggered by certain events), but I don't understand how I might go about this using built-in functionality such that the value of inCart is dynamically auto-computed.
Maybe there would be an answer to this in the next few courses, but I don't see us covering that in the intro material. Sorry for the neophyte question. Thank you in advance.
In Vue the way you communicate "state" from higher-level objects to lower-level objects is through props.
So, assuming your app looks something like...
<MyApp>
<MyShoppingPageWithItems>
<MyItem></MyItem>
<MyItem></MyItem>
<MyShoppingPageWithItems>
</MyApp>
You need to pass the cart object down as a prop.
So in your MyShoppingPageWithItems template, you'll have something like...
<template>
<div>
<MyItem v-for="item in items" :item=item :cart="cart"?
</MyItem>
</div>
</template>
And in your item template...
<template>
<div>
<div>
{{item.name}}
</div>
<div v-if="cart.includes(item.id)">
Remove button or whatever
</div>
</div>
</template>
Not that the .includes() method is a native JavaScript method, which you can read more about here.
Edit
To reference a prop in a computed property (or anywhere else in a Vue component), just refer to this.propName, as demonstrated here in the Vue docs.
So, if you want to create a computed property, you can do the following:
<template>
<div>
<div>
{{item.name}}
</div>
<div v-if="isInCart">
Remove button or whatever
</div>
</div>
</template>
<script>
export default {
props: ['cart', 'item'],
computed: {
isInCart() {
return this.cart.includes(this.item.id)
}
}
}
</script>
Note that the formula is the exact same as above, but just includes this. for cart and item. In templates, the this. is implied when referring to props, data, and computed properties.

Vue Router Data persistance

I have an app that requires a persistent connection (uses WEBRtc) The VUEX store can change based on a data transfer.
In my routes I have (for simplicity sake) 2 navs in my router view
<b-dropdown-item
href="#"
#click="$router.push({name: 'marriagesection', params: {id:Math.floor(Math.random() *10 )}})"
>Previous Marriages</b-dropdown-item>
<b-dropdown-item
href="#"
#click="$router.push('/applic/children',s,e)"
>Children / Grandchildren</b-dropdown-item>
When I navigate between them, I loose the data.
I have tried putting a :key on the router-view, explored beforeEnter, and created a mutation that I subscribe to to get the info initialized again - this works if I console log it, but it doe not update the DOM. I have used :keys in the do after getting the info and still doesn't work. I have more than 3 days on this problem and there is a severe lack of documentation on this issue.
I have MUCH to much to keep all of the information in a store, and the DOM has to respond to changes in other views, making use of VUEX almost impossible, or so large it almost would become useless.
Please help

Vuejs: data through the router-view

Is it a good practice to pass data through the router-view? I have a nested router and some children have to have access to the data that parent is having. I know Vuex is the way to pass the data all over the app, but I`d like to know what are the exact disadvantages of binding data to the router-view to make it available in the child components.
So for now I have something like that:
<router-view v-bind:list="array" />
You can programtically pass through router like below
from parent component trigger below fn on click or redirection
this.$router.push({
name: 'ChildRouteName',
params: {'type':'name', 'id': '1',}
})
and in child component receive the parameters like this
type = this.$route.params['type']
id = this.$route.params['id']
You can pass data to the rendered component using the router-view but most likely is not what you want.
Routing can happen from any part of your app, but if you pass info via router-view you need to update the data that is bound to the view, which in turn means to have access to the component enclosing the template that presents router-view. This ends up tightly coupling components or using the bus/vuex.
You could use Vuex to pass the information, but there is a much easier way to pass information when routing.
You can define your route to transform parameters set when routing to props to the component. More info here. This means that you can make a call similar to this:
<router-link :to="{ name: 'routeName', params: { id: 1 }}">Go to route</router-link>
and then whatever component is registered for routeName will get the prop id set to value 1. The same will happen if you trigger a navigation programatically.

Trouble with routing Vue.js 2 and browser history

Faced such a problem - I send data to the props of the /router-link/ tag, when I click on the link, I go to the article, it gets the data, everything works. Well, if you press the "back" button in the browser and then "forward" there will be no articles, there will be empty fields without data. How can this be avoided?
This is link to the article
<h3 class="database-article__title">
<router-link
:to="{name : 'article',params: {
id: item.id ,
type:item.type ,
name: item.name,
text: item.text,
author: item.author,
isFavorite: item.isFavorite
}}"> {{item.name}} </router-link>
</h3>
Little part of article-template.vue
<div class="content-type marketing">
{{$route.params.type}}
</div>
<h3 class="database-article__title">
{{$route.params.name}}
</h3>
<div class="database-article__text">
{{$route.params.text}}
</div>
Once again, the data transfer is good, when you click on the link, everything is displayed. The problem is that when clicking on the buttons in the browser "back" and "forward" - the browser history is not saved.
Does anyone know the solution to the problem, or where i can read how to solve it?
Thanks!
My guess is that your article route does not specify any of those params in its path. When you click the link, vue-router will remember the params object you specified in the <router-link> and will be accessible through $route.params in the article component.
However, when you click the browser back then forward buttons, the transition to the article route did not occur by clicking the <router-link> like it did the first time, and since those params were not included in the route's path, $route.params will be empty.
I'm guessing you're just trying to pass data from one route to another. If you want it to persist across history state changes (i.e. browser back/forward), then either:
The data needs to be included in the URL, either as params (e.g. /article/:id/:type etc, this needs to be specified upfront in the route's path) or in the query string (e.g. /article?id=1&type=foo). This isn't ideal for this situation.
(Recommended) Store the item object in such a way that it can be accessed by any route. Vuex is one way, but this may be overkill.
Realistically your URLs should only need to have the article's ID in it, like this /article/1. All the other stuff like type/name/etc don't belong in the URL. From the ID you should be able to fetch the full article object either from a REST API (XHR request), or obtain it from some in-memory data store abstraction (Vuex or anything else really).