Trigger a button inside a link with Vue - javascript

I have a set of images with some information like the author and now I'm adding a few buttons to allow users to like images.
Since the image has a link to the images screen I don't know how to trigger the button avoiding to fire the link.
Here is the code, I'm using Vuetify and Nuxt:
<nuxt-link
:to="
`/photo/${slotProps.item.id}/${
slotProps.item.slug
}`
"
>
<v-hover>
<v-img
slot-scope="{ hover }"
:src="slotProps.item.url"
>
<v-fade-transition mode="in-out">
<div
v-if="hover"
class="d-flex transition-fast-in-fast-out photo-overlay pa-2"
>
<div
class="d-flex pl-1 credits justify-space-between align-center w-100"
>
<div>
<nuxt-link
:to="
`/user/${slotProps.item.pId}`
"
class="secondary--text body-2 d-inline-block"
>
<v-avatar size="30">
<img
:src="slotProps.item.avatar"
:alt="`${slotProps.item.name}`"
/>
</v-avatar>
<span class="ml-2">
{{ slotProps.item.name }}
</span>
</nuxt-link>
</div>
<div>
<v-menu
v-model="addToGalleriesMenu"
:close-on-content-click="false"
:nudge-width="200"
>
<template v-slot:activator="{ on, attrs }">
<v-btn v-on="on" v-bind="attrs" icon color="secondary">
<v-icon small>
fal fa-hearth
</v-icon>
</v-btn>
</template>
<v-card outlined>
<v-card-title>Test</v-card-title>
</v-card>
</v-menu>
</div>
</div>
</div>
</v-fade-transition>
</v-img>
</v-hover>
</nuxt-link>
The code above generate an image, on mouse hover a layer appear at the bottom showing the name and a button to like the image.
Clicking on the user link it works fine, as expected. Clicking on the button that should fire an action is not working because the image link get clicked.
How can I work around it?

You can stop event propagation to the parent element very easily using Vue click modifiers:
<a href="example.com">
...
<v-btn #click.stop.prevent="test()">
...
You can achieve the same thing without using Vue modifiers:
<a href="example.com">
...
<v-btn #click="test($event)">
...
methods: {
test (event) {
event.preventDefault()
event.stopPropagation()
}
}

Related

Using v-carousel with a static image

I am trying to use Vuetify's v-carousel but with a static image and only utilize the carousel for transitioning texts. So I have the carousel and the same image is being used across each carousel item but the issue is to keep the "sliding" effect it also slides the image. This is not an issue if the image was just a base color but since it is an image it makes it look odd. I only want the text to move.
My Initial Code:
<template>
<v-carousel
cycle
height="400"
hide-delimiter-background
show-arrows-on-hover
>
<v-carousel-item
v-for="(slide, i) in slides"
:key="i"
:src="/path/to/img.png"
>
<v-row
class="fill-height"
align="center"
justify="center"
>
<div class="text-h2">
Slide {{ i + 1 }}
</div>
</v-row>
</v-carousel-item>
</v-carousel>
</template>
I have tried appending a v-img into the code so it look like:
<template>
<v-carousel
cycle
height="400"
hide-delimiter-background
show-arrows-on-hover
>
<v-carousel-item
v-for="(slide, i) in slides"
:key="i"
>
<v-img src="/path/to/img.png" />
<v-row
class="fill-height"
align="center"
justify="center"
>
<div class="text-h2">
Slide {{ i + 1 }}
</div>
</v-row>
</v-carousel-item>
</v-carousel>
</template>
I have also tried making the image a v-sheet and putting the text on top but it still gives off the sliding effect. Is this possible to do or should I be going down a different route?

Is there a way to make Vuetify v-carousel move to the next item on scroll?

