Vue.js: Save index of v-for? - vue.js

I would like to save the latest index inside a v-for, but I don't know how to include this logic inside the template?
Basically, I have this:
<div v-for="(reply, index) in replies" :key="reply.id">
I want to include this logic inside the template somehow:
this.last_index = index
I just want to know the amount of total replies in that v-for loop.
Thank you!

The most adequate solution is use a computed property in Vue. I usually made it like this:
computed: {
lengthReply() {
return this.replies.length;
}
}
If you use Vuex, then you probably can use getters for this case.
If you really don't wanna use computed property, then you can put it in your template in curly braces, like this:
{{ replies.length }}
If you need to render only last element in your reply list, then you can use this terrible code:
<div v-for="(reply, index) in replies" v-if="reply === replies[replies.length - 1]">

Related

Vue doesn't rerender list even when using set

I made a list that each item could be removable and my code looked like this:
Template
<template v-for="(timeFrame, index) in form.timeFrames">
<el-form-item >
<el-button #click="removeTimeFrame(index)">
<i class="el-icon-remove"></i>
</el-button>
</el-form-item>
</template>
Js:
removeTimeFrame(index = 0) {
this.$set(this.form, 'timeFrames', this.form.timeFrames.filter((_, i) => index !== i));
}
Somehow the list doesn't rerender until I add an new item to the list. Does anybody know what's wrong with my code?
templates in Vue need a top level element wrapping their content, so you shouldn't assign the v-for directly to the template tag, but instead create a div inside the template tag and either add v-for to the el-form-item component or wrap it in another div-tag.
Additionally, every element in a v-for loop should contain a key. If you do not plan to reorder or delete elements from the loop, the index-value of each element is fine for this. Seeing your example I suspect that a unique identifier, such as a randomly generated unique id, might work better for your use case.

Vuejs Render list of Array based on key values

I have a dataArray with data like this:
dataArray: {'stat1': 'stat1stat', 'stat2': 'stat2stat', 'stat3': 'stat3stat'}
and so on with hundreds of statistics in the array.
I have been outputting things hard coded in the vue template like this:
{{dataArray.stat2}}
{{dataArray.stat3}}
..etc
What I would like to do is have a new array that specifies the keys I want to render. So something like this:
dataToShow: ['stat2', 'stat3']
And then somehow I could do a loop or v-for to only show the data that is in dataToShow
I've tried a few different ways and I can't get it to work. I think it needs to be a computed property but it isn't working.
Can anyone give some advice on how to implement this?
Wouldn't it just be this?
<template v-for="property in dataToShow">
{{ dataArray[property] }}
</template>
Plus any relevant markup for each entry.
dataToShow could be a computed property as you've suggested but it could just as easily be in your data:
data () {
return {
dataArray: {
stat1: 'stat1stat',
// etc.
},
dataToShow: ['stat2', 'stat3']
}
}

VueJS find element by key

I've just wanted to know if it is possible to find a DOM element by the key attribute of vue?
I'm currently working with a list. I'm displaying it via v-for directive on a div. I'm binding the key with the index of the elements.
v-for="(apk, index) in project.apks" v-bind:key="index"
It would really help me if i could compute something for each of these elements as soon as they are fetch from my server and displayed. It's just parsing a file and looking for keyword, and accordingly choosing a css class for the items.
The problem is I dont know how to call a method for each of these elements as soon as they are added to the DOM. They are a lot of html events but i couldnt find one representing the object beeing inserted to dom :(
The purpose of key is not selecting element. Even if it can be done, don't do it.
The proper way to do it is by using ref.
for example, add ref attribute to your html like this
v-for="(apk, index) in project.apks" v-bind:key="index" :ref="'sample-ref-'+index"
and then in your methods, you can get the DOM using this.$refs['sample-ref-0'],this.$refs['sample-ref-1'] and so on.
Hope this helps.
I found that if you give the 'ref' the same name in a v-for, like this:
<div v-for="data in list" :key="data.id" ref="bar"></div>
Then you will find they just store in an array called 'bar' and you can visit them by:
this.$refs['bar'][index]
something like this could allow you to find a component by key :
this.$children.forEach(child=>{
print("child.$vnode.key")
})
also use mounted , as it gets called when the component is added to the dom:
mounted:function(){
this.$el.querySelector("#ele1")...
}
The problem is I dont know how to call a method for each of these elements as soon as they are added to the DOM. They are a lot of html events but i couldnt find one representing the object beeing inserted to dom :(
You can create a new component with your v-for and just call the created() hook.
Example
/* On your main function */
<div v-for="apk in project.apks">
<apk :data="apk"></apk>
</div>
/* On your 'apk' component */
export default {
props: [ "data" ],
created() {
console.log("Created !");
}
}

Using multiple filters in v-for directive in Vue 2.0

Just following a tutorial about Vue filter on v-for directive in Vue 1.x, the author was using multiple filters in one v-for directive, e.g.
<ul v-for="post in posts | filterBy nameFilter in 'name' | filterBy catFilter in 'cat'"></ul>
As far as I know from the official documentation, this syntax is no longer being used in Vue 2.0, I tried to rewrite this line of code into
<ul v-for="post in nameFilter | catFilter"></ul>
I also created two computed functions nameFilter and cateFilter to filter out the posts by name and category. My code is not working, it only listens to the first filter which is nameFilter, cateFilter has no effect at all.
So I was wondering in Vue 2.0, is that still possible to add multiple filters in v-for directive? If it is possible, could you guys please advise the syntax?
If that's impossible, does that mean that I need to create one filter function to do all the filter logic in that single function?
Thanks in advance.
Found the answer from here
Basically, we only need one computed function to return the filtered data for v-for directive, e.g.
<ul v-for="post in filteredPosts"></ul>
If we want to add multiple, just chain all your javascript native .filter functions in that function and return the data. In my case, it would be something like this:
computed: {
filteredPost: function () {
var self = this
return self.posts
.filter(function (post) {
return post.title.indexOf(self.searchQuery) !== -1;
})
.filter(function(post) {
return (post.category.includes(self.selectedCategory))
})
}
}
self.searchQuery and self.selectedCategory are just data properties for this Vue instance in my example, the key takeaway is one computed function with multiple .filter() functions chaining together.
Hope that will help.

When v-for array created by computed option changs, the DOM doesn't change accordingly

Recently, I've encountered a problem that caused by the computed option of vuejs.
Firstly, I use v-for to loop for an array (soloColImgs) which is created by the computed option.
my HTML
<div class="show-box" v-for="item in soloColImgs" track-by="$index">
<img v-bind:src="item.imgUrl"/>
<a v-bind:href="item.itemUrl" target="_blank"></a>
</div>
my JS
//...
computed: {
soloColImgs :function(){
//....
},
methods: {
change:function(){
this.soloColImgs.pop();
}
}
Secondly, I change the array (soloColImgs) by using pop() or splice() etc...When I look into the console, the array can change accordingly, however, the DOM does't change at all. It would be greatful if anyone can help me out of this.
The point of a computed property is that its determined solely by the function that defines it. You cannot change it directly, you must change it by acting on the dependencies. The dependencies are the properties that are used to calculate the returned value.