Matching route to preselected value in VueJS - vue.js

In the first componen I have several buttons that should redirect to certain nested route based on which button was clicked.
<btn to="financials/financialdata"></btn>
<btn to="financials/revenuedata"></btn>
This route displays a component that should be different depending on the route name. The most important thing is the options form where the value that is preselected matches the route name but a bit differently.
Here is how i confiugred that route in router
{ path: '/financials/:name', component: dataview}
This is my select form:
<v-select
:items="datasets"
label="Solo field"
item-text="text"
item-value="value"
v-model="data"
dense
solo
></v-select>
And here is the options:
datasets: [
{
text: "Financial Condition",
value: 'A'
},
{
text: "Revenue Data",
value:'B'
}]
So how can match the route name with the value in the dataset, so that i can be preselected in the select form?
I also want to display which route is currently displayed in the title on the component page:
<h1>{{title}}</h1>
So based on the route param it would display the same title as selected in the form (so based on the dataset)

in your router config... add a name to the route or use meta parameter
in routes file:
{
path: "/revenue",
name: "Revenue",
component: Revenue
}
in select component:
<script>
export default {
data() {
return {
datasets: [
{
text: "Financial Condition",
value: "A"
},
{
text: "Revenue Data",
value: "Revenue"
}
]
};
},
mounted() {
this.selectValue = this.$route.name;
}
};
</script>

In your component, in the created function you could set or update the datasets or what you are binding the form to with the route params.
created: function () {
this.yourformdata = this.$route.params.thevalue
},

Related

Passing to v-model a composed value

