How to access V-for elements - vuejs2

I have Large Image elements dynamically rendered using v-for
<div class="preview-pic tab-content">
<div class="tab-pane"
v-bind:class="activeClass"
:id= index
v-for="(imgLink, index) in itemSelected.itemImages"
v-bind:ref="index">
<img :src="imgLink.urlLargeImage" />
</div>
</div>
I also have Thumbnail images rendered in v-for
<li v-for="(imgLink, index) in itemSelected.itemImages">
<a #click="onImgClicked" :data-target="'#' + index" data-toggle="tab">
<img :src="imgLink.urlThumbnail" />
</a>
</li>
in my methods:
methods:{
onImgClicked: function (index) {
document.getElementById(index).className="active" // works but is it vue-way?
this.$refs.0.className = "active" // only works if i know what index of the thumbnail will be clicked
}
}
When a thumbnail image is clicked, I'd like to make it's corresponding large image to be active by setting the css class "active". I can accomplish this with document.getelementbyid, but is that the vue-way? My attempt with $refs
I also attempted using v-bind but I was unsuccessful because either all large images will be active or not active.

If you only want one image active at a time, add an activeImage property to your data.
data(){
return {
activeImage: null
}
}
Modify your template in this way.
<div class="preview-pic tab-content">
<div class="tab-pane"
:class="{active: imgLink === activeImage}"
:id= index
v-for="(imgLink, index) in itemSelected.itemImages"
v-bind:ref="index">
<img :src="imgLink.urlLargeImage" />
</div>
</div>
...
<li v-for="(imgLink, index) in itemSelected.itemImages">
<a #click="activeImage = imgLink"
:data-target="'#' + index" data-toggle="tab">
<img :src="imgLink.urlThumbnail" />
</a>
</li>
And get rid of your onImgClicked. Also, you will want to set activeImage to null when you don't want any image active.
Alternatively, if more than one image could be active at a time, add a boolean active property to your imgLink objects, and change your template to
:class="{active: imgLink.active}"
and
#click="imgLink.active = !imgLink.active"

Related

Vuejs - How to add multiple loading indicators (spinner) to have different states from each other?

What I want is the spinner which can be found here in How To Add Loading Indicators to Your Vue.js Application. However I want to use it for different elements and with different states. For example when the first image is uploading, I change the state of the spinner to be shown however if I change the variable spinner to true, all the spinners inside all images will be shown but I want only the spinner that its parent(image) is uploading to be circulating.
<div class="image">
<input class="d-none" type="file" #change="spinner = true"> <!-- This shows other spinners too -->
<div class="loader" v-if="spinner === true"></div>
</div>
<div class="image">
<input class="d-none" type="file" #change="spinner = true"> <!-- This shows other spinners too -->
<div class="loader" v-if="spinner === true"></div>
</div>
I would create a component per each image with it's own state. Or another solution would be to put each image object (with state logic and name) in an array and loop through it with v-for, changing loading state in particular object. E.g.
<div class="image" v-for="(image, i) in images" :key="i">
<input class="d-none" type="file" #change="image.loading = true">
<div class="loader" v-if="image.loading"></div>
</div>
data() {
return {
images: [
{src: 'www/some.com', loading: false},
{src: 'www/some2.com', loading: false}
]
}}

v-on:click not working - dynamically added html element

I am trying to get all images for a category using Vue
<div class="col-md-12 col-sm-2 p-2">
<a v-on:click="onCategoryManageImageClick($event)" data-target="#location-
category-images">
</span>
</a>
</div>
So the event onCategoryManageImageClick ($event) does not work, if I am adding a html block and then click on get image button.
this is index.js
methods:{
onImagesTabClick(){
this.$root.$emit('activated-tab:location-images');
},
onCategoriesTabClick(){
window.j1App.eventBus.$emit("j1-location-image-list:shown");
},
onCategoryManageImageClick: function(event) {console.log('working event..');
event.preventDefault();
window.j1App.eventBus.$emit("j1-location-category-image-
list:shown",event.currentTarget.id);
}
}
So basically it need to to work like we do in jQuery
$(document).on('click',function{
})
So it works either page load or if adding any new html element on DOM. same I want in Vue.
You cannot alter the Vue template outside of Vue. That won't work. Vue compiles the template once when starting up and adds the event listeners to the rendered elements. If you add elements afterwards, Vue will not know about them.
The correct way of doing this would be to add those new elements in Vue.
<div
class="col-md-12 col-sm-2 p-2"
v-for="item in items"
:key="item.id"
>
<a
v-on:click="onCategoryManageImageClick($event, item)"
data-target="#location-category-images"
>
</a>
</div>
See https://v2.vuejs.org/v2/guide/list.html for documentation. In this case you need the items array variable in data and add more array elements to it, if you need more links.
Try raplacing your a tag with p
<div class="col-md-12 col-sm-2 p-2">
<p v-on:click="onCategoryManageImageClick" data-target="#location-
category-images">
</p>
</div>

Change element background-image inside a v-for

I have a v-for thats reading different .md files which have a image property in their front matter.
I am trying to change my div's background-image But it has to read that url taken from the files frontmatter.
this is the code:
<div v-for="item in projectsList" class="li" >
<div style="background-image: url(https://i.pinimg.com/originals/4f/c4/92/4fc49228a940e41435b3796c18fc2346.jpg)">
<a :href="item.path" class="li">
<span>{{ item.title }}</span>
</a>
</div>
</div>
Now the issue lies in changing the style:"background-image: url(<URL>) property.
I can access the image through item.frontmatter.image,
I read about this so i tried to do an example and just for testing purposes tried to feed an image through the Data function, but to vue the Url is undefined so i need a different way of feeding a URL based image to the background.
:style:"{'background-image': url( imageURL )}"
data: function () {
return {
imageURL: 'https://i.pinimg.com/originals/4f/c4/92/4fc49228a940e41435b3796c18fc2346.jpg'
}
},
You should be able to do it like this:
<div v-for="item in projectsList" class="li" >
<div :style="{ 'background-image': `url(${item.frontmatter.image})` }">
<a :href="item.path" class="li">
<span>{{ item.title }}</span>
</a>
</div>
</div>
No data function needed here I think.

Show Div When Hover Based on ID in Vue JS

I have a div that when i want hover to it, it will show other div. However, my first div is dynamic, it has an ID. So how will i able to hover to ID based on its ID?
It should be #mouseenter="hoverService{{services.id}} = true" but it causes error. So i made the code below to just static.
Here's my code below:
<template>
<div
class="col-md-3"
v-for="(services, index) in servicesFiltered"
:key="index"
#mouseenter="hoverService = true"
#mouseleave="hoverService = false"
>
<div class="service_background" v-if="hoverService">
<div class="mb-1" v-for="(sub_services, index) in services.menu_items" :key="index">
<router-link
:to="{ path: `/${sub_services.data}`}"
>
<a
href="#"
class="btn btn-outline-primary w-100 services_button"
>{{sub_services.text }}</a>
</router-link>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
hoverService: false
};
}
};
</script>
Try this code
https://codesandbox.io/s/y7p9qyyovz
You need to maintain hover for each item you can not manipulate using single variable for multiple items.

