Vue 3 prop returned as a string - vue-router

I have a router link:
<router-link
:to="{
name: 'EditStaff',
params: { id: key, staffInfo: staff }
}"
>
<i class="fas fa-edit text-info"></i>
</router-link>
and a view with the following prop;
props: {
staffInfo: {
type: Object,
required: true
}
}
with a route;
{
path: "/staff/edit/:id",
name: "EditStaff",
component: EditStaff,
props: true,
beforeEnter: requireAuth
},
When I log props.staffInfo in the EditStaff view, I am getting the string version of Object, "[object Object]".
What do I need to change to get the object?

If you're using console.log(props.staffInfo ) it may be converting your object to a string in-place
try console.log(JSON.stringify(props.staffInfo ,null, 2)) instead
const staffInfo = {gettingFired: 'falsešŸ¤ž'};
console.log(staffInfo); // what you'd hope to get
console.log(staffInfo.toString()); // but you might be doing this, especially if it happens in the template
console.log(JSON.stringify(staffInfo).toString()); // so convert to string first
If you're trying to output it in the template, {{ props.staffInfo }} will be converted to use a toString (or equivalent)`
You can use <pre>{{ JSON.stringify(props.staffInfo ,null, 2)) }}</pre> to have nicer output.

Related

regex for router links

