This question already has answers here:
How to limit iteration of elements in `v-for`
(7 answers)
Closed 2 years ago.
Simple problem, i have a members list where i iterate through it with a v-for.
How can i limit the results and only show the first 2 ?
members = [ {id : 1, name: 'Franck'}, {id : 2, name: 'Sophie'}, {id : 3, name: 'Bob'}]
<div v-for="member in members" :key="member.id">
<p>{{ name }}</p>
</div>
Just want to know if it's feasible from template ? Otherwise i know that i can use a computed properties that filtered it and i just have to loop through the results of my filtered array
You can use slice() in the template if you prefer to not use a computed property. I would though choose to have a computed property, if for nothing else, I like to handle all logic in script instead of template. But as said, you can use slice:
v-for="(member, index) in members.slice(0, 2)"
A forked fiddle that was provided by #Raffobaffo in a comment.
After some discussions here, lets divide the answer in two:
A fast, not super correct way but still referred inside vue docs
Use a v-if and set and index in the v-for.
<div v-for="(member, index) in members" :key="member.id" v-if="index < 3">
<p>{{ name }}</p>
</div>
else, the most correct way is to create a computed property returning just the elements you need:
<template>
<div v-for="member in justTwoElements" :key="member.id">
<p>{{ name }}</p>
</div>
<template>
....
computed: {
justTwoElements: function(){
return this.members.slice(0,2);
}
}
This latest solution is more indicated when your data entry is huge, the benefits of using it instead of the first solution are well explained here.
I hope this helps to give you the correct path to follow
Related
I am printing some data on some condition by looping It is working fine but i feel like my approach is not correct as i am doing calculation based work inside the script tag (javascript portion below )
My for loop
<div v-for="row in cars.honda" v-if="cars.id == row.car_id" >
**<span v-show="txt=='show'">{{ cars.id == row.car_id?txt="sizes":txt="showerror"}}</span>**
<p v-if="cars.id == row.car_id" >
{{ row.car_name}}
</p>
</div>
Is it okay or good practice to assign value to txt variable inside tag as i am unable to do the same thing when I create a function in script tag It doesnt works that way as the txt variable value is not updated
No, it not recommended even the first line of code is not recommended. Using v-for and v-if together is not a good idea. You can read more about it vuejs doc
Assigning a new txt variable, that also you should generally avoid, it will hard to track if your template have more code.
Here is sample you can do it in a simple way.
<div v-for="row in cars.honda" :key="row.id">
<div v-if="cars.id == row.car_id">
<span v-if="somecondition">Show Valid Data</span>
<span v-else>Show Error</span>
<p>
{{ row.car_name}}
</p>
</div>
</div>
Generally its good practice to avoid multiple computation in the template, template are mean to be represent the data with help of directive like v-for v-if etc. They are not much responsible for computation of logic. Also use :key with v-for for better performance.
The reason why we don't use ternary operations like you have used is because it's a recipe for bugs. Everything inside the Double brackets "{{ }}" is escaped which means if you include any html tags they would be removed. Your example should be working fine but it's best practice to only stick with v-if & v-else
<span v-if="somethingIsTrue">{{showSomething}}</span>
Well, you although you could use v-if with v-for, it's not a recommended approach. Read this for more.
When used together with v-if, v-for has a higher priority than v-if. See the list rendering guide for details.
Therefore, you should always use v-for independently and then use v-if inside it to show/hide content based on some conditions.
Now coming to your question on whether it is safe to assign values in templates, the answer is no it's not, because that's just a bad syntax which is difficult to read. Ternary operator is not used to assign values like the way you have used.
Correct syntax for assigning using a ternary operator is:
let a = b=="something" ? "Hello" : "world";
Which in turn should be encapsulated within a computed property or a method to be called everywhere in vuejs.
Showing a sample approach below
Vue.config.productionTip = false
Vue.config.devtools = false
new Vue({
el: "#app",
data: {
cars: {
id: 1,
honda: [
{car_id: 1, car_name: "Honda City"},
{car_id: 2, car_name: "Honda Civic"},
],
}
},
methods: {
isSameCar(carID){
return this.cars.id ===carID ? true : false;
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div v-for="row in cars.honda" :key="row.id">
<div v-if="isSameCar(row.car_id)">
<p>{{ row.car_name}}</p>
</div>
<div v-else>
<p>Not the same car, so show error here</p>
</div>
</div>
</div>
Sometimes it is needed to comment out some element attribute without having to remember it in order to restore it quickly after some tests.
Commenting out whole element is achievable with HTML commenting syntax
<div>
<!-- <h2>Hello</h2> -->
<span>hi</span>
</div>
However this won't work with a single attribute (causes rendering error)
<my-comp id="my_comp_1"
v-model="value"
<!-- :disabled="!isValid" -->
#click="handleClick">
</my-comp>
The best approach I could see and used before was to make a tag backup by copying whole element and settings v-if="false" for it (or comment out whole copied element) and continue to experiment with original one
I don't think you can put an HTML comment inside a component tag, for much the same reason you can't put comments inside an HTML element opening tag. It's not valid markup in either situation. I think the closest you could come would be to place the comment in the quotes:
:disabled="// !isValid"
Which would have the same effect as:
:disabled=""
Depending on whether your component can handle that value being missing, that might fit your needs.
Prefix the attribute value with data- or Wrap with data attribute.
<my-comp id="my_comp_1"
v-model="value"
data-:disabled="!isValid"
data-_click="handleClick"> # `#` could not be used
</my-comp>
or
<my-comp id="my_comp_1"
v-model="value"
data='
:disabled="!isValid"
#click="handleClick">
'>
</my-comp>
I'll with the attribute set to something like data-FIXME.
I got these solutions to work. I thought of solution 1.
Starting code:
<div
v-for="foo in foos"
:key="foo.id"
#click="foo.on = !foo.on /* JavaScript comment. */"
>
<label>
{{ foo.name }} {{foo.on}}
</label>
</div>
The Vue directive HTML attribute that needs to be disabled: #click="foo.on = !foo.on"
How the final div tag will run:
<div
v-for="foo in foos"
:key="foo.id"
>
Solutions 1 and 2 keep the disabled attribute inside its tag. I didn't find a good way to make a "raw string". To keep the attribute in the tag, the outer and inner quotes must be different.
sol. 1: I made a new v-bind attribute (:lang) to put the disabled attribute in.
:lang='en /* #click="foo.on = !foo.on" */'
Sol. 2: Pick a Vue directive. Put the attribute in.
v-for="foo in foos /* #click='foo.on = !foo.on' */"
Solutions 3 and 4 put the attribute outside the tag.
Sol. 3:
<div v-if="false">
#click="foo.on = !foo.on"
</div>
Sol. 4: <!-- #click="foo.on = !foo.on" -->
One way to remove/hide component attributes is to create a custom directive for it.
Let's say you create a directive called v-hide and put it in your component as:
<my-comp v-model="value" #click="handleClick" v-hide :disable='true'></my-comp>
And the output would be:
<my-comp v-model="value" #click="handleClick"></my-comp>
Here is a working example:
Vue.component ('my-component', {
template: `<p> A custom template </p>`
})
Vue.directive('hide', {
inserted: function (el) {
console.log('el before hide', el)
while(el.attributes.length > 0)
el.removeAttribute(el.attributes[0].name);
console.log('el after hide', el)
}
})
new Vue({
el: '#app',
data () {
return {
someValue: 'Hello'
}
}
})
<script src="https://unpkg.com/vue#2.5.3/dist/vue.js"></script>
<div id="app">
<my-component v-model='someValue' v-hide :disable='true'></my-component>
</div>
Hopefully this replica isn't too alien to the Vue.js world.
I have a list of profiles. Inside these profile instances there is an array that represents their socialMedia accounts. However, due to legacy database reasons, let's say that for some of the artists the socialMedia account comes through into the Vue.js application as null.
So, imagine I have something like:
<a
v-if="artwork.artist.socialMedia"
v-for="(social, index) in artwork.artist.socialMedia.filter(social => social.url.length > 0)"
v-bind:key="index"
v-bind:href="parseSocialMediaURL(social.url, social.platform)"
>
</a>
However, the preceding v-if statement, doesn't seem to be skipping past those values for artwork.artist.socialMedia when this is null. For most, this value is just a plain old Array, so how do I go about handling both cases?
Your v-if should work, but if your condition is more complex than a simple if you can consider using a computed method for this. It could also handle the filter in it. You can also use isArray for a better check.
computed: {
artistSocialMedia () {
if( !Array.isArray(this.artwork.artist.socialMedia) ) {
return []
}
return this.artwork.artist.socialMedia.filter(social => social.url.length > 0)
}
}
and then use the computed method
<a
v-for="(social, index) in artistSocialMedia"
v-bind:key="index"
v-bind:href="parseSocialMediaURL(social.url, social.platform)"
>
</a>
As part of the vue documentation, you should not be using them together https://v2.vuejs.org/v2/guide/conditional.html#v-if-with-v-for.
To render conditionally without adding addition elements wrap it in a template
<template v-if="artwork.artist.socialMedia">
<a
v-for="(social, index) in artwork.artist.socialMedia.filter(social => social.url.length > 0)"
v-bind:key="index"
v-bind:href="parseSocialMediaURL(social.url, social.platform)"
>
</a>
</template>
i have a object name question.which is coming from database.i have used v-for with my question object for creating input field.and filing the field the with the question. but i have also a answer field below of question field.i want to use v-model on that answer field. as example i have five question there is five answer field.if i have four question i have four answer field. i don't know for sure how many question field will be there as it is not certain.i want to use v-model with the answer field.as example if there is five answer field i want to create five object of answer filed. how should i do it?
<template>
<div v-for="(creative_s,index) in question_s_s.creative_s_s" v-if="question_s_s.type=='Creative'">
<v-textarea
disabled
filled
label="Story"
rounded
v-model="creative_s.story"
></v-textarea>
<v-textarea
label="Answer for Question no 1"
outlined
rounded
v-model=""
></v-textarea>
</div>
</template>
<script>
export default {
data: () => ({
creative: {},
}),
}
</script>
question_s_s is coming by ajax request from database.inside question_s_s i have creative_s_s object there is no problem. i want to use v-model on the answer part.
I have a problem using Vue.js and the library VueDraggable (https://github.com/SortableJS/Vue.Draggable)
Here is a sample of code :
<draggable v-if="n === 2 && track.getDisplayArray()[1].length !==0"
element="ul"
:options="{group:'layers '+ track.itemId}"
v-bind:class="{ hidden: !track.show, 'child-container': track.show }"
v-model="track.getDisplayArray()[1]"
:move="onMove"
#start="onStart"
#end="onFinished">
<li class="item" v-bind:class="{ hidden: !layer.show, child: layer.show }"
v-for="layer in track.getDisplayArray()[1]">
<span>{{layer.name}}</span>
<img class="item-view" src="static/img/ic_view.svg" alt="view">
</li>
</draggable>
onMove function just returns true, onStart and onFinished are empty (but I want to do something with them in the future ;) )
When the "v-model" property is here, the li tags which are created cannot be swapped.
When I remove this property, the li tags can be swapped.
Do you see the problem? Are they some "conflicts" between some properties that I am not aware of?
I found the solution of my problem. Changing v-model to value didn't change anything, because they don't see updates from the list they are linked to.
I replaced the "v-model" property by the property "list" .
According to the documentation :
The main difference is that list prop
is updated by draggable component using splice method, whereas value
is immutable.