Use popup gallery with index - vue.js

Hi I am a beginner on learning Vue. I want to shorten my popup code with index. But I don't know how to make it clearly.
Can you tell me how to give my images some attributes to control the popup if it shows or not. Or Other methods to solve it.
Here is my code. Thank you.
<div class="image" v-for="(img, index) in images" :key="index">
<span #click="imgClick(index)">
<img class="initial_img" :src="require(`#/assets/picture/${img}.jpg`)" alt="">
</span>
</div>
<Popup :open="isOpen_1" #close="isOpen_1 = !isOpen_1">
<img :src="require('#/assets/picture/001.jpg')"/>
</Popup>
<Popup :open="isOpen_2" #close="isOpen_2 = !isOpen_2">
<img :src="require('#/assets/picture/002.jpg')"/>
</Popup>
</div>
</script>
import Popup from "../components/Popup.vue"
import {ref} from "vue"
export default {
components: {
Popup,
},
setup(){
const isOpen_1 = ref(false);
const isOpen_2 = ref(false);
return {isOpen_1, isOpen_2}
},
data() {
return{
images:['001','002'],
}
},
methods:{
closeAllisOpen(){
this.isOpen_1 = false;
this.isOpen_2 = false;
},
imgClick(index){
this.closeAllisOpen();
switch(index){
case 0: this.isOpen_1 = true; break
case 1: this.isOpen_2 = true; break
}
},
}
}
</script>

Maybe you can make your photos to object in script. Like the blow.
images:[{src:require("your path"),}]
Then control isOpen with methods to choose which one should be popup now.
<Popup :open="isOpen" #close="isOpen = !isOpen">
<template #img><img :src="images[imgIndex].src"/></template>
</Popup>
imgClick(index){
this.isOpen = true;
switch(index){
case 0: this.imgIndex = 0; break...
}
},

Related

How can I hide the other elements when one dropdown menu is click

I'm still new to Vue.js so far I'm liking it. Currently stuck on drop menus.
If one drop down menu is click is there a way to hide the other menus that are open?
<script setup>
import { ref } from 'vue';
const hideshow1= ref(false);
const hideshow2= ref(false);
const hideshow3= ref(false);
function show1() {
this.hideshow1= !this.hideshow1;
};
function show2() {
this.hideshow2= !this.hideshow2;
};
function show3() {
this.hideshow3= !this.hideshow3;
};
</script>
<template>
<button #click="show1()" type="button"> show</button>
<button #click="show2()" type="button"> show</button>
<button #click="show3()" type="button"> show</button>
<div :class="{'block':hideshow1, 'hidden': ! hideshow1}" class="sm:hidden ">show1</div>
<div :class="{'block':hideshow2, 'hidden': ! hideshow2}" class="sm:hidden ">show2</div>
<div :class="{'block':hideshow3, 'hidden': ! hideshow3}" class="sm:hidden ">show3</div>
</template>
Maybe I'm grossly over-simplifying your problem, but as I mentioned in comment, why not change your apps data state with the buttons, and then use a v-if to check state of your data, toggling visibility. The data probably should be an array of objects, perhaps something like this:
<template>
<h2>Show Hide Menus</h2>
<button v-for="item in hideShows" :key="item.text" #click="show(item)">
Button {{ item.text }}
</button>
<div v-for="item in hideShows" :key="item.text">
<span v-if="item.value">Show {{ item.text }}</span>
</div>
</template>
<script setup>
import { ref } from 'vue';
const hideShows = ref([
{
text: "1",
value: true
},
{
text: "2",
value: false
},
{
text: "3",
value: false
}
]);
function setAllFalse() {
hideShows.value.forEach(hideShow => {
hideShow.value = false;
})
}
function show(item) {
setAllFalse();
item.value = !item.value;
}
</script>

Popup on top of each other VUEJS3

I want to put several Buttons, each one opening a different Popup. A Popup would print data concerning its Button.
I have a Popup.vue component :
<template>
<div class="popup">
<div class="popup-inner">
<slot />
<Button class="popup-close" #click="TogglePopup()">
Close
</Button>
</div>
</div>
</template>
<script>
export default {
props: ['TogglePopup']
}
</script>
And in another .vue I call it like that :
<template>
<div v-for="infoItem in data" :key="infoItem.name"> // loop to create several buttons
<Button
icon="pi pi-eye"
#click="() => TogglePopup('buttonTriggerDetail')">
</Button>
<Popup
v-if="popupTriggers.buttonTriggerDetail"
:TogglePopup="() => TogglePopup('buttonTriggerDetail')"
>
{{ infoItem.control }}
</Popup>
</div>
</template>
<script>
import ...
export default {
computed: {
data() {
return this.$store.state.data;
},
},
mounted() {
this.$store.dispatch("getData");
},
setup() {
const popupTriggers = ref({
buttonTriggerDetail: false
});
const TogglePopup = (trigger) => {
popupTriggers.value[trigger] = !popupTriggers.value[trigger];
};
return {
Popup,
TogglePopup,
popupTriggers,
};
},
};
</script>
So it prints several Button but when I click on one, it don't open the Popup with the data of this Button, it always prints the data of the last Button. I think in reality it places all the pop up on top of each others.
How can I do to open only the good Popup with the good data ?
Thanks
The mistake is that you are rendering 3 popups when you need only one with certain props. Think of your popups as of tabs: let popup be rendered by clicking on certain button and pass in props you need, for example:
<template>
<div v-for="infoItem in data" :key="infoItem.name"> // loop to create several buttons
<Button
icon="pi pi-eye"
#click="clickHandler">
</Button>
</div>
<Popup
v-if="popupTriggered"
:TogglePopup="() => TogglePopup('buttonTriggerDetail')"
>
{{ data[currentActiveItem].control }}
</Popup>
</template>
<script>
import ...
export default {
data () {
currentActiveItem: 0,
popupTriggered: false
},
methods: {
clickHandler (index) {
this.popupTriggered = true
this.currentActiveItem = index
}
}
... // other component data
};
</script>
I wrote my example in Vue 2 style because I haven't worked with Composition API yet but I hope you got the idea.