I'm trying to build a navbar and since it will receive the links from a prop so it might be a router link or hyperlink which is why I want to use regex to check if the first character is / and if so then use push or else use href. however I'm getting one error. what am I doing wrong here? is my regex wrong? also is my approach correct?
error Unnecessary escape character: \/ no-useless-escape
my code so far
<template>
<nav>
<ul>
<li v-for="(item, $index) in navLinks" :key="$index">
<router-link :to="item.link" v-if="item.link.match(reg)">{{ item.name }}</router-link>
<a :href="item.link" v-else>{{ item.name }}</a>
</li>
</ul>
</nav>
</template>
<script>
export default {
name: "Navbar",
props: {
navLinks: {
type: Array,
},
data () {
return {
reg: '^[\/].*' // the regex which sees if the first character is `/` or not
}
}
}
</script>
the navlinks can be
const navLinks = [
{ name: "About",
link: "#about" },
{
name: "Projects",
link: "/projects",
},
];
In vue, if you want to use a variable in the template section then you need to define it inside the data property.
data () {
return {
reg: '^[/].*'
}
}
Now you can access this reg in the template section.
For the issue of the regular expression, define your regex as '^[/].*'.

How to pass dynamic props with Vue

I need to pass props using Vue, I thought of JSON with object that includes name and value. I need to pass data to a different component but it changes as in each event the names and values change.
So for example I might have name: 'a' value: 'b', name: 'f' value: 'k' and in anorher event name: 'c' value: 'd'
my code that works but it work because i return hard coded data
data() {
return {
params: {
name:'bill',
value:'jones'
},
in child
#Component({
props:
{
urls: {
type: Object,
default: () => { return {name:'', value: ''} }
},
}
function with object params that i need to get the data from
getParams(url) {
paramsData[key] = value;
//console.log(key,value);
}
return params;
console.log(params)
You can use computed property names
emitEvent(name, value) {
let objectToEmit = {
[name]: value,
};
this.$emit("event-name", objectToEmit);
}
Now name and value will be set according to whatever you pass in emitEvent function.
You can read more about computed property names on below link
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer
You can pretty much pass anything through and you can do it in many ways. Here are 4 examples:
Note: for all options we are assuming you have a parent component that is using the following syntax
<example-component :name="somename" :value="somevalue"></example-component>
Option1: props as a list of array of strings. The values can be anything in JS i.e. numbers, strings, objects, functions
<template>
<div>
<p v-text="example"></p>
</div>
</template>
<script>
export default {
name: "ExampleComponent",
prop: ['name','value']
}
</script>
Option 2: most common approach. Every prop to be a specific type of value. In these cases, you can list props as an object, where the propertiesā€™ names and values contain the prop names and types, respectively
<template>
<div>
<p v-text="example"></p>
</div>
</template>
<script>
export default {
name: "ExampleComponent",
props: {
name: {
type: String,
required: false,
default: 'something'
},
value: {
type: Number,
required: true
}
},
}
</script>
Option 3: you can validate or in this case pass in an Object and defaults returned from a factory function so you will always have some value. You can even return validation validator: function (value) {...}
<template>
<div>
<!-- some value from EventServiceClass-->
<p v-text="example.name"></p>
</div>
</template>
<script>
import EventServiceClass from "./EventServiceClass";
export default {
name: "ExampleComponent",
props: {
example: {
type: Object,
default: function () {
return {name:'a', value: 'b'}
}
},
},
}
</script>
Option 4: a little more advanced but in this example we are bind get and set to input properties on a form, which we would use to create factory form components
<template>
<div>
<input
id="name"
type="text"
v-model="name"
class="form--input light"/>
</div>
</template>
<script>
export default {
name: "ExampleComponent",
props: {
name: {
type: String,
default: ""
}
},
computed: {
name: {
get() {
return this.value;
},
set(value) {
this.$emit("input", value);
}
}
}
}
</script>

Passing object through routerlink Vuejs

I have a two component bus list and bus profile. Bus list contain several icon know as bus. when i click on bus icon it must pass object item from api requested. item object look like this:
item: { "id": 1, "bus_number": "xx-xx-xxx", "bus_color": "black" }
Here is my code:
In my Bus list.vue file
<template slot="bus" slot-scope="data">
<span class="bus" v-for="bus in buss">
<router-link :to="bus.url + data.item">
<a><i :key="data.item.id" ></i>
<a><i v-bind:class="bus.icon"></i></a>
</a>
</router-link>
</span>
</template>
In java script part
data () {
return {
buss: [
{url: '/xxxx/xxxxxx/xxxxxx/', icon: 'fa fa-bus fa-2x text-success'}
],
},
methods: {
getBusInfo: function () {
axiosWithOutAuth({
method: 'post',
url: 'xxx/xxxx/xxxx',
headers: {Authorization: 'JWT ' + localStorage.getItem('usertoken')}
}).then(response => {
console.log(response.data.results)
this.items = response.data.results
}).catch(function (error) {
console.log(error)
})
},
}
In my component file where i named as index.js
{
path: 'bus-profile/:item',
name: 'agency-bus-profile',
component: TravelAgencyBusProfile,
props: true
}
In my bus profile.vue file...
I am showing how i tried myself to access object
export default {
name: 'agency-bus-profile',
props: [item],
}
</script>
Please note that here syntax error does not matter to me. Here i am just want a know how can i directly pass object from one component to another using router link and props...
You can use query to pass additional data to the route:
<router-link :to="{
path: bus.url + data.item,
query: {
item: { "id": 1, "bus_number": "xx-xx-xxx", "bus_color": "black" }
}
}">
and then you can access them with this.$route.query.
It is easy, check this example
<router-link :to="{
path: '/path_example',
query: { // or if you want to use params: { ley1: value1, ke2: value2, ...}
item: { key: value_1, ke2: value2, ... }
}
}">
To access it from the other view use
const item = this.$router.params.item
const item = this.$router.query.item
Search "vue send object router link" and see documentation or watch a video from vueschool.

How to use filters in Vue js?

I need to use filter "capitalize" in vue js 2, but when I add filters according to documentation, it gave me error.
my code
<template>
<div class="test">
<h1>{{title}}</h1>
<ul>
<li v-for="item in items | capitalize" :key="item.first">{{item.first}},{{item.last}}</li>
</ul>
</div>
</template>
<script>
export default {
name: 'test',
vinput: '',
data () {
return {
title: 'Hello,
items: [
{
first: 'John0',
last: 'Doe'
},
{
first: 'Pavel',
last: 'Doe'
},
{
first: 'Shox',
last: 'Doe'
}
]
}
},
filters: {
capitalize: function (value) {
if (!value) return ''
value = value.toString()
return value.charAt(0).toUpperCase() + value.slice(1)
}
}
}
</script>
error
enter image description here
Any ideas, how to corrext that error?
Use filters in the template syntax.
<li v-for="item in items" :key="item.first">{{item.first | capitalize}},{{item.last | capitalize}}</li>
First, we have to define in main.js as shown below.
Vue.filter('UpperCase', function(val) {
return val.toUpperCase()
})
Then, we have to use where we need as shown below.
<div>{{ name | UpperCase }}</div>
Whatever function you want, just write function and call it.

Conditional <router-link> in Vue.js dependant on prop value?

Hopefully this is a rather simple question / answer, but I can't find much info in the docs.
Is there a way to enable or disable the anchor generated by <router-link> dependent on whether a prop is passed in or not?
<router-link class="Card__link" :to="{ name: 'Property', params: { id: id }}">
<h1 class="Card__title">{{ title }}</h1>
<p class="Card__description">{{ description }}</p>
</router-link>
If there's no id passed to this component, I'd like to disable any link being generated.
Is there a way to do this without doubling up the content into a v-if?
Thanks!
Assuming you want to disable anchor tag as in not clickable and look disabled the option is using CSS. isActive should return true by checking prop id.
<router-link class="Card__link" v-bind:class="{ disabled: isActive }" :to="{ name: 'Property', params: { id: id }}">
<h1 class="Card__title">{{ title }}</h1>
<p class="Card__description">{{ description }}</p>
</router-link>
<style>
.disabled {
pointer-events:none;
opacity:0.6;
}
<style>
If you want to just disable the navigation , you can use a route guard.
beforeEnter: (to, from, next) => {
next(false);
}
If you need to use it often, consider this:
Create new component
<template>
<router-link
v-if="!disabled"
v-bind="$attrs"
>
<slot/>
</router-link>
<span
v-else
v-bind="$attrs"
>
<slot/>
</span>
</template>
<script>
export default {
name: 'optional-router-link',
props: {
params: Object,
disabled: {
type: Boolean,
default: false,
},
},
};
</script>
Optional, register globally:
Vue.component('optional-router-link', OptionalRouterLink);
Use it as follows:
<optional-router-link
:disabled="isDisabled"
:to="whatever"
>
My link
</optional-router-link>
The problem is that router-link renders as an html anchor tag, and anchor tags do not support the disabled attribute. However you can add tag="button" to router-link:
<router-link :to="myLink" tag="button" :disabled="isDisabled" >
Vue will then render your link as a button, which naturally supports the disabled attribute. Problem solved! The downside is that you have to provide additional styling to make it look like a link. However this is the best way to achieve this functionality and does not rely on any pointer-events hack.
I sometimes do stuff like this:
<component
:is="hasSubLinks ? 'button' : 'router-link'"
:to="hasSubLinks ? undefined : href"
:some-prop="computedValue"
#click="hasSubLinks ? handleClick() : navigate"
>
<!-- arbitrary markup -->
</component>
...
computed: {
computedValue() {
if (this.hasSubLinks) return 'something';
if (this.day === 'Friday') return 'tgif';
return 'its-fine';
},
},
But I basically always wrap router-link, so you can gain control over disabled state, or pre-examine any state or props before rendering the link, with something like this:
<template>
<router-link
v-slot="{ href, route, navigate, isActive, isExactActive }"
:to="to"
>
<a
:class="['nav-link-white', {
'nav-link-white-active': isActive,
'opacity-50': isDisabled,
}]"
:href="isDisabled ? undefined : href"
#click="handler => handleClick(handler, navigate)"
>
<slot></slot>
</a>
</router-link>
</template>
<script>
export default {
name: 'top-nav-link',
props: {
isDisabled: {
type: Boolean,
required: false,
default: () => false,
},
to: {
type: Object,
required: true,
},
},
data() {
return {};
},
computed: {},
methods: {
handleClick(handler, navigate) {
if (this.isDisabled) return undefined;
return navigate(handler);
},
},
};
</script>
In my app right now, I'm noticing that some combinations of #click="handler => handleClick(handler, navigate)" suffer significantly in performance.
For example this changes routes very slow:
#click="isDisabled ? undefined : handler => navigate(handler)"
But the pattern in my full example code above works and has no performance issue.
In general, ternary operator in #click can be very dicey, so if you get issues, don't give up right away, try many different ways to bifurcate on predicates or switch over <component :is="" based on state. navigate itself is an ornery one because it requires the implicit first parameter to work.
I haven't tried, but you should be able to use something like Function.prototype.call(), Function.prototype.apply(), or Function.prototype.bind().
For example, you might be able to do:
#click="handler => setupNavigationTarget(handler, navigate)"
...
setupNavigationTarget(handler, cb) {
if (this.isDisabled) return undefined;
return this.$root.$emit('some-event', cb.bind(this, handler));
},
...
// another component
mounted() {
this.$root.$on('some-event', (navigate) => {
if (['Saturday', 'Sunday'].includes(currentDayOfTheWeek)) {
// halt the navigation event
return undefined;
}
// otherwise continue (and notice how downstream logic
// no longer has to care about the bound handler object)
return navigate();
});
},
You could also use the following:
<router-link class="Card__link" :to="id ? { name: 'Property', params: { id: id }} : {}">
<h1 class="Card__title">{{ title }}</h1>
<p class="Card__description">{{ description }}</p>
</router-link>
If id is undefined the router won't redirect the page to the link.
I've tried different solutions but only one worked for me, maybe because I'm running if from Nuxt? Although theoretically nuxt-link should work exactly the same as router-link.
Anyway, here is the solution:
<template>
<router-link
v-slot="{ navigate }"
custom
:to="to"
>
<button
role="link"
#click="onNavigation(navigate, $event)"
>
<slot></slot>
</button>
</router-link>
</template>
<script>
export default {
name: 'componentName',
props: {
to: {
type: String,
required: true,
},
},
methods: {
onNavigation(navigate, event) {
if (this.to === '#other-action') {
// do something
} else {
navigate(event);
}
return false;
},
};
</script>