Single file component - re mount component on changing a value from navbar - vue.js

This is the structure of my vuejs application.
<template>
<div class="page-body-wrapper">
<Sidebar/>
<div class="main-panel">
<Header/>
<div class="content-wrapper">
<router-view></router-view>
</div>
</div>
</div>
</template>
<script>
import Header from '../header/header';
import Sidebar from '../sidebar/sidebar';
export default {
name: 'Layout',
components: {
Header,
Sidebar
}
}
</script>
In all the routes that are rendered inside <router-view>, i am calling various functions and api calls based on a store variable 'myValue'. And, I have a dropdown in my <Header/> component ( which is common for all routes). Whenever I select a value from the dropdown in header, the store variable 'myValue' changes. Now, I need to remount whatever component is rendered inside <router-view> whenever the store variable 'myValue' changes. Using watch will be a last option since I will have to do the same in a number of components. I cannot use computed, since I have to fetch all data in either 'created' or 'mounted' hook. Is there any option to remount the entire <router-view> when a store variable changes? Note: I am using vuex for state management.

Just pass a key to <router-view :key="myValue"></router-view>, or in your case <router-view :key="$store.state.myValue"></router-view>.
Also check out this answer.

Related

Insert 2 components in nuxt.js page

i'm new of this framework :(
the problem is here because i've tried to put the component in another page and work it.
It sign error the component
this is my index.vue page
If you're using nuxt2.0, you should wrap them in a container but this is not needed in nuxt3.0.
<template>
<main>
<navbar />
<slideshow />
</main>
</template>
If this is nuxt2.0, then you should also import the component and register it but you haven't done it here. The path you've given to the component is not correct also.
<script>
import Slideshow from '~/components/slideshow.vue';
export default {
components: { Slideshow }
}
</script>
You need to wrap the into a div or any other tag (to not have multiple tags at the root of the template) like that
<template>
<div>
<navbar></navbar>
<slideshow></slideshow>
</div>
</template>
And you can also skip the import part because Nuxt is already doing that for you as explained here: https://nuxtjs.org/tutorials/improve-your-developer-experience-with-nuxt-components/

How to render child components in parent component in vue.js and only render the changes occurred in child component?

What I have done so far is created two componenets which are present in src/components folder and I want to add these components which is contained by parent component present in src/views folder.
I have one component named form.vue and another component background.vue
And what I want is, to show the form.vue (which contains a form) on top of backgound.vue (which is for background purpose). So every time, any changes happen in child,forces the whole parent page to re-render. So is there any way to solve this ?
Below are folder structure:
You can use slots for that, so in your background.vue you would have:
<template>
...
<slot><slot> <!-- place where the external component will be rendered -->
...
</template>
and then in the main component, you would have:
<background>
<my-form></my-form>
</background>
create 3 components and call 2 of them into 3rd component.
For example:
You have
component1.vue
component2.vue
component3.vue
In component3.vue:
<script>
//import components
import componentOne from '/path/to/component1'
import componentTwo from '/path/to/component2'
//now register them locally to use them in this component
export default{
components:{componentOne, componentTwo}
}
//now call these components in <template> section using kebab case
<template>
<div>
<component-one /> //camelCAse name of component in <script> tag is used in kebab case in template section
<component-two /> // means componentTwo will called as <component-two/>
</div>
</template>
</script>

How to update properties of component for dynamic router-link in vuejs