Update properties of component in Vue.js

I've been searching for the answer 2nd day. But still couldn't find solution.
I have the modal window template. And the main page template from where I need to update modal window size by clicking on the button (span). Shortly it's like this for HTML:
<template id="modal">
<div>
<div :class="'modal-' + size">
...
</div>
</div>
</template>
<template id="list">
<div>
<span #click="onDetails">
Show Details
</span>
</div>
<modal size="md" #showdetails="showdetails();" ref="modal">
...
</modal>
</template>
And for JS:
Vue.component("modal", {
template: "#modal",
props: {
size: {
type: String,
default: ""
}
},
methods: {
onDetails() {
this.$emit("showdetails")
}
}
})
var List = Vue.extend({
template: "#list",
methods: {
showDetails() {
if(this.$refs.modal.size == "md") {
this.$refs.modal.size = "lg"
}
<additional code here>
}
}
})
When I'm accessing this.$refs.modal.size for read - it's OK. When I'm just changing it from showDetails - OK if only this action in the function. When I'm put something else instead of - size is not updating.
For example:
this.$refs.modal.size = "lg" - will work
this.$refs.modal.theme = "danger"; this.$refs.modal.size = "lg" - neither of them are updating
What am I doing wrong?
You need to assign the attribute value of Size by the javascript method setAttribute . Example : this.$refs.modal.setAttribute('size', 'lg')
There is a working demo below:
new Vue({
el: '#app',
methods: {
showdetails() {
console.log(this.$refs.modal.getAttribute('size'));
this.$refs.modal.setAttribute('size', 'lg')
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.15/vue.js"></script>
<div id='app'>
<button size="md" #click="showdetails" ref="modal">Click</button>
</div>

Binding method to an option in a component in vue.js

I'm pretty new to Vue and are using a litebox component which I want to customize a bit so the lightbox gallery starts on different images depending on which button is pressed. I have succeeded to solve this by using a click event which I'm binding to an option in the litebox component. Since I am new to Vue. I'm just wondering if this is a good way of solving something like this or if there is a better way?
<template>
<div id>
<button type="button" #click="show(); start1();">Show Litebox start 1</button>
<button type="button" #click="show(); start2();">Show Litebox start 2</button>
<vue-litebox v-if="showLitebox" :startAt="start" :items="images" #close="hide"></vue-litebox>
</div>
</template>
<script>
import VueLitebox from "vue-litebox";
export default {
components: { VueLitebox },
data() {
return {
images: [
"https://placekitten.com/400/400",
"https://placekitten.com/400/401",
{
title: "My image title",
src: "https://placekitten.com/400/402"
}
],
showLitebox: false,
start: 0
};
},
methods: {
show() {
this.showLitebox = true;
},
hide() {
this.showLitebox = false;
},
start1() {
this.start = 1
},
start2() {
this.start = 2
}
}
};
</script>
Here is the code on code sandbox:
https://codesandbox.io/s/9ok4y6lopo?fontsize=12
Templates should be as logic-free as possible, besides, there is no need to chain methods this way because you can always pass parameters to methods, like this:
// in your template
<button
type="button"
#click="show(1)"
>
Show Litebox start 1
</button>
// in methods section
show (start = 1) { // defaults to 1
this.show = true;
this.start = start;
}
By the way, it seems like v-show would be a better choice than v-if for vue-litebox component (see documentation).

Vue data property not reactive

Considering the code below, I can not make the active data property reactive. In this case I would like to show a div only on mouseover on an image.
<template>
<div>
<img #mouseover="showInfo" class="cursor-pointer w-full" :src="project.images[0].url" width="100%">
<div v-show="active" class="bg-red h-12">
Info about the image
</div>
</div>
</template>
<script>
export default {
props: ['project'],
data: function () {
return {
active: false
}
},
methods: {
showInfo: () => {
this.active = !this.active;
}
}
}
</script>
I have tried using v-if instead and printing active but to no effect. What am I doing wrong?
Don't use arrow functions to define methods, this will not work.
Just replace
showInfo: () => {
this.active = !this.active;
}
With:
showInfo() {
this.active = !this.active;
}
This can be simpler if you just change the value in HTML and you don't require a separate method for that.
#mouseover="active = !active"
It will look like this,
<div>
<img #mouseover="active = !active" class="cursor-pointer w-full" :src="project.images[0].url" width="100%">
<div v-show="active" class="bg-red h-12">
Info about the image
</div>
</div>
data() {
return {
active: false
}
},
Update your data like the one above.
Also I'd rename your function to toggleInfo as it can also hide it on mouse out.
And remove the arrow.
toggleInfo() {
this.active = !this.active;
}