<router-link> Vue Router #click event - vue.js

I tried using a click event on a <router-link>. It works, but it is reloading the page everytime the link is clicked. I would like to avoid it but I can't figure out how.
I am aware that <router-link> does not accept a simple #click event. I saw on some forums that #click.I native would work, but as we know, that is deprecated.
So I would like to know if there is any solution other than wrapping the router link in a div and putting the listener on that div.
The reason why I want to do this is that I want to bind a class dinamicaly when the link is clicked. I have created a dropdown menu which is triggered onClick. But then when I follow a link inside that dropdown menu, the menu remains open. Therefore, I would like to have an additional #click event to dinamically bind a class (display: none) to the dropdown menu. The thing is that the items inside the dropdown are iterated which send parameters to a Vuex Mutation and therefore i can’t use regular tags and wrapping the router-links with a span or div is also not giving me the desired effect.
Thank you !
Regards,
T.

I have managed to solve the problem using a div wrapper and changing my css (that was preventing the code to work properly)
<div class="dropdown">
<a class="dropbtn" #click="dropClick"><i class="ri ico ri-draft-line"></i> Docs <i class="ri ico ri-arrow-drop-down-line ri-1x"></i></a>
<div class="dropdown-content" :class="{ 'dropdown-content-display': clicked }">
<div class="wrapper" v-for="route in $store.state.menuItems" :key="route.name" #click="dropClick">
<router-link :to="{ name: 'docs', params: { title: route.name } }"> <i :class="'ico ri ' + route.icon"></i> {{ route.name }}
</router-link>
</div>
</div>
</div>

If a understand your question, there is a "active-class" property on vue-router(router-link). You can set your classes dynamically by based on an active route.

Related

How to disable modal-ok slot of b-modal in vue bootstrap?

I have used modal-ok slot available in b-modal slots to render the OK button of b-modal. I want to conditionally disable the OK button. I have tried 2 methods with no luck. Any suggestion is welcome on how to disable the OK button rendered using the slot.
Disabled prop
<div
slot="modal-ok"
:disabled="true"
#click.stop="uploadFile(item.id)"
>
Upload
</div>
ok-disabled prop of b-modal
<div
slot="modal-ok"
:ok-disabled="true"
#click.stop="uploadFile(item.id)"
>
Upload
</div>
Use the ok-disabled prop on <b-modal>, to conditionally enable/disable the ok button.
<b-modal :ok-disabled="true">
<!-- Content -->
</b-modal>
For more information check out this section of the documentation.
Just add hide-footer if you want to get rid of the buttons
<b-modal hide-footer>
<!-- Content -->
</b-modal>
model-ok scope can't modify button itself, it just change button content
You need to use modal-footer scope instead and declare buttons manually there.

Vue draggable element with a click event on it?

I am making a Tinder clone type app in Vue. I am using the Vue2InteractDraggable component. This component works great for the use case. But I want to have a click event on the draggable portion, which does not fire (because it interprets the click as a start of a drag, as opposed to a click event).
I would like for it to use a click event if it's clicked and let go, but want it to use the current drag functionality if it's held for more than a certain amount of time. I can't figure out a way to do this, so any advice would be greatly appreciated. Here is an example of the Vue Component that I'm using. The #click on the detail section does not fire.
<Vue2InteractDraggable
v-if="cardVisible"
:interact-out-of-sight-x-coordinate="500"
:interact-max-rotation="15"
:interact-x-threshold="200"
:interact-y-threshold="9999"
#draggedRight="right()"
#draggedLeft="left()">
<div class="flex flex--center">
<img class="profilePicture" style="z-index: 4" :src="getImageSrc(current.image)"/>
</div>
<div class="rounded-borders card card--one">
<div class="userName">{{ Object.keys(this.users)[this.index] }}</div>
<div class="userAge">Age: {{current.age}}</div>
<div class="userDetailExpand" #click="expandDetails()">
<span>User Details</span>
<img class="carrot" src="../assets/svg/carrot_expand.svg"/>
</div>
</div>
</Vue2InteractDraggable>
Please let me know if you can think of any ideas. I've been hung up on this for a while and cannot find an answer.
Thank you for your help.
Try to add:
#touchstart="expandDetails()"
near:
#click="expandDetails()"

Pass a button with click handler via slot to recursive child component

