set target= '_blank' in router-link of vuejs 2.5 - vuejs2

Using vuejs 2.5 if there is a way in router-link to set
target= '_blank'
?
I tried this way:
<router-link :to="{name: 'UserProfileView', params: {id: participantUser.user_id}, target: '_blank' }" >
but failed...
Thanks!

You will add target='_blank' like on <a> tag
Hope is clear

You must to use method. Method looks something like this:
methods: {
redirectToUserView(user) {
const route = this.$router.resolve({
name: 'UserProfileView',
params: {id: participantUser.user_id},
});
window.open(route.href, '_blank');
},
}

Below code is to open a new tab with parameter.
With router link=
<router-link
:to="{ name: 'task_section',query: {reportId: item.task,}}"
target="_blank"> Link Text
</router-link>
Now access to the sented data
this.$route.query.reportId

Perfectly worked for my code "target='_blank'" with external redirect.
<b-dropdown-item
:key="props.row.banner_id"
:to="{name:'banners-preview',
params: { id: props.row.banner_id } }"
target='_blank'
>
<feather-icon
icon="ExternalLinkIcon"
class="mr-50"
/>
<span>Preview Link</span>
</b-dropdown-item>

Related

Nuxt Menu links from API...How can i detect if its a Nuxt link :to or :href?

Im building my main menu from an API :
<b-navbar-nav>
<div v-for="result in resultsmenu" :key="result.id">
<span class="hoverlink">
<nuxt-link :to="result.slug">{{result.title}}</nuxt-link>
</span>
</div>
</b-navbar-nav>
Everythings works well but one problem is in the menu from the API ..One link is external with an "href" like : https://ww.instagram.com so nuxt-link process it like a internal route i end up with :
http://localhost:3000/https://ww.instagram.com
I was wondering if there is a way to tell Nuxt that if a link is an "href" type: "link" to handle it like an external link instead of an nuxt-link to: ?
Thank you
One way to achieve this would be to use a computed property.
Assuming your resultsmenu data looks something like...
resultsmenu: [
{slug: 'http://www.website.com', title: 'link to website.com'},
{slug: '/test', title: 'link to a website.com'},
{slug: '/yay', title: 'link to b website.com'},
{slug: 'http://www.website.com', title: 'link to c website.com'}
]
You can do...
computed: {
menuLinks() {
let links = []
this.resultsmenu.forEach(link => {
let menuItem = {}
menuItem.isHttp = !!link.slug.includes('http');
menuItem.target = link.slug
menuItem.title = link.title
links.push(menuItem)
})
return links
}
}
Then in your template:
<div v-for="(result, index) in menuLinks" :key="index">
<span>
<nuxt-link v-if="!result.isHttp" :to="result.target">{{result.title}}</nuxt-link>
<a v-else :href="result.target">{{result.title}}</a>
</span>
</div>

vue-router what is the difference to from :to

When to use vue-router link as
<router-link to="/login">Login</router-link> it render to login view and <router-link :to="/login">Login</router-link> this one is the same.
What is the difference and why we use the colon and we must use it ?
The : is v-bind Shorthand syntax.
https://v2.vuejs.org/v2/guide/syntax.html#v-bind-Shorthand
If you want to use Javascript expressions then need to use :
let LoginUrl = '/login'
<router-link :to="loginUrl">Login</router-link>
// Another example
let student = {id: 521, name: 'Jhon Doe'}
<router-link :to="`students/${student.id}`"></router-link>
Without : You're just writing string inside to=""
Colon is shorthand for v-bind directive and you would use it to bind to computed property or method.
https://v2.vuejs.org/v2/guide/syntax.html#v-bind-Shorthand
Examples:
<!-- Static value -->
<router-link to="/login">Login</router-link>
<!-- Dynamic values-->
<router-link :to="`/user/${id}`">Login</router-link>
<router-link :to="getUserLink(id)">Login</router-link>
<router-link :to="currentUserLink">Login</router-link>
new Vue({
data() {
return {
id: 1
}
},
computed: {
currentUserLink() { return '/user/'+ this.id }
},
methods: {
getUserLink(id) {
return '/user/'+ id
}
}
});

How to exhange a full route? Router-link exchanges only the last part of the route

