Vuejs active router link does not work, tried multipled ways - vue.js

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 :)

Related

Vue3 transition-group, enter active animation is not working while leave is working

I tried to animate addition and deletion of element in v-for loop.
I searched some similar quesitons here and mainly the answers were about
class name change in vue3 from vue2.
I'm sure my case is not related to class name.
My code is as below.
Component name: VueOnly
<transition-group tag='div' class='VueOnly' name='fade'>
<div class='graphs' v-for="boro in lotteriesByBorough" :key="boro['value']">
<div>{{boro[0]}}</div>
<div class="bargraph" :style="{width: xScale(boro[1]) + 'px'}"></div>
</div>
</transition-group>
<div style='display:none'>{{console}}</div>
</template>
*css
.fade-enter-active{
animation:fade-in 1s
}
.fade-leave-active{
animation:fade-in 1s reverse
}
#keyframes fade-in {
from{
opacity:0 ;
width:0 ;
background-color:blue ;
}
to{
opacity:1;
width:100%;
}
}
I strongly believe I am following the syntax of
why is this not working?
It works only when 'leave' event is triggered.
Temporary class is added when 'leave' events are running while no class is added when 'enter' events are running.
So I think there is a problem in enter process in general.
Does it have anything to do with addition logic?
My addition logic is as below.
App.vue
<div class="filters">
<el-checkbox-group v-model="filters">
<el-checkbox label="1"></el-checkbox>
<el-checkbox label="2"></el-checkbox>
<el-checkbox label="3"></el-checkbox>
<el-checkbox label="4"></el-checkbox>
</el-checkbox-group>
</div>
<div class="section" :style="{width:`${width}px`,height:`${height}px`}">
<vue-only
:lotteries="filteredLotteries"
:lottery-stats="lotteryStats"
:width="width"
>
</vue-only>
</div>
The entire code can be seen in the following link.
https://github.com/jotnajoa/studioquestion/tree/main/d3vue
Set the appear property on <transition-group>:
<transition-group tag="div" class="VueOnly" name="fade" appear>
demo
I stumbled upon the same problem. It seems that the class animation_name-enter-active is not applied to new items (regardless of using appear or not). But the class animation_name-enter-to will be applied normally, so I moved my animation css to this class and it worked. Probably more a workaround than a real solution.

How to properly create a popup component in Vue 3

As part of becoming a better Vue programmer, I am trying to implement a popup similar to Popper with a clean and Vueish architecture. Here is a simple schematic that I came up with:
So basically there is a target component, which is the reference for the popup's position. The popup can be positioned above, below, right and left of the target, therefore I will need to have access to the target element in my popup. Also, the target can be an arbitrary component. It can be a simple button or span, but also something much more complex.
Then there is the popup itself, which will be put into a modal at the end of the body, It contains the actual content. The content again can be an arbitrary component.
I have a working implementation of the popup, but the basic structure seems to be far from perfect. I am using two slots, one for the target element and one for the content.
Here is what I have come up with so far for the template:
<template>
<div ref="targetContainer">
<slot name="target"></slot>
</div>
<teleport to="body">
<div v-show="show" class="modal" ref="modal">
<div ref="popover" class="popover" :style="{top: popoverTop + 'px', left: popoverLeft + 'px'}">
<slot name="content"></slot>
</div>
</div>
</teleport>
</template>
There are several issues with this that I am not really happy with.
Using the popup is not very simple
When using this popup in another component, two <template> tags are rquired. This is ungly and not very intuitive. A very simple use case looks like this:
<modal :show="showPopup" #close="showPopup=false">
<template v-slot:target>
<button #click="showPopup=true"></button>
</template>
<template v-slot:content>
<div>Hello World!</div>
</template>
</modal>
The target is wrapped in another <div>
This is done to get access to the target element, that I need for the layout. In mounted() I am referencing the target element like this:
let targetElement = this.$refs.targetContainer.children[0];
Is this really the best way to do this? I would like to get rid of the wrapping <div> element, which just asks for unintended side effects.
The best solution would be to get rid of one slot and somehow reference the target element in another way because I only need its layout information, it does not have to be rendered inside the popover component.
Can someone point me in the right direction?
Here is my solution, which was inspired by a comment on my question and which I think is worth sharing.
Instead of putting the target element into a slot, I am now passing its ref as a prop, which makes things much cleaner.
The popover component's template now looks like this.
<template>
<teleport to="body">
<div v-show="show" class="modal" ref="modal">
<div ref="popover" class="popover" :style="{top: popoverTop + 'px', left: popoverLeft + 'px'}">
<slot ref="content"></slot>
</div>
</div>
</teleport>
</template>
I has a targetRefprop, so the component can be simply used like this:
<div ref="myTargetElement" #click="isPopupVisible=true">
</div>
<modal :show="isPopupVisible" #close="isPopupVisible=false" targetRef="myTargetElement">
<!-- popup content goes here -->
</modal>
And after mounting I can access the target element like this:
let targetElement = this.$parent.$refs[this.targetRef];
I like this solution a lot. However, ideas, advice or words of caution are still highly welcome.