I've got a page template with the following code part:
<nested-draggable v-bind:list="list" v-bind:selected="selected" v-bind:group="dragGroup">
<slot>
<v-icon v-on:click="$root.$emit('click', el)" small v-if="allowcreate" style="float: right">mdi-plus</v-icon>
</slot>
</nested-draggable>
the sub component ("nested-draggable.vue") for the recursion looks like this:
<template>
<ul class="tree">
<draggable
class="dragArea"
tag="li"
v-for="el in list"
v-bind:elementdata="el"
v-bind:key="el._id"
v-bind:list="list_empty"
v-bind:selected="selected"
v-bind:group="group"
v-on:add="add"
>
<span v-bind:class="{'selected' : el._id === selected._id}" v-on:click="elemClicked(el)">{{ el.title }}</span>
<slot></slot>
<!-- render children of the current iterated element -->
<nested-draggable
v-bind:list="el.children" v-bind:selected="selected" v-bind:group="group">
<!--<slot></slot>-->
</nested-draggable>
</draggable>
</ul>
</template>
so I'd like to have the click event from the button within the passed slot emited with the current iteration's var "el" when the "plus" button is clicked, but within the slot the "el" var that is used within the iteration at the nested-draggable component can not be accessed. Vue tells that there is no "el" reference when trying to emit. (Throwing this error: https://pastebin.com/8bNwMcDr)
So how can I access the recursive data within the passed slot? How do I have to define my slot when passing it?
The only solution I found is putting the button/event-link directly into the nested-draggable component (not as slot) but I think to be clean and write a nice separated component, this would not belong into the nested draggable component, but in its parent.
You don't need to pass your event from the template because you can get in your method anyways. This should help you out.

Vuejs active router link does not work, tried multipled ways

I cannot make the active button (router-link tag) to light up.
Here is my code:
<div class="bottom-buttons">
<span v-for="button in buttons" class="button" :class="{ 'is-active': $route.path === button.path}">
<router-link :to="button.path">
<i :class="button.iclass"></i>
<p class="button-label">{{button.label}} </p>
</router-link>
</span>
</div>
When I print out $route.path it returns the right path, and button.path is the data I have in the data object, and it works. So the condition should be right. But the 'is-active' class is not activated. (This thread: VueJS exact-active-class)
If I hard-code the 'is-active' class, it works.
When I use a:hover, a:visited, a:link it works, but a:active does not work :D. I have tried a:router-link-active but it does not work. (This thread: How to VueJS router-link active style)
I have tried to add linkActiveClass: 'is-active' in the /router/index.js file as suggested. It does not work. (This thread: Bulma navbar and VueJS router active link)
Anybody knows why? Or have more suggestions? Thank you in advance!
It seems to be that your problem is in the class condition. Maybe try to use == instead of === in your :class?
I would have add a comment instead of an answear if i had enough reputation :)

Vue.js. Best practices with initialization-only data binding?

I have this component which is managed by Bootstrap, specifically one of those nav-tabs widgets where, as you click Bootstrap shows and hides.
Bootstrap keeps track of which item was clicked on using the .active class. And, in Vue, I was to initialize a certain nav as being active on page load. But, once that's done, I want Vue leave the .active class management entirely up to Bootstrap.
<template>
<li class="nav-item" v-if="toshow">
<a class="nav-link" v-bind:id="'nav_' + link"
:class="{ active: isActive }" :aria-expanded="isActive"
v-bind:href="'#'+link" data-toggle="tab" #click="onclick">
{{label_}}
<span v-if="badge" class="badge" :class="badge_level">{{badge}}</span>
<span v-if="dynamic_badge" class="badge" :class="badge_level" >{{badge_value}}</span>
</a>
</li>
</template>
At page load time, each component checks against Vuex and figures out if its id is in this.$store.state.active_tab - that's what sets .active.
,isActive: function(){
//active_tab is where I specify which tab should be active
//at first
var res = this.link === this.$store.state.active_tab;
return res;
},
v-once is not a good fit, because the only thing I want to disable is the computation of .active (the badge children need to be updated live).
The component works, kinda. I think mostly because this.$store.state.active_tab's value does not mutate so Vue doesn't re-render. But it seems brittle at best.
What are best practices for using Vue to only set the initial values of certain variables, and then relinquishing control, without using v-once?
I would just access the a.nav-link element and add the .active class to its classList directly.
You can add a ref attribute to the a.nav-lank element link so:
<a class="nav-link" ref="link" ...>
...
</a>
And then add the .active class in the mounted hook:
mounted() {
if (this.link === this.$store.state.active_tab) {
this.$refs.link.classList.add('active');
}
}