Sending variables from one view to another view and url in vue - vue.js

What I want is when I click an image, it redirects to a URL (another view) which is made by the something/image_name. I am making the project in vue.js. I am thinking of doing this by using props (passing all the variables needed from the first view to the next view). But the data is not displayed in the 2nd view. Also, I want to know how can I make the URL like something/image_name. I am using it by hardcoding the URL.
routes.js
const router = new Router({
mode: "foo",
base: "foobar",
routes: [
{
path: "/event/:title",
name: "event",
component: event,
props: true,
}
where title is the variable (event.title to be more precise) I want to pass from other view. I also want to get title in URL also.
view 1
<template>
<div src="image_location" :to="/event/{{event.title}}"></div>
</template>
<script>
export default {
name: "event",
components: {
Event
},
data: function initData() {
return {
event: {},
};
},
};
</script>
view 2 (Event.vue) (its URL should be foobar/event/{{ title }})
props: {
event: Object,
}
I tried router-link also but lack of its documentation restricts me from using it efficiently.

You can add an #click event to the image and programmatically move the user to the new URL when they click on the image. Something like:
<imge src="..." #click="$router.push(`/event/${event.title}`)" />

Related

How to pass props to named views through <router-link /> in vuejs?

I’m new to VueJS and front end development.
I’m looking to pass a props (in this case, my club’s id) to my component/view.
It was initially working with <router-link :to="{ name: 'club', params: {id: club.id } }">.
My component call a props “id”, and my view, named club has the parameter props:true;
Fast forward a little later, i had to add named view. (I only added one for now - but i’ll have a view content and one nav).
mode: 'history',
base: process.env.BASE_URL,
linkExactActiveClass: 'is-active',
routes: [
{
path: '/',
name: 'clubs',
components: {
content: Clubs
}
},
{
path: '/club/:id',
name: 'club',
props: true,
components: {
content: Club
}
}
]
})
And this broke everything.
In the Vue extension, i can see that my send is sending my props as a param (see attachement 1), but once on the view, the id is undefined (see attachment 2).
Am i missing anything?
Attachement 1
Attachement 2
You'd need to set a props value for each named view in that case. e.g.
components: {
content: Club
},
props: {
content: true
}
I can't find a decent explanation of this in the documentation but it does feature in an example here:
https://router.vuejs.org/guide/essentials/passing-props.html
Note the following comment lurking in the code example:
// for routes with named views, you have to define the `props` option for each named view:

Dynamic Vue Router

I am researching whether a vue router is the best approach for the following scenario:
I have a page containing 'n' number of divs. Each of the divs have different content inside them. When a user clicks on a button in the div, I would like the div to open in a separate browser window (including its contents).
Can a route name/component be created on the fly to route to? Since I have 'n' number of divs, that are created dynamically, I cannot hard-code name/components for each one
<router-link :to="{ name: 'fooRoute'}" target="_blank">
Link Text
</router-link>
I want to avoid the same component instance being used (via route with params) since I may want multiple divs to be open at the same time (each one in their own browser window)
If the link is opening in a separate window, it makes no sense to use a <router-link> component as the application will load from scratch in any case. You can use an anchor element instead and generate the href property dynamically for each div.
To answer your questions:
A route name cannot be created dynamically since all routes must be defined at the beginning, when the app (along with router) is being initialized. That said, you can have a dynamic route and then dynamically generate different paths that will be matched by that route.
There is no way for the same component instance to be reused if it's running in a separate browser window/tab.
It is possible to create dynamic router name.
profileList.vue
<template>
<main>
<b-container>
<b-card
v-for="username in ['a', 'b']"
:key="username"
>
<b-link :to="{ name: profileType + 'Profile', params: { [profileType + 'name']: username }}">Details</b-link>
</b-container>
</main>
</template>
<script>
export default {
name: 'profileList',
data () {
return {
profileType: ''
}
},
watch: {
// Call again the method if the route changes.
'$route': function () {
this.whatPageLoaded()
}
},
created () {
this.whatPageLoaded()
},
methods: {
whatPageLoaded () {
this.profileType = this.$route.path // /user or /place
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style>
</style>
b-container, b-card, b-link are taken from bootstrap-vue, so you can freely change it.
router.js
const router = new Router({
mode: 'hash',
base: process.env.BASE_URL,
linkExactActiveClass: 'active',
routes: [
// USERS
{
path: '/user/:username',
name: userProfile,
component: userProfile
},
{
path: '/user',
name: 'userList',
component: profileList
},
// PLACES
{
path: '/place/:placename',
name: placeProfile,
component: placeProfile
},
{
path: '/place',
name: 'placeList',
component: ProfileList
}
]
})

How to use "data" or "methods" result to VueRouter prop

I have simple menu tabs router as follow:
Tab 1 | Tab 2 | Tab 3
Routes are attached with individual component to each tab as example below.
const router = new VueRouter({
routes: [
{ path: '/views/type1', component: Type1, props: { listname: value} }
]
})
Problem:
How route[] prop modify to take the value from "data" of vue. Basically,
one of the component accept property as 'Array' and I need to pull those data from service and attach to component.
routes: [
{ path: '/views/type1', component: Type1, props: { collection: *[retrieve from service and attach here]*} }
]
//collection is not able to bind from "methods" or "data" , it only accepts static data.
The props field of Vue Router does not hold properties to be passed to the rendered view component, but rather it is a Boolean flag (or a hash/map of view names to Boolean flags) that tells Vue Router to pass any route parameters (parsed from the path) as properties to the component.
For example, given the following:
route config:
{
path: '/user/:name/:uid',
component: User,
props: true
}
User component definition:
export default {
props: ['name', 'uid']
}
URL:
/user/john/123
Then, User would be rendered with name set to john and uid set to 123, equivalent to this:
<User :name="john" :uid="123" />
If you need to initialize a view with server data, you could wrap the target component (e.g., with Type1View) that you initialize after you've fetched the data. In the example below, Type1.list is bound to a local list data variable. When Type1View mounts, we fetch data from the server, and save the result in list, which also updates Type1.list.
<template>
<div>
<Type1 :list="list" />
</div>
</template>
<script>
export default {
name: 'Type1View',
data() {
return {
list: []
}
},
async mounted() {
const data = await this.fetchData();
this.list = data.list;
}
}
</script>

How to pass data from one view to another with the vue-router

When using the vue-router with .vue files, there is no documented way to pass data from one view/component to another.
Let's take the following setup...
main.js:
import Vue from 'vue';
import VueRouter from 'vue-router';
Vue.use(VueRouter);
let routes = [
{
path: '/page1',
component: require('./views/Posts.vue')
},
{
path: '/page2',
component: require('./views/EditPost.vue')
}
];
let router = new VueRouter({
routes
});
new Vue({
el: '#main',
router
});
Posts.vue:
<template>
<div>
Posts.vue passing the ID to EditPost.vue: {{ postId }}
</div>
</template>
<script>
export default {
data() {
return {
allPostsHere: // Whatever...
}
}
}
</script>
EditPost.vue:
<template>
<div>
EditPost.vue received ID from Posts.vue: {{ receivedId }}
</div>
</template>
<script>
export default {
data() {
return {
receivedId: // This is where I need the ID from Posts.vue
}
}
}
</script>
Please note: It is not possible to receive the ID directly from the EditPost.vue, because it has to be selected from Posts.vue.
Question: How can I pass the ID from one view/component to the other?
A route can only be accessed via a URL and a URL has to be something user can type into the URL bar, therefore to pass a variable from one view component to another you have to use route params.
I assume you have a list of posts in Posts component and want to change page to edit a specific post in EditPost component.
The most basic setup would be to add a link in the post list to redirect to the edit page:
<div v-for="post in posts">
{{ post.title }}
<router-link :to="'/post/' + post.id + '/edit'">Edit</router-link>
</div>
Your routes would look like this:
[
{
path: '/posts',
component: require('./views/Posts.vue'),
},
{
path: '/post/:postId/edit',
component: require('./views/EditPost.vue'),
props: true,
},
]
The props configuration option is just to inform the Router to convert route params to component props. For more information see Passing props to route components.
Then in EditPost you'd accept the id and fetch the post from server.
export default {
props: ['postId'],
data() {
return {
post: null,
}
},
mounted() {
this.fetchPost();
},
methods: {
fetchPost() {
axios.get('/api/post/' + this.postId)
.then(response => this.post = response.data);
},
},
}
After the request has been completed, EditPost has its own copy which it can further process.
Note, that on every post edit and every time you enter the post list, you'll make a request to the server which in some cases may be unnecessary, because all needed information is already in the post list and doesn't change between requests. If you want to improve performance in such cases, I'd advise integrating Vuex into your app.
If you decide to do so, the components would look very similar, except instead of fetching the post to edit via an HTTP request, you'd retrieve it from the Vuex store. See Vuex documentation for more information.
if you don't want the params appear in the URL bar,you can use window.sessionStorage, window.localStorage or vuex.
Before you leave the view, set your parameters and get it after entering the new view.
You can use a prop on the <router-view :my-id="parentStoredId"></router-view> to pass down data present in the app.vue (main component). To change the parent data you need to emit a custom event comprising the value, from the childs (Posts.vue, EditPost.vue).
Another way is the Non Parent-Child Communication.
The way I prefer is Vuex. Even if it require you to learn the usage, it will repay back when the app grows.

Vue render component as modal in specific route if route metadata key is set to true

I'm using vue-router and i'm trying to create a functionality as follows:
I want to be able to specify in the router routes if a component should be rendered in modal or not. And if it is rendered in Modal keep every component below ( under modal-mask ) as it was.
I've created a modal-wrapper component that have basic modal structure and slot inside its modal body so the component I want to render should go in the slot. But how to achieve that. Does Vue-Router have options for that functioanlity.
Router routes:
{
path: '/customers/:clientId',
component: customerView
meta: {
auth: true,
},
},
{
path: '/customers/:clientId/addAddress',
component: dataViewAdd
meta: {
openInModal: true,
auth: true,
},
},
Since if component should be rendered inside modal while overlaying the previous router-view, I guess ill need 2 router-views.
<router-view class="normal-view"></router-view>
<router-view class="modal-view" name="modal-view"></router-view>
If the component displayed in each modal route was not used in a non-modal context, then you can just modify the modal route component's template (dataViewAdd) so that the modal component is the root of the template. But you mentioned that you would be reusing these components in different situations (so one route might use dataViewAdd inside a modal and another route might use dataViewAdd not inside a modal).
You could create wrapper modal versions of each component, but that'll become messy; it looks like you just want to be able to specify openInModal: true and have it work for any component.
You also mentioned that the position of the modal in the DOM doesn't matter (otherwise I'd recommend using something like portal-vue to assist with this).
First you'll need to change your router configuration so that the modal route is a child of the component you want to keep visible underneath it. Make sure customerView has a <router-view> inside it.
Create a helper function which returns a modal-wrapped version of the component and use that as the route component. This doesn't use the openInModal meta property, but it works in a similar way.
The following code is untested.
import Modal from './modal.vue';
function wrapInsideModal(childComponent) {
return {
functional: true,
render(h) {
return h(Modal, [h(childComponent)]);
},
};
}
// Routes
{
path: '/customers/:clientId',
component: customerView,
meta: {
auth: true,
},
children: [
{
path: 'addAddress',
component: wrapInsideModal(dataViewAdd),
},
],
},