How to trigger a transition when a component is reused? - vue.js

How to trigger a transition when transitioning between the same component?
(With vue-router 1, there was a canReuse hook. It doesn't exist anymore in vue-router 2.)
const Index = {
template: `<div id="app">
<router-link :to="{ path: '1' }">page 1</router-link> |
<router-link :to="{ path: '2' }">page 2</router-link>
<router-view></router-view>
</div>`
};
const Page = {
template: `<transition #enter="transitionEnter" #leave="transitionLeave">
<div>
<p>page {{ id }}</p>
</div>
</transition>`,
data() {
return {
id: this.$route.params.id,
}
},
methods: {
transitionEnter(el, done) {
console.log('transitionEnter');
done();
},
transitionLeave(el, done) {
console.log('transitionLeave');
done();
},
fetchData() {
this.id = this.$route.params.id;
}
},
watch: {
'$route': 'fetchData'
},
};
const App = Vue.extend(Index);
const router = new VueRouter({
routes: [{
path: '/:id',
component: Page
}, {
path: '*',
redirect: '/1'
}]
})
const app = new App({ router }).$mount('#app');
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
<div id="app"></div>

Use the key parameter on the router-view.
const Index = {
template: `<div id="app">
<p>app</p>
<router-link :to="{ path: '1' }">page 1</router-link> |
<router-link :to="{ path: '2' }">page 2</router-link>
<router-view :key="'a' + $route.params.id"></router-view>
</div>`
};
const Page = {
template: `<transition #enter="transitionEnter" #leave="transitionLeave">
<div>
<p>page {{ id }}</p>
</div>
</transition>`,
data() {
return {
id: this.$route.params.id,
}
},
methods: {
transitionEnter(el, done) {
console.log('transitionEnter');
done();
},
transitionLeave(el, done) {
console.log('transitionLeave');
done();
},
},
};
const App = Vue.extend(Index);
const router = new VueRouter({
routes: [{
path: '/:id',
component: Page
}, {
path: '*',
redirect: '/1'
}]
})
const app = new App({ router }).$mount('#app');
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
<div id="app"></div>

Related

How do you select a single array item from a data object and pass it to another component?

I have some data that I get from axios and pass to a Bootstrap table. In my computed properties where I declare the nameOfPerson field, I have made a click event, so that when a user clicks on the name, a modal opens. This modal also contains the data shown in the table.
However, I would like to change it so that when you click on the name of a person, ONLY the data for THAT single person gets passed to the modal. So instead of passing a prop containing data of ALL users the modal, I just want the data related to the name that I actually click on.
How would I accomplish this?
The parent:
<template>
<b-container>
<b-card class="mt-4">
<b-table
:items="dataItems"
:fields="fields"
:per-page="[5, 10]"
sort-desc
primary-key="id"
/>
</b-card>
<data-modal ref="dataModal" :selected-name="dataItems"/>
</b-container>
</template>
<script>
import {axiosComponent} from '#/axios/services';
import DataModal from '#/components/DataModal';
export default {
components: {
DataModal
},
data() {
return {
dataItems: null,
};
},
computed: {
fields() {
return [
{
key: 'nameOfperson',
label: 'name',
sortable: true
click: () => this.$refs.dataModal.show(),
},
{
key: 'ageOfPerson',
label: 'Age',
sortable: true
},
]
},
},
methods: {
load(){
axiosComponent.getData().then(result => {
this.dataItems = result.data
})
}
},
created() {
this.load()
}
};
</script>
The child (modal)
<template>
<b-modal v-model="showModal">
<div v-for="log in selectedName">
{{ log }}
</div>
</b-modal>
</template>
<script>
export default {
props: {
selectedName: Array
},
data() {
return {
showModal: false,
};
},
methods: {
show(){
this.showModal = true
}
}
};
</script>
You can use #row-selected method, take a look at following demo:
Vue.component('child', {
template: `
<b-modal v-model="showModal">
<div v-for="log in selectedName">
{{ log }}
</div>
</b-modal>
`,
props: {
selectedName: Array,
},
data() {
return {
showModal: false,
};
},
methods: {
show(){
this.showModal = true
}
}
})
new Vue({
el: "#demo",
data() {
return {
dataItems: null,
selected: null,
};
},
computed: {
fields() {
return [
{
key: 'nameOfperson',
label: 'name',
sortable: true,
},
{
key: 'ageOfPerson',
label: 'Age',
sortable: true
},
]
},
},
methods: {
load(){
// axiosComponent.getData().then(result => {
this.dataItems = [{id: 1, nameOfperson: 'aaa', ageOfPerson: 5}, {id: 2, nameOfperson: 'bbb', ageOfPerson: 25}, {id: 3, nameOfperson: 'ccc', ageOfPerson: 35}, {id: 4, nameOfperson: 'ddd', ageOfPerson: 45}]
// })
},
onRowSelected(items) {
this.selected = items
this.$refs.dataModal.show()
},
},
created() {
this.load()
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<link type="text/css" rel="stylesheet" href="https://unpkg.com/bootstrap/dist/css/bootstrap.min.css" />
<link type="text/css" rel="stylesheet" href="https://unpkg.com/bootstrap-vue#latest/dist/bootstrap-vue.min.css" />
<script src="https://unpkg.com/bootstrap-vue#latest/dist/bootstrap-vue.min.js"></script>
<script src="https://unpkg.com/bootstrap-vue#latest/dist/bootstrap-vue-icons.min.js"></script>
<div id="demo">
<b-container>
<b-card class="mt-4">
<b-table
:items="dataItems"
:fields="fields"
:per-page="5"
sort-desc
primary-key="id"
selectable
:select-mode="'single'"
#row-selected="onRowSelected"
/>
</b-card>
<child ref="dataModal" :selected-name="selected"></child>
</b-container>
</div>

Vue JS Children Nested Routes Not Showing

I'm having a problem with Vue JS Nested Routes. Children component is not showing. Here's my code.
Router
{
path: '/events',
name: 'Events',
components: {
default: () => import('#/views/SideNavigation/Events/index.vue'),
sidebar: () => import('#/components/SideNavigation/index.vue')
},
children:[
{
path: 'list',
component: { default: () => import('#/views/SideNavigation/Events/EventLists/index.vue'), }
},
{
path: 'create',
name: 'Create',
component: {
create: () => import('#/views/SideNavigation/Events/CreateEvent/index.vue'),
}
}
]
},
Event.vue (Parent)
<template>
<div class='events px-md-5 px-5 py-md-5 text-white'>
<router-link to="/events">/events</router-link>
<router-link to="/events/create">/create</router-link>
<router-view />
</div>
</template>
I have router-view in my App.vue. When I click the links my children components is not showing also the script is not found
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>

Component doesn't load while the route changes

I want to create a nested route with its children's route.
Basically what I want is,
https://localhost/contact render the ContactList component.
https://localhost/contact/add render the ContactAdd component.
What I have tried is:
let Layout = {
template: '<div>Layout Page <router-view></router-view></div>'
};
let Home = {
template: '<div>this is the home page. Go to <router-link to="/contact">contact</router-link> </div>'
};
let ContactList = {
template: '<div>this is contact list, click <router-link to="/contact/add">here</router-link> here to add contact</div>'
};
let ContactAdd = {
template: '<div>Contact Add</div>'
}
let router = new VueRouter({
routes: [{
path: '/',
redirect: 'home',
component: Layout,
children: [{
path: 'home',
component: Home
},
{
path: 'contact',
component: ContactList,
children: [{
path: 'add',
component: ContactAdd
}]
},
]
}]
});
new Vue({
el: '#app',
components: {
'App': {
template: '<div><router-view></router-view></div>'
},
},
router
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://unpkg.com/vue-router#3.0.1/dist/vue-router.js"></script>
<section id="app">
<app></app>
</section>
Here, the problem is when I change the route from /client to /client/add, the view doesn't render. What is the problem with the nested children's route here? How to solve this issue?
I check this documentation https://router.vuejs.org/guide/essentials/nested-routes.html, but It didn't help in this case.
You need to add one <router-view> in the template of <ContactList> to load its children route.
Or if you'd like to display ContactAdd in Layout, moves ContactAdd to direct child of path=/.
let Layout = {
template: '<div>Layout Page <router-view></router-view></div>'
};
let Home = {
template: '<div>this is the home page. Go to <router-link to="/contact">contact</router-link> </div>'
};
let ContactList = {
// add <router-view> in order to load children route of path='/contact'
template: '<div>this is contact list, click <router-link to="/contact/add">Add Contact In sub Router-View</router-link> here to add contact<p><router-view></router-view></p> Or Click <router-link to="/addcontact">Add Contact In Current Router-View</router-link></div>'
};
let ContactAdd = {
template: '<div>Contact Add</div>'
}
let router = new VueRouter({
routes: [{
path: '/',
redirect: 'home',
component: Layout,
children: [{
path: 'home',
component: Home
},
{
path: 'contact',
component: ContactList,
children: [{
path: 'add',
component: ContactAdd
}]
},
{
path: 'addcontact', // or move ContactAdd as direct child route of path=`/`
component: ContactAdd,
}
]
}]
});
new Vue({
el: '#app',
components: {
'App': {
template: '<div><router-view></router-view></div>'
},
},
router
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://unpkg.com/vue-router#3.0.1/dist/vue-router.js"></script>
<section id="app">
<app></app>
</section>

Vue Router: Redirects don't work with history mode

For some reason, a regular redirect rule does't works with history mode, but works well with hash mode.
Here is a code snippet:
let first = {
name: "first",
template: `<section><h1>First</h1></section>`
};
let second = {
name: "second",
template: `<section><h2>Second</h2></section>`
};
new Vue({
el: "#app",
router: new VueRouter(
{
mode: "history",
routes: [
{ path: "/", redirect: { name: 'first' }}, // Works with hash mode, but does't with history
{ path: "/first", component: first, name: "first"},
{ path: "/second", component: second, name: "second" }
]
}
)
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.10/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue-router/3.1.3/vue-router.min.js"></script>
<div id="app">
<router-link to="/first">First</router-link>
<router-link to="/second">Second</router-link>
<router-view></router-view>
</div>
Why?

Unable to show updated v-model value in input

I have the following code:
const BasicInput = {
template: '<input v-model="content" #input="handleInput" />',
prop: ["value"],
data() {
return {
content: this.value
};
},
methods: {
handleInput(e) {
this.$emit("input", this.content);
}
}
};
new Vue({
el: "#app",
data: { name: "" },
mounted() {
self = this;
setTimeout(() => {
self.name = "test";
}, 2000);
},
components: { BasicInput }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<basic-input v-model="name"></basic-input>
<p>
<strong>Name:</strong> {{ name }}
</p>
</div>
How do I get the updated v-model value to also show in the input tag ?
You need to v-bind the property for the BasicInput component. The short form of it is :.
See <basic-input :value="name"></basic-input> usage below, only changed it.
const BasicInput = {
template: '<input v-model="content" #input="handleInput" />',
prop: ["value"],
data() {
return {
content: this.value
};
},
methods: {
handleInput(e) {
this.$emit("input", this.content);
}
}
};
new Vue({
el: "#app",
data: { name: "" },
mounted() {
self = this;
setTimeout(() => {
self.name = "test";
}, 2000);
},
components: { BasicInput }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<basic-input :value="name"></basic-input>
<p>
<strong>Name:</strong> {{ name }}
</p>
</div>