Nuxt : #click does not work with Nuxt-link - vue.js

I am expecting to include on my web application an effect that underlines the section where we are in the list of sections.
I am working with Nuxt.
I don't know why the following code does not change the value of the boolean isActive.
<nuxt-link
:to="`${path}/${filterItem.filter}`"
:style='{"text-decoration": (isActive ? "underline" : "none")}'
#click="selectSeason(filterItem.filter) toggleUnderline()" >
methods: {
selectSeason(filter) {
this.$router.push(`${this.path}/${filter}`)
},
toggleUnderline() {
this.isActive = !this.isActive
}
},

You could probably achieve this with something like this
<template>
<nuxt-link to="/about" :custom="true">
<a #click="test">go to about page</a>
</nuxt-link>
</template>
<script>
export default {
methods: {
test() {
console.log('called test method')
},
},
}
</script>
As shown here: https://github.com/vuejs/router/issues/846#issuecomment-808150258
Even thought, this is probably not the best approach overall and seems quite too hacky for a simple use case.
Use a button tag if you want an action, otherwise put conditional logic on your route but don't mix a client side navigation and some kind of click events.

In Nuxt3 <NuxtLink> will get a class="router-link-active router-link-exact-active" if it's active, so you can use those to underline active link.

Same as router-link, you need to use v-on:click.native
<nuxt-link
:to="`${path}/${filterItem.filter}`"
:style='{"text-decoration": (isActive ? "underline" : "none")}'
#click.native="selectSeason(filterItem.filter) toggleUnderline()"
>
</nuxt-link>
How do we v-on:click nuxt-link?

Nuxt3:
<script lang="ts" setup>
const anyFunction = () => {
console.log('easy')
}
</script>
<template>
<NuxtLink
:to="'/'"
#click.prevent="anyFunction()"
>easy</NuxtLink>
</template>

Related

vue 2 [GSI_LOGGER]: The value of 'callback' is not a function. Configuration ignored

I'm trying to put a google sign in button inside my Vue2 project, so I tried to follow the instructions here https://developers.google.com/identity/gsi/web/guides/display-button#html
So I put this code below into my Hello.vue component
<template>
<section>
<div id="g_id_onload"
data-client_id="YOUR_GOOGLE_CLIENT_ID"
data-callback=myCallbackFunction
data-auto_prompt="false">
</div>
<div class="g_id_signin"
data-type="standard"
data-size="large"
data-theme="outline"
data-text="sign_in_with"
data-shape="rectangular"
data-logo_alignment="left">
</div>
</section>
</template>
<script>
export default {
methods: {
myCallbackFunction(){
}
}
}
</script>
and when I reloaded my page/component, it will display the error [GSI_LOGGER]: The value of 'callback' is not a function. Configuration ignored.
I think the problem is data-callback couldn't find or recognize myCallbackFunction which I already declared under methods. I've also tried to put myCallbackFunction under computed instead, but it still return the same error. So is there any way I can make this work?
Ok, I think I got it—but I switched from using the HTML documentation to the JavaScript documentation, since VueJS works better with this.
Still, I don't know if mounted is the best option, but it's at least working as intended.
Just use the callback function created at methods, and that's it.
mounted: function () {
google.accounts.id.initialize({
client_id:
'xxxxxxx.apps.googleusercontent.com',
callback: this.handleCredentialResponse,
})
google.accounts.id.prompt()}
working for me in Vue 2
<template>
<div>
<div id="signin_button"></div>
</div>
</template>
<script>
export default {
components: {
},
methods: {
handleCredentialResponse(response) {
console.log(response);
}
},
mounted: function () {
let googleScript = document.createElement('script');
googleScript.src = 'https://accounts.google.com/gsi/client';
document.head.appendChild(googleScript);
window.addEventListener('load', () => {
console.log(window.google);
window.google.accounts.id.initialize({
client_id: "xxxxxxx.apps.googleusercontent.com",
callback: this.handleCredentialResponse
});
window.google.accounts.id.renderButton(
document.getElementById("signin_button"),
{ theme: "outline", size: "large" } // customization attributes
);
})
}
}
</script>
use globalThis.yourcallbackfunction