So new to Vue and haven't found anything that specifically addresses my issue.
I have a simple Vue app using VueRouter where I am trying to generate a bracket-style sports tournament that records the outcomes of the different games in the tournament.
I need to make an asynchronous axios call to a server to get info on a specific game. I do not know how to update my component properly to get this info.
App.vue is very simple. The home page is just an overview of the bracket
<template>
<div id="app">
<div id="nav">
<router-link :to="{ name: 'bracket'}">Bracket</router-link>
</div>
<router-view />
</div>
</template>
I have a view component, Bracket.vue, and, for now, all I want this view do is provide links to the different matchups in the tourney.
I have made this work pretty well dynamically as follows:
<template>
<div class="home">
<div id="nav">
<div v-for="round in rounds" :key="round">
<router-link v-for="game in gamesPerRound" :key="matchupKey(round, game)" :to="{ name: 'matchup', params: {round: round, game: game} }">Matchup {{ round }} {{ game }}</router-link>
</div>
</div>
</div>
</template>
When link is clicked, I pull up another view component, Matchup.vue, which I would like to display certain data about the matchup. (MatchupService is an axios API instance)
I pass the round # and the game # as props via router-link. These load fine in the Matchup.vue.
However, when I try to make an asynchronous call to get the matchup data, nothing happens. the matchup property never updates, not on the link click or ever. So I either get nothing (when I use a ternary as per below) or an error if I just try to use the matchup value
Matchup.vue
<template>
<div class="matchup">
<h1>Round {{ round }}</h1>
<h2>Game {{ game }}</h2>
<h6>Team 1: {{matchup.teams ? matchup.teams[0]: 0}}</h6>
<h6>Team 2: {{matchup.teams ? matchup.teams[1] : 0}}</h6>
</div>
</template>
<script>
import MatchupService from '#/services/MatchupService.js'
export default {
props: ["round", "game"],
data() {
return {
matchup: {},
}
},
async updated() {
let matchups = await MatchupService.getMatchups()
this.matchup = matchups.data.rounds[this.round].games[this.game]
},
}
</script>
I have tried many different approaches on this: updated vs. created vs. other hooks, I've tried to update a property post-load and hook that to v-if, etc.
I am just totally stymied on this so hoping for some help.
Looks like you need to use navigation hook beforeEnter in your router.js file or you can use beforeRouteEnter hook directly in your compoennt file. (NOTICE! Using beforeRouteEnter in a component file you can't access 'this', so maybe, there is a reason to use Vuex if you want to store some data within serfing your app). There you can define/fetch/set any data before redirect user to a specific page. By this way you do any actions you want and set it before redirecting.
More about you can find here:
https://router.vuejs.org/guide/advanced/navigation-guards.html

How to pass data to a router-view in Vue.js

How can I pass data from my main app to a component through router-view in Vue.js? I have successfully gotten the data from my API as shown below:
mounted() {
// console.log(model)
this.model = model;
// console.log(this.model)
}
The component I want to pass data to has been loaded as shown below:
#section('content')
<div style="padding: 0.9rem" id="app">
<router-view name="bookBus"></router-view>
<router-view></router-view>
{{-- #{{ model }} --}}
</div>
#stop
How do I pass the model data to the bookBus component?
From https://router.vuejs.org/en/api/router-view.html
Any non-name props will be passed along to the rendered component, however most of the time the per-route data is contained in the route's params.
So if you want to pass data down from the parent component, rather than from the router, it would be something like this:
<router-view name="bookBus" :model="model"></router-view>
Your bookBus component would then need to have a model prop configured to receive the data, just like it would for any other prop.

v-if on a component template tag

From the docs:
Because v-if is a directive, it has to be attached to a single
element. But what if we want to toggle more than one element? In this
case we can use v-if on a element, which serves as an
invisible wrapper. The final rendered result will not include the
element.
But on my template in my component:
<template v-if="false">
<div>
....
</div>
</template>
But the component still renders.
I ask because I want a hook on the component so if v-if is true, I can do some code in beforeMounted and beforeDestroyed if false.
If I undestood what are you doing...
You're putting v-if int the template tag ina .vue file right?
Like this
// component.vue
<template v-if="false">
<div>
My Component
</div>
</template>
<script>
export default {
name: 'my-component'
};
</script>
<styles>
</styles>
Right?
If YES, you are doing it wrong.
The template there is a tag for Webpack Vue Loader to load the component template.
So the if must go inside the template tag.
// component.vue
<template>
<div v-if="false">
My Component
</div>
</template>
<script>
export default {
name: 'my-component'
};
</script>
<styles>
</styles>
If you need to "hide" multiple elements, just encapsulate into another div.
As Lucas Katayama said, you cannot use v-if inside SFC, but another way to hide you component is use v-if on this component in its parent component.
Your reference to the docs is correct, you can use a v-if on a template tag. However, I believe conditionals on the top-level <template> in a Single File Component are ignored.
To achieve the effect showed in the docs (conditional render a template) that template needs to be within the top-level template section.
Example:
<script>
// your script section
</script>
<template>
<template v-if="false">
<div>
....
</div>
</template>
</template>
<style>
// your style section
</style>