I am new to vue and vue router and am using Vue router in history mode. The app contains a menu which is dynamically loaded
<router-link
tag="li"
class="link"
v-for="item in menu"
v-bind:key="item.id"
:to="item.slug"
:exact="item.slug === '/' ? true : false">{{ item.content }}
</router-link>
It works well as long as I stay in the parent routes like http://localhost:8080/posts As soon as I navigate a level deeper, e.g. to a post with the id 8 http://localhost:8080/posts/8 with a routerlink inside the Template
<router-link
tag="h2"
class="link"
:to="{ name: 'post', params: { id: post.id }}">
{{ post.title.rendered }}
</router-link>
it works in one way, but doesnt go back to the parent route when I click the main navigation links. Instead just adds the link of the main menu to the end of the route, e.g. instead of http://localhost:8080/posts
http://localhost:8080/posts/posts
The router
const router = new Router({
mode: 'history',
base: '',
routes: [
{ path: '/', name: 'home', component: HomePage },
{ path: '/posts', name: 'posts', component: PostsPage },
{ path: '/posts/:id', name: 'post', component: SinglePost },
{ path: '/projects', name: 'projects', component: ProjectsPage },
{ path: '/projects/:id', name: 'project', component: ProjectPage },
{ path: '/:page', name: 'page', component: SinglePage },
{ path: "*", redirect: '/' },
],
// etc..
});
I guess I am making a common mistake, but I canĀ“t find a solution. Any help appreciated.
You can use absolute paths. Instead of
<router-link
tag="h2"
class="link"
:to="{ name: 'post', params: { id: post.id }}">
{{ post.title.rendered }}
</router-link>
use
<router-link
tag="h2"
class="link"
:to="{ name: '/post', params: { id: post.id }}">
{{ post.title.rendered }}
</router-link>
The change is /post vs post in router-link's :to attribute.
You could and probably should use nested routes and components for posts posts/:id, but this a little more work and you my not need it at the moment. More on nested routes here.

Conditional link behavior in VueJS

Couldn't find a proper name for the title, will be glad if someone figures out a better name.
I have a component which represents a product card. The whole component is wrapped in <router-link> which leads to product page.
However I have another case, when I do not need the component to lead to a product page, but instead I need to do some other action.
The only solution I found is to pass a callback function as a prop, and based on this, do something like:
<router-link v-if="!onClickCallback">
... here goes the whole component template ...
</router-link>
<div v-if="onClickCallback" #click="onClickCallback">
... here again goes the whole component template ...
</div>
How can I do this without copy-pasting the whole component? I tried to do this (real code sample):
<router-link class="clothing-item-card-preview"
:class="classes"
:style="previewStyle"
:to="{ name: 'clothingItem', params: { id: this.clothingItem.id }}"
v-on="{ click: onClick ? onClick : null }">
However I got this: Invalid handler for event "click": got null
Plus not sure if it's possible to pass prevent modificator for click and this just looks weird, there should be a better architectural solution
Commenting on the error, you could use an empty function instead of null, in the real code snippet
<router-link class="clothing-item-card-preview"
:class="classes"
:style="previewStyle"
:to="{ name: 'clothingItem', params: { id: this.clothingItem.id }}"
v-on="{ click: onClick ? onClick : null }">
This should works (replace a for "router-link" then insert right properties)
Further infos :
https://fr.vuejs.org/v2/guide/components-dynamic-async.html
v-bind is simply an Object where each keys is a props for your component, so here, I programmatically defined an object of properties depending on the wrapper (router link or a simple div). However we cannot do this for events (of course we could create our own event listener but it's a little bit tricky) so I simply but an handle method.
new Vue({
el: "#app",
data: {
products : [{onClickCallback : () => { alert("callback"); return true;}}, {}, {}]
},
methods : {
handleClick(product, event) {
if (!product.onClickCallback) return false
product.onClickCallback()
return true
},
getMyComponentName(product) {
if (product.onClickCallback) return "div"
return "a"
},
getMyComponentProperties(product) {
if (product.onClickCallback) return {is : "div"}
return {
is : "a",
href: "!#"
}
}
}
})
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
<component
v-for="(product, index) in products"
:key="index"
v-bind="getMyComponentProperties(product)"
#click="handleClick(product, $event)"
>
<div class="product-card">
<div class="product-card-content">
<span v-show="product.onClickCallback">I'm a callback</span>
<span v-show="!product.onClickCallback">I'm a router link</span>
</div>
</div>
</component>
</div>
Do you have to use a <router-link>? If it can safely be a <div>, you could use something like
<div #click="handleClick" ...>
<!-- component template -->
</div>
and
methods: {
handleClick (event) {
if (this.onClickCallback) {
this.onClickCallback(event)
} else {
this.$router.push({ name: 'clothingItem', ... })
}
}
}
See https://router.vuejs.org/guide/essentials/navigation.html

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>