I'm using Quasar v.2 with VueJs 3.
I'm using the q-select component in order to switch dynamically the language. Here's my code:
<template>
<q-select v-model="$i18n.locale" :options="langs">
</q-select>
</template>
<script lang="ts">
export default defineComponent({
name: 'LanguageSwitch',
setup() {
const langs = ['en', 'jp']
return {langs}
}
</script>
What I want to do now is to keep displaying "en" and "jp", and to concatenate them with another word (to form, for example "en-US") in the moment I pass them to the i18n.locale
You could update langs to include the desired values and labels:
export default defineComponent({
setup() {
const langs = [
{ value: 'en-US', label: 'en' },
{ value: 'jp-JP', label: 'jp' },
]
return { langs }
}
}
Then set <q-select>.optionValue to "value" so it uses the item's value property as the option value, and <q-select>.optionLabel to "label" to use the item's label property as the label:
<q-select v-model="$i18n.locale" :options="langs"
option-value="value"
option-label="label">
</q-select>

VueJs use props that comes from <router-link>

i have a navbar and there is a text field in that the user can search for posts by tags. If the user enters 1-3 tags, the written tags will be stored in a tags array.
My router-link in the navbar component looks like this: (only relevant part)
<router-link :to="{name:'posts', props:{searchTags: tags}}">
<button type="button" v-if="this.tags.length > 0"
class="...">Search
</button>
</router-link>
in my routes.js is my posts route (important snippet of my routes.js)
routes: [
{
path: "/posts",
component: posts,
name: 'posts'
},
]
The navbar should send the tags array to the posts component. Unfortunately I can't do it.
The posts component, sends a post request to an API that gets the latest posts. But I want that when tags are passed, not the newest posts are fetched, only posts with certain tags. But first I have to get the tags somehow.
I tried to get them with "this.$props.searchTags" and other things. Unfortunately the result is always "undefined".
export default {
name: "posts",
props: {
searchTags: Array,
required: false
},
data: function () {
return {
apiUrl: '/getPosts',
....
tags: [this.searchTags],
}
},
methods: {
getPosts: function (url) {
this.$http.get(url).then(function (data) {
// blabla
});
},
getPostsByTags: function() {
//
},
},
created() {
if(this.$props.searchTags == null)
this.getPosts(this.apiUrl);
else
this.getPostsByTags(bla);
},
}
Router link to property accepts string or Location as a value. Location object does not have props property.
Instead, it is possible to use params to send data to route component:
<router-link
:to="{ name: 'posts', params: { searchTags: tags } }"
>
...
</router-link>
This way searchTags with value of assigned tags will be accessible via this.$route.params.searchTags inside destination component.
So created hook of example above should be updated to:
created () {
if (!this.$route.params.searchTags) {
this.getPosts(this.apiUrl);
} else {
this.getPostsByTags(bla);
}
},
Try to add props: true in your route definition
routes: [
{
path: "/posts",
component: posts,
name: 'posts',
props: true
},
]

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 editable data to component?

I'm working on an app that allows you to capture and edit soccer match results.
there is a Matches component that makes an AP call to get the data of multiple matches from a server (match_list) and then renders a bunch of Match components, passing the data as props to these sub-components to fill their initial values.
<component :is="Match" v-for="match in match_list"
v-bind:key="match.id"
v-bind="match"></component>
On the Match component, I accept all the values as props.
But I get a warning that props shouldn't be edited and these should be data elements instead. So I tried passing them to the component data.
export default {
name: "Match",
props: ['local_team', 'visitor_team', 'localScore', 'visitorScore', 'date', 'time', 'location', 'matchId'],
data(){
return{
id: this.id,
local_team: this.local_team,
visitor_team: this.visitor_team,
location: this.location,
date: this.date,
time: this.time,
localScore: this.localScore,
visitorScore: this.visitorScore
}
},
Now I get a warning that editable data shouldn't be based on props.
How can I make the data from the Match component editable so it safely propagates to the parent component?
You need to accept your match object on the component's props, and make a copy of it on data (to be used as a model for your inputs). When your model changes you should emit that change to the parent so that it can change its own data appropriately (which then gets passed and reflected correctly through the child's props):
In this example I watch for any changes to the model and then emit the event directly, you can of course replace that behavior by having a submit button that fires the event upon click or something.
Vue.component('match', {
template: `
<div>
<p>{{match.name}}</p>
<input v-model="matchModel.name" />
</div>
`,
props: ['match'],
data() {
return {
matchModel: Object.assign({}, this.match)
}
},
watch: {
matchModel: {
handler(val) {
this.$emit('match-change', val)
},
deep: true,
}
}
});
new Vue({
el: "#app",
data: {
matches: [{
id: 1,
name: 'first match'
},
{
id: 2,
name: 'second match'
}
]
},
methods: {
onMatchChange(id, newMatch) {
const match = this.matches.find((m) => m.id == id);
Object.assign(match, newMatch);
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.min.js"></script>
<div id="app">
<match v-for="match in matches" :match="match" :key="match.id" #match-change="onMatchChange(match.id, $event)"></match>
</div>

VueJS vue-router passing a value to a route

In VueJS 2 with vue-router 2 I am using a parent view with subcomponents like this:
WidgetContainer.vue with route /widget_container/:
<template>
<component :is="activeComponent"></component>
</template>
<script>
import WidgetA from './components/WidgetA'
import WidgetB from './components/WidgetB'
export default {
name: 'WidgetContainer',
components: {
WidgetA,
WidgetB
},
data () {
return {
activeComponent: 'widget-a'
}
}
}
</script>
In WidgetA I have the option of selecting a widget id
<template>
// v-for list logic here..
<router-link :to="{ path: '/widget_container/' + widget.id }"><span>{{widget.name}} </span></router-link>
</template>
<script>
export default {
name: 'WidgetA',
data() {
return {
widgets: [
{ id: 1,
name: 'blue-widget'
}]}}
routes.js:
export default new Router({
routes: [
{
path: '/widget_container',
component: WidgetContaner
},
{
path: '/widget_container/:id?',
redirect: to => {
const { params } = to
if (params.id) {
return '/widget_contaner/:id'
} else {
return '/widget_container'
}
}
}]})
From the WidgetContainer if the route is /widget_container/1 (where '1' is the id selected in WidgetA) I want to render WidgetB, but I cant work out:
1) how to pass the selected widget id into the router-link in WidgetA
2) How to know in WidgetContainer the the route is /widget_contaner/1 instead of /widget_container/ and render WidgetB accordingly.
Any ideas?
You can pass data to parent using by emitting event, you can see more details around here and here.
Once the data is change, you can watch over it and update the variable which has stored your widget.
Another option, if communication between components become unmanageable over time is to use some central state management, like vuex, more details can be found here.
Wouldn't it be easier and more scallable to use Vuex for that?
Just commit id to store and than navigate ?