I'm trying to build a front page using the v-carousel and would like to scroll to the next item instead of using arrows or delimiters, how would I achieve that?
Here is my code at the moment
<template>
<v-carousel vertical-delimiters
:vertical="true"
:cycle="true"
height="100%"
>
<v-carousel-item >
<v-sheet
color="black"
height="100%"
tile
>
<v-container
fill-height
fluid
>
<v-row
align="center"
justify="center"
dense
class ="ma-0"
>
<v-col
align="center"
justify="center"
>
<v-img src="imagepath"
max-height="350"
max-width="350"
class="ma-10"
>
</v-img>
<div class="text-h4 pa-7">
Some text
</div>
</v-col>
</v-row>
</v-container>
</v-sheet>
</v-carousel-item>
<v-carousel-item>
<v-sheet
color="black"
height="100%"
tile
>
<v-container
fill-height
fluid
>
<v-row
align="center"
justify="center"
dense
class ="ma-0"
>
<v-col
align="center"
justify="center"
>
<v-img src="Image Path"
max-height="350"
max-width="350"
class="ma-10"
>
</v-img>
<div class="text-h4 pa-7">
Some text
</div>
</v-col>
</v-row>
</v-container>
</v-sheet>
</v-carousel-item>
</v-carousel>
</template>
The carousel works just fine, but I can't find a way to send scroll event to the carousel as a an event to move to the next item.
I think you could wrap your carousel into Intersection observer so you could observe the scroll event and after that, you will be able to call the function which can handle the carousel.
e.g. you have to provide a v-model for the <v-carousel> then after tracking the scroll event you can increase or decrease the amount of that v-model.
Another way could be the use of scroll directive. The v-scroll directive allows you to provide callbacks when the window, specified target, or the element itself (with .self modifier) is scrolled.

How to avoid #click on only one child component