Disable nuxt link based on boolean

I can't seem to find a good way to disable a nuxt-link based on a data variable. Could anyone suggest something? I've tried looking at doucmentation but I can't come up with anything.
Say I have a boolean called disable I want to do something like this
<nuxt-link :disabled="disable"></nuxt-link>
I basically just don't want the link to be clickable if the boolean is set to false
<nuxt-link> is essentially <router-link> of Vue Router.
You can disable it using the event prop.
Assuming your one of your data or computed property is disabled boolean:
<nuxt-link :event="disabled ? '' : 'click'"></nuxt-link>
Working example:
const Foo = { template: '<div>foo</div>' }
const Bar = { template: '<div>bar</div>' }
const Baz = { template: '<div>baz</div>' }
const routes = [
{ path: '/foo', component: Foo },
{ path: '/bar', component: Bar },
{ path: '/baz', component: Baz }
]
const router = new VueRouter({
routes
})
const app = new Vue({
router,
data(){
return {
disabled: true
}
}
}).$mount('#app')
<script src="https://unpkg.com/vue#2.7.13/dist/vue.min.js"></script>
<script src="https://unpkg.com/vue-router#3.6.5/dist/vue-router.min.js"></script>
<div id="app">
<h1>Hello App!</h1>
<div>
<!-- Assume they are <nuxt-link> because they are the same -->
<router-link
:event="disabled ? '' : 'click'"
to="/foo"
>
Go to Foo ({{ disabled ? 'Disabled' : 'Enabled' }})
</router-link>
<router-link to="/bar">Go to Bar</router-link>
<router-link to="/baz">Go to Baz</router-link>
</div><br />
<button #click="disabled = !disabled">Toggle Foo availability</button><br /><br />
<router-view></router-view>
</div>
I found that the most simple way was to just create a class for the disabled links. I'm still not sure if this is the best way to do it but it works for me and does exactly what I want.
<nuxt-link to="/search" :class="{ disabled: disabled }"> Search </nuxt-link>
my css
.disabled {
color: lightgrey
pointer-events: none
}
Another way to do this, which I'd like the most. Is to change the tag to the button and use the native :disabled state.
<nuxt-link tag="button" :disabled="disabled" to="/some/location">Some location</nuxt-link>
Then just turn the button into the link with the help of styles.
In Nuxt3 this works for me: :to="canNavigate ? link : null"
In Vue Router 4, router-link do not support tag and event props anymore. Here you can have more information.
I'll copy the example from the link above here:
replace
<router-link to="/about" tag="span" event="dblclick">About Us</router-link>
with
<router-link to="/about" custom v-slot="{ navigate }">
<span #click="navigate" #keypress.enter="navigate" role="link">About Us</span>
</router-link>
And I'll give a real example of usage. This piece of code I'm using in a real project, using nuxt and tailwind.
<nuxt-link
v-slot="{ navigate }"
class="flex-grow font-ember"
:to="`lesson/${l.lesson_id}`"
append
custom
>
<button
class="flex items-center"
:class="{
'text-gray-400 cursor-not-allowed': !l.released,
'text-gray-900': l.released,
}"
:disabled="!l.released"
#click="navigate"
>
...
</button>
</nuxt-link>
Just add the event prop if you simply want to disable a nuxt-link
<nuxt-link event="">Go to Foo</nuxt-link>
For this case anyway you can click on it. It displaying disabled but still clickable.
You need to use attribute tag in you nuxt-link
Example here <nuxt-link tag="button" :disabled="disable"></nuxt-link>
None of these seemed to work for me, so I set the :to on the nuxt-link to a computed method. The to attribute on nuxt link will redirect nowhere when empty. For example:
<script>
export default{
computed: {
redirectRequest(){
return this.isMobile ? "" : "/Worklog";
}
}
}
</script>
<template>
<NuxtLink :to="redirectRequest"></NuxtLink>
</template>