<router-link> Vue Router #click event

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.

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()"

Child component using parent component data to re-direct

I currently have a website/app that displays "FeatureCard" (components) onto a "Grid" component.
The feature cards have all the basic props to pass to the parent (Grid) component, so that data can be grabbed and a v-for used to create as many "featureCards" as possible.
That is all fine and working.
The issue comes when I want a title of a Feature card to link to its on slug-route.
Here is a snippet of my "FeatureCard" component -
<div class="card-content">
<div class="row-1">
<!-- <h4 class="bold">{{ resourceTitle }}</h4> -->
<router-link :to="{ name: 'FigmaFind', params: {resource_slug: this.slug} }"><h4 class="bold">{{ resourceTitle }}</h4></router-link>
<button class="price"><h6 class="bold">{{ resourcePrice }}</h6></button>
</div>
<div class="row-2">
<a :href=creatorProfile target="_blank" >
<img :src="creatorImage">
</a>
<a :href=creatorProfile target="_blank" >
<p>By <strong>{{ creatorsName }}</strong></p>
</a>
</div>
<div class="row-3">
<a :href="downloadLink" class="btn main" target="_blank" >
<p class="light semibold" for="info" >Download Resource</p>
</a>
<a :href="resourceOriginalLink" class="btn icon" target="_blank">
<p class="material-icons light md-18">info</p>
</a>
</div>
</div>
As you can see, in "row-1" I have tried including a router-link, but obviously it doesn't work as it has not yet recieved the data for "this.slug" but essentially, that is where I want a user to click this, and be redirected to "website.com/selected-item-1"
My issue is, I do not pull the "slug" data in, until it is rendered onto the Grid component. So, until then I am not sure how to reference it for later use, I referenced the titles as "resource title" or links as ":href="resourceOriginalLink"" but no idea how to do it for a router item. I could just use ":href="resourceOriginalLink"" but I don't know how I would pass the route-info through...
any ideas?
UPDATE
So, I figured it out. It may be the wrong way to do it, or there may be an easier way. But here is what I have done.
I passed the data "slug" as a prop to my child component (featureCard).
I then set slug: this.resourceSlug in my data.
Then within my title section I simply set <router-link :to="{ name: 'FigmaFind', params: { resource_slug: this.slug }}"><h4 class="bold">{{ resourceTitle }}</h4></router-link>
And, it seems to be working!!
Obviously, if there is a better way please, someone let me know.
UPDATE
So, I figured it out. It may be the wrong way to do it, or there may be an easier way. But here is what I have done.
I passed the data "slug" as a prop to my child component (featureCard). I then set slug: this.resourceSlug in my data. Then within my title section I simply set {{ resourceTitle }}
And, it seems to be working!!
Obviously, if there is a better way please, someone let me know.