For example if I click on all the v-card I am redirecting to an other link BUT if I click on the title World of the Day and only on the title I don't want to do nothing. How to avoid to be redirected when clicking on title ?
template>
<v-card
class="mx-auto"
max-width="344"
#click="goToAnOtherLink"
>
<v-card-text>
<div>Word of the Day</div>
<p class="display-1 text--primary">
be•nev•o•lent
</p>
<p>adjective</p>
<div class="text--primary">
well meaning and kindly.<br>
"a benevolent smile"
</div>
</v-card-text>
<v-card-actions>
<v-btn
text
color="deep-purple accent-4"
>
Learn More
</v-btn>
</v-card-actions>
</v-card>
</template>
If it's only the title, use the stop event modifier. This is easier than having the logic in the method.
<v-app>
<v-card class="mx-auto" max-width="344" #click="goToAnOtherLink">
<v-card-text>
<div class="title" #click.stop>Word of the Day</div>
<p class="display-1 text--primary"> be•nev•o•lent </p>
<p>adjective</p>
<div class="text--primary"> well meaning and kindly.<br> "a benevolent smile" </div>
</v-card-text>
<v-card-actions>
<v-btn text color="deep-purple accent-4"> Learn More </v-btn>
</v-card-actions>
</v-card>
</v-app>
https://codeply.com/p/2ExpE6PF6F
Add a class to the title div as well, and check the classes of your event's target inside the function goToAnOtherLink. Then you can use stopPropagation() along with the custom code you have in that function.
new Vue({
el: "#app",
data() {},
methods: {
goToAnOtherLink(e) {
if (e.target.classList.contains("title") || e.target.classList.contains("display-1")) {
e.stopPropagation()
console.log("Cancelled Navigation!")
} else {
console.log("Navigated!")
}
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#1.5.14/dist/vuetify.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/vuetify#1.5.14/dist/vuetify.min.css" rel="stylesheet" />
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons" rel="stylesheet" />
<div id="app">
<v-app>
<v-card class="mx-auto" max-width="344" #click="goToAnOtherLink">
<v-card-text>
<div class="title">Word of the Day</div>
<p class="display-1 text--primary">
be•nev•o•lent
</p>
<p>adjective</p>
<div class="text--primary">
well meaning and kindly.<br> "a benevolent smile"
</div>
</v-card-text>
<v-card-actions>
<v-btn text color="deep-purple accent-4">
Learn More
</v-btn>
</v-card-actions>
</v-card>
</v-app>
</div>
You can wrap your v-card in a div and use absolute positioning to place the title; so that the title is in "front" of the v-card thus clicking on it does nothing.
Pseudo-code
<div>
<span>Word of the day</span> <!-- use absolute to position inside the div -->
<v-card></v-card>
</div>

Limit maximum page length in css

I have a Vue application running Vuetify but neither of these seem to be equipped to handle my desire to limit the maximum length of the page to be such that there is no scrolling. I hope that makes sense. My hope is to just pull up a screen with a bunch of routing to similarly formatted screens. Of course, the user could make the window smaller, in which case I would need scrolling. So how would I set that up when I want to have the page open to full screen with a maximum page length that will prevent the NEED for scrolling, but still allow scrolling if the need is there due to the user resizing the page to something a good bit smaller?
I spent hours looking around for details on this but didn't find anything that really seemed to be a direct solution. How can I set a max page length? Would CSS offer this? I saw a solution putting CSS in the <head>-tag but with a Vue application this head tag doesn't get used in the same way as typical HTML pages.
EDIT: because I don't think it's clear that because I'm working in vue/vuetify the solution might be different from the general case, I think it is best if I provide my App.vue and an example page.
--- App.vue ---
<template>
<v-app>
<app-toolbar></app-toolbar>
<router-view></router-view>
<app-footer></app-footer>
</v-app>
</template>
<script>
import AppToolbar from "./components/AppToolbar.vue";
import AppFooter from "./components/AppFooter.vue";
export default {
name: "App",
components: {
AppToolbar,
AppFooter
},
data: () => ({
//
})
};
</script>
<style scoped></style>
--- Homepage.vue ---
<template>
<div>
<v-app>
<v-responsive aspect-ratio="16/9">
<v-carousel cycle hide-delimiter-background show-arrows-on-hover>
<v-carousel-item
v-for="(item, i) in items"
:key="i"
:src="item.src"
reverse-transition="fade-transition"
transition="fade-transition"
></v-carousel-item>
</v-carousel>
</v-responsive>
</v-app>
</div>
</template>
<script>
export default {
data() {
return {
items: [
{
src: "https://cdn.vuetifyjs.com/images/carousel/squirrel.jpg"
},
{
src: "https://cdn.vuetifyjs.com/images/carousel/sky.jpg"
},
{
src: "https://cdn.vuetifyjs.com/images/carousel/bird.jpg"
},
{
src: "https://cdn.vuetifyjs.com/images/carousel/planet.jpg"
}
]
};
}
};
</script>
<style></style>
EDIT 2: Adding the app-toolbar & app-footer
--- Toolbar.vue ---
<template>
<div>
<v-toolbar dense color="#3F51B5" dark>
<v-app-bar-nav-icon
color="#76ff03"
#click.stop="drawer = !drawer"
></v-app-bar-nav-icon>
<v-btn to="/" color="#76ff03" text>Vuetification</v-btn>
<v-spacer></v-spacer>
<v-spacer></v-spacer>
<v-spacer></v-spacer>
<v-spacer></v-spacer>
<v-spacer></v-spacer>
<v-spacer></v-spacer>
<v-spacer></v-spacer>
<v-spacer></v-spacer>
<v-row align="center" justify="center">
<v-badge bordered color="error" icon="mdi-lock" overlap>
<v-btn class="white--text" color="error" depressed>
Lock Account
</v-btn>
</v-badge>
<div class="mx-3"></div>
<v-badge
bordered
bottom
color="deep-purple accent-4"
dot
offset-x="10"
offset-y="10"
>
<v-avatar size="40">
<v-img src="https://cdn.vuetifyjs.com/images/lists/2.jpg"></v-img>
</v-avatar>
</v-badge>
<div class="mx-3"></div>
<v-badge avatar bordered overlap>
<template v-slot:badge>
<v-avatar>
<v-img src="https://cdn.vuetifyjs.com/images/logos/v.png"></v-img>
</v-avatar>
</template>
<v-avatar size="40">
<v-img src="https://cdn.vuetifyjs.com/images/john.png"></v-img>
</v-avatar>
</v-badge>
</v-row>
<div class="hidden-sm-and-down">
<v-btn icon>
<v-icon color="#76ff03">mdi-magnify</v-icon>
</v-btn>
<v-btn icon>
<v-icon color="#76ff03">mdi-heart</v-icon>
</v-btn>
<v-btn icon>
<v-icon color="#76ff03">mdi-dots-vertical</v-icon>
</v-btn>
<v-btn color="#76ff03" text>About</v-btn>
<v-btn to="/contact" color="#76ff03" text>Contact</v-btn>
<v-btn to="/login" color="#76ff03" text>Login</v-btn>
</div>
</v-toolbar>
<v-navigation-drawer
v-model="drawer"
expand-on-hover
app
temporary
right
height="160px"
>
<v-list-item>
<v-list-item-avatar>
<v-img src="https://randomuser.me/api/portraits/men/78.jpg"></v-img>
</v-list-item-avatar>
<v-list-item-content>
<v-list-item-title>John Leider</v-list-item-title>
</v-list-item-content>
</v-list-item>
<v-divider></v-divider>
<v-list dense>
<v-list-item v-for="item in items" :key="item.title" link>
<v-list-item-icon>
<v-icon>{{ item.icon }}</v-icon>
</v-list-item-icon>
<v-list-item-content>
<v-list-item-title>{{ item.title }}</v-list-item-title>
</v-list-item-content>
</v-list-item>
</v-list>
</v-navigation-drawer>
</div>
</template>
<script>
export default {
data() {
return {
drawer: false,
items: [
{ title: "Home", icon: "mdi-ghost" },
{ title: "About", icon: "mdi-kabaddi" }
]
};
}
};
</script>
<style scoped>
.toolbar-item {
color: #76ff03;
}
</style>
--- Footer.vue ---
plate>
<v-app>
<v-footer dark padless fixed>
<v-card class="flex" text tile>
<v-card-title class="teal">
<strong class="subheading"
>Get connected with us on social networks!</strong
>
<v-spacer></v-spacer>
<v-btn v-for="icon in icons" :key="icon" class="mx-4" dark icon>
<v-icon color="#76ff03" size="24px">{{ icon }}</v-icon>
</v-btn>
</v-card-title>
<v-card-text class="text-center">
<v-layout>
<v-flex class="toolbar-item" v-for="(col, i) in rows" :key="i" xs3>
<span class="body-2" v-text="col.title.toUpperCase()" />
<div v-for="(child, i) in col.children" :key="i" v-text="child" />
</v-flex>
<v-flex class="toolbar-item" xd3 layout column>
<span class="body-2">CONTACT</span>
<div>
<v-icon color="#76ff03" size="18px" class="mr-3"
>fa-home</v-icon
>
New York, NY 10012, US
</div>
<div>
<v-icon color="#76ff03" size="18px" class="mr-3"
>fa-envelope</v-icon
>
info#example.com
</div>
<div>
<v-icon color="#76ff03" size="18px" class="mr-3"
>fa-phone</v-icon
>
+ 01 234 567 89
</div>
<div>
<v-icon color="#76ff03" size="18px" class="mr-3"
>fa-print</v-icon
>
+ 98 765 432 10
</div>
</v-flex>
</v-layout>
<strong> {{ new Date().getFullYear() }} — Vuetify </strong>
</v-card-text>
</v-card>
</v-footer>
</v-app>
</template>
<script>
export default {
data: () => ({
icons: [
"fab fa-facebook",
"fab fa-twitter",
"fab fa-google-plus",
"fab fa-linkedin",
"fab fa-instagram"
],
rows: [
{
title: "Company Name",
children: [
"Here you can use rows and columns here to organize your footer content. Lorem ipsum dolor sit amet, consectetur adipisicing elit"
]
},
{
title: "Produts",
children: [
"MDBootstrap",
"MDWordPress",
"BrandFlow",
"BootstrapAngular"
]
},
{
title: "Useful Links",
children: [
"Your account",
"Become an Affiliate",
"Shipping Rates",
"Helper"
]
}
]
})
};
</script>
<style scoped>
strong {
color: #76ff03;
}
.toolbar-item {
color: #76ff03;
}
</style
>
By default, if the HTML content is larger than the window, the browser will create scrollbars and if it's smaller than the window there won't be a scroll. However, I don't think this is what you're really asking for. I think you're trying to change the window size itself.
I'm going to start by saying its very bad practice to modify the size of the user's browser window. You should work to make your content fit instead.
That said, as Vue.js and Vuetify are built on Javascript, and you'll need to write some custom JS to resize the browser window. The default overflow on the <body> tag (yes those exist in a Vue app) will take care of the scrolling...
window.resizeTo(width, height);
Should be called after Vue has rendered the content to the screen so inside Vue's Mounted Lifecycle hook.
Now, I assume the height of the content changes so you would want to grab the height of the Vue app div.
var newHeight = document.getElementById('app').innerHeight()
You also want to get the screen size so you don't make the window larger than the screen. You can get that height from the screen object.
var screenHeight = window.screen.height
so
if(newHeight < screenHeight){
window.resizeTo('800px', newHeight);
} else {
window.resizeTo('800px', screenHeight);
}
Before you do this
You should know that most modern browsers BLOCK the window.resizeTo() function so again you should find a different solution to the problem.
You Can nest your content inside another div element.If max-height of your inner div is equal to the height of its container, scroll bar will never appear. if you want to see scroll bar use this.
.scrollDiv {
height:auto;
max-height:150%;
overflow:auto;
}

Show mutiple v-dialog boxes with different content in vue.js

Hii I am working on the Vue.js template and I stuck at a point where I need to show dynamic v-dialog using looping statement but now it shows all.
Dom:
<template v-for="item of faq">
<div :key="item.category">
<h4>{{ item.heading }}</h4>
<div v-for="subitems of item.content" :key="subitems.qus">
<v-dialog
v-model="dialog"
width="500"
>
<template v-slot:activator="{on}">
{{subitems.qus}}
</template>
<v-card>
<v-card-title
class="headline grey lighten-2"
primary-title
>
Privacy Policy
</v-card-title>
<v-card-text>
{{ subitems.ans }}
</v-card-text>
<v-divider></v-divider>
</v-card>
</v-dialog>
</div>
</div>
</template>
Script:
export default {
data: () => ({
faq,
dialog:false,
}),
}
I do not understand how I can do this. If I click on one button then it shows all.
There must a design a pattern for this one but a quick solution would be to create array of booleans for v-models of dialogs. something like below
export default {
data: () => ({
faq,
dialog: [] // Array instead of Boolean.
}),
}
and
<template v-for="item of faq">
<div :key="item.category">
<h4>{{ item.heading }}</h4>
<div v-for="(subitems, index) of item.content" :key="subitems.qus">
<v-dialog
v-model="dialog[index]"
width="500"
>
<template v-slot:activator="{on}">
{{subitems.qus}}
</template>
<v-card>
<v-card-title
class="headline grey lighten-2"
primary-title
>
Privacy Policy
</v-card-title>
<v-card-text>
{{ subitems.ans }}
</v-card-text>
<v-divider></v-divider>
</v-card>
</v-dialog>
</div>
</div>
</template>
Brother, you are doing a very small mistake, you should not keep your v-dialog component inside your loop, take this out from loop block and don't take dialog as empty array keep it false.

Categories

Resources