How can we define new iterator like v-for (for example v-for2) that iterate over an array ?
I want to accumulate one property of array items.
the result would be like this :
<div v-for2="(item, accumulated) in [1,2,3,4,5,6]">
{{accumulated}}
</div>
Related
I have a grid created for videos. It makes a call to an api to return back videos. I have a state isFetching that is set to true when the page loads and tries to retrieve the list from the API. After the videos are retrieved, isFetching is set to false and the data is stored as videoList.
I am using a grid with a placeholder component for each item if the API takes a while to fetch. The VideoGrid expects a items because inside of it, it iterates through it. I want to have 16 grid items but I don't want to have to do :items=[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]. I tried :items="[new Array(16).keys()] but that seems to create a nested array. Is there a way to accomplish this without having to write it out like that?
Main.vue
<VideoGrid v-if="isFetching && !videoList" :items="[1,2,3,4,5,6]">
<template>
<ItemPlaceholder />
</template>
</VideoGrid>
<VideoGrid v-else :items="videoList">
<template v-slot="slotProps>
<VideoComponent :title="slotProps.title" />
</template>
</VideoGrid>
You should just be able to remove the brackets from your items declaration like so:
<VideoGrid v-if="isFetching && !videoList" :items="Array(16).fill(1)">
<template>
<ItemPlaceholder />
</template>
</VideoGrid>
<VideoGrid v-else :items="videoList">
<template v-slot="slotProps>
<VideoComponent :title="slotProps.title" />
</template>
</VideoGrid>
Array(16).fill(1) will create an array with 16 number 1's. If you want to have incrementing values in your array you can use Array.from({length: 16}, (v, i) => i) or see How to initialize an array's length in JavaScript?.
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.
I am creating components in a loop in my vue app. However, I need those components to have an id value like "board-1" etc. using the index of the loop. (Just like I did it with v-bind:key="component-${block._uid}".)
How can I achieve this?
<div
class = "col-4"
v-for="(block, index) in layouts"
v-bind:key="`component-${block._uid}`"
>
<Board
id="`board-${block._uid}`"
class="droparea"
#dropped-component="$emit('dropped-component', $event, index)"
:acceptsDrop=true
draggable="true"
>
Layout {{index + 1}}
</Board>
</div>
You need to bind the value for JS code to get executed, otherwise you are attributing a string, not JS code.
:id="`board-${block._uid}`"
You can also use v-bind, actually : is just a shorthand
v-bind:id="`board-${block._uid}`"
consider you got a list of objects you want to iterate over of which each object contains an array with the name f. Also you got a log function that prints a string from a parameter and returns true. Here you see the corresponding template section:
<template>
<div>
<div v-for="o in objArr" v-if="log('base')">
<div v-for="a in o.f" v-if="log('subbase')">
</div>
</div>
</div>
</template>
Here is an example of the data if have used:
objArr: [
{ a : 1, b : 2, c : 3, d : 4, e : 5, f : [10,9,8]},
{ a : 1, b : 2, c : 3, d : 4, e : 5, f : [10,9,8]},
],
Now I change a random array element in one of the Objects. I do this on the console with:
$vm.objArr[3].f.splice(2,1,4);
(This will change the 4th Object, and within that object replace the 3rd array element with the value of 4).
Because of vue's reactive capabilities, it will detect the change and rerender the necessary components. Imagine the objArr has 2 elements and the array of object we are changing has 3 elements. The Output will be:
base
subbase
subbase
subbase
base
subbase
subbase
subbase
Now I want to use components as wrappers. I change above to:
<div>
<div >
<performance-test v-for="o in objArr" v-if="log('base')" :mydata="o">
</performance-test>
</div>
</div>
And inside the performance-test component we got:
<div>
<div v-for="a in mydata.f" v-if="log('basesub')">
</div>
</div>
We still got a for-loop inside a for-loop and I use the same method as above to change the base components array, but vue decides to update different this time. The output is:
subbase
subbase
subbase
I can't make up my mind right now. If I don't want to have any data (and logic) in my subcomponents. How would I prevent vue from going all over the whole object even if only one array inside a single object changed?
Hope you can help.
It seems the problem is you have not declared a :key when using performance-test (a custom component) in a v-for. Try:
<performance-test v-for="o in objArr" v-if="log('base')" :mydata="o" :key="o.a">
</performance-test>
Note: o.a must be unique for each o!
Codesandbox working demo here.
How do you pass the item instance from the foreach loop as a prop?
<div v-for="n in parentArray">
<blog-card prop="{{ n.content }}"></blog-card>
</div>
When I run this I get an error
(Emitted value instead of an instance of Error)
Can this be done without rebinding the item to the parent component?
With Vue 2 you don't use interpolation in attributes, you use the attribute binding syntax.
<blog-card v-bind:prop="n.content"></blog-card>
Or the shortcut
<blog-card :prop="n.content"></blog-card>