Check the height of an image with a display block

This is what I'm trying to achive:
I have list of images which are rotating inside a div (fade in, fade out effect)
in each rotation there is one which displays and all the rest are hidden (display: none)
I am trying to create a "resize" event which will always check the height of only existing image (the only one that is showing in the sequence) and assign this height to it's main container (in my case: the UL)
Here is my HTML:
<ul id="output">
<li>
<div class="description">Lorem Ipsum</div>
<img src="images/sample1.jpg">
</li>
<li>
<div class="description">Lorem Ipsum</div>
<img src="images/sample2.jpg">
</li>
<li>
<div class="description">Lorem Ipsum</div>
<img src="/images/sample3.jpg">
</li>
</ul>
and my JS:
jQuery(window).resize(function() {
slide_img = jQuery.find("ul#output li img");
slide_img_height = jQuery(slide_img).height();
if(jQuery(slide_img).css("display") != "none"){
jQuery("ul#output").height(slide_img_height);
}
});
It is not working. it also get the height of the "hiddden" images in the sequence and displays their height (which equals to 0)
how do I pull only the image with the display block always and get it's height and then assign it to the main UL?
Thanks
Let me make sure I understand your question:
1.) You have a container for several images, only one of which will be visible at a time.
2.) You want to change the size of the container to just fit the image currently displayed.
3.) Are you also trying to display the height (in pixels) as a text element?
If you're just trying to accomplish the first two, you can nest your images in a instead of like:
<div id='output'>
<div class='container'>
<div class='description'>Lorem ipsum</div>
<div class='image>
<img src='images/sample1.jpg' />
</div>
</div>
<div class='container'>
<div class='description'>Lorem ipsum</div>
<div class='image>
<img src='images/sample2.jpg' />
</div>
</div>
<div class='container'>
<div class='description'>Lorem ipsum</div>
<div class='image>
<img src='images/sample3.jpg' />
</div>
</div>
</div>
If you do this, the height of your 'output' div will always be the height of the only displayed image. If you needed to display the value of the actual height, you could use:
var outputHeight = $('#output').height();
Since I can't add enough code in a comment to answer your follow-on question, here it is:
If you need to keep your original structure, try this:
<ul id="output">
<li class="container active">
<div class="description">Lorem Ipsum</div>
<img src="images/sample1.jpg" />
</li>
<li class="container">
<div class="description">Lorem Ipsum</div>
<img src="images/sample2.jpg" />
</li>
<li class="container">
<div class="description">Lorem Ipsum</div>
<img src="images/sample3.jpg" />
</li>
</ul>
Then you can select the <li>'s to be either hidden or visible with some CSS like this:
.contaner {
display: none;
}
.active {
display: inline;
}
Like this, the entire <li> gets removed when you set display: none; and only the visible one will take up space in the <ul>. That will let your <ul> only be as high as the currently displayed image.
Hopefully that answers your question.
So eventually, this is what I came up with and it works perfectly:
jQuery(window).resize(function() {
// variables presenting the LI, IMG and th eheigt of the img
slide_li = jQuery("ul#output li").css('display','list-item');
slide_img = jQuery(slide_li).find('img');
slide_img_height = jQuery(slide_img).height();
jQuery("ul#output").height(slide_img_height);
});
This way I was able to find the only image that has a display of "list-item" (I know it's weird but this is how the slider works, I didn't build it)
and then, get the image height and assign it to the main container which is in my case:
ul#output
Credit to #anson for doing his best to help
Thanks