Vue: render <script> tag inside a variable (data string)

I'm new to Vue.js
I want to render a script tag inside a variable (data string).
I tried to us a v-html directive to do so, but it doesn't work Nothing is rendered
Any way I can achieve this?
I'd place a v-if directive on the script tag and put the content of it in a variable.
<script v-if="script">
{{script}}
</scrip>
If I understand you correctly, my answer is:
<template>
<div>
{{ strWithScriptTag }}
</div>
</template>
<script>
export default {
name: 'Example',
methods: {
htmlDecode(input) {
const e = document.createElement('div')
e.innerHTML = input
return e.childNodes[0].nodeValue
},
},
computed: {
strWithScriptTag() {
const scriptStr = '<script>https://some.domain.namet</script>'
return this.htmlDecode(scriptStr)
}
},
}
</script>
I think that by safety vue is escaping your <script> automatically and there is no way to avoid this.
Anyway, one thing you can do is eval(this.property) on created() lifecycle hook.
data: {
script: 'alert("this alert will be shown when the component is created")'
},
created() {
eval(this.script)
}
Use it with caution, as stated in vue js docs, this may open XSS attacks in your app

Vue js dynamically render router link path

I'm struggling to find a way to render the path of the router-link dynamically, for example with the test variable. I'm trying to bind :to but unsuccessfully. I don't know if I can use the ternary operator in the binding as shown below:
<template>
<div>
<router-link
:to="{ test ? '/success' : '/fail' }"
tag="button"
class="btn-next">
<span class="btn-text">BUTTON</span>
</router-link>
</div>
</template>
<script>
export default {
// ...
data: function() {
return {
test: false
};
}
}
</script>
Your solution is close (you don't need the curly brackets). It should look like this:
<router-link :to="test ? '/success' : '/fail'">
demo

How to stop <router-link> from sending the user to another page?

I have a logic like this: is the user is V2 use the user to the url in subHeaderRouter.router. If the user isn't launch this.openModal:
<router-link
v-for="subHeaderRouter in subHeaderRouters"
:to="subHeaderRouter.router"
#click="handleOpenModal()">
</router-link>
handleOpenModal () {
if (this.IsV2User) return
this.openModal('changeUserType', 'user.changeUserType')
}
The only thing I need to do now is to stop :to then she user is not V2. How to accomplish that?
You can prevent the default <router-link> behavior by specifying no default event to listen to and handling the click event manually with the .native modifier:
<router-link
v-for="subHeaderRouter in subHeaderRouters"
event=""
:to="subHeaderRouter.router"
#click.native.prevent="handleOpenModal(subHeaderRouter.router)"/>
handleOpenModal(route) {
if (this.IsV2User) {
this.$router.push(route)
} else {
this.openModal('changeUserType', 'user.changeUserType')
}
}
If the event="" seems weird to you, it also works with an empty attribute:
<router-link
v-for="subHeaderRouter in subHeaderRouters"
event
:to="subHeaderRouter.router"
#click.native.prevent="handleOpenModal(subHeaderRouter.router)"/>
Vue 3 Solution
In Vue3, the event has been removed from "<router-link>, you will need to use v-slot API instead.
<router-link :to="yourRoute" custom v-slot="{ href, navigate }">
<a v-if="yourBoolean" #click="handleEvent()">Run the function</a>
<a
v-else
:href="href"
#click="navigate">
Go to route in "to"
</a>
</router-link>
// Vue 3 Composition API
export default {
setup() {
const handleEvent = () => {
// Add your logic here
}
}
};
I had the same problem and used dynamic Vue Components as solution. You will also have to check the difference in styling for router and div tag.
<component
:is=" condition ? 'router-link' : 'div' "
#click="handleOpenModal"
:to="your_link">
</component>