VUEJS V-FOR acting weird - vuejs2

I need a simple v-for to render object properties in a list.
<div
v-if="profileData && profileData.length > 0"
>
<ul
v-for="value in profileData"
:key="value.id"
>
<li>{{value.id}}</li>
</ul>
</div>
In the script:
profileData: {},
created() {
const userId = this.$route.params.userId
const currentUser = this.$store.getters.currentUser
const profileData = this.$store.getters.profileData
console.log('profileData in seeProfile: ', profileData) }
(profileData comes from an api response)
I did exactly the same in two other pages (just rendering different objects) and it worked.
With this code, in the console I get value is undefined.
If I remove :key="value.id" (it becomes red in the editor but it still works), and instead of the list items I type only {{ value }}}, then the object properties get rendered ( but in the ugly format of a js object). How can it be? What am I doing wrong?
Thank you

Your v-if will never show even if profileData has data, because you can't directly check for the length of an Object in javascript.
A few things:
You can't check for the length of an Object, it will return undefined. If you must use an object, then you'd have to check for Object.keys(obj).length.
let obj = {
first: {
name: "first",
meta: "data"
},
second: {
name: "second",
meta: "data"
}
};
console.log("Object.length is: ", obj.length);
console.log("Object.keys().length is: ", Object.keys(obj).length);
You're being redundant, you don't need to check for profileData and its length (and you don't need to > 0), you could simply check for v-if="Object.keys(profileData).length". If the Object has zero entries, then it won't show because if(0) is false.
I'd strongly recommend to work with arrays to iterate with v-for. I'd use computed properties and return an array, and iterate through that. Object reactivity works non-intuitively in JS, so you'll be scratching your head later when you try to find out why stuff isn't updating on your view:
computed: {
listData() {
let list = Object.values(this.profileData);
return list;
}
}
In view:
<div v-if="listData.length"/>
Also, don't use the array's entry index as your :key, because if you have another array with v-for, you'll have duplicated keys in your model. I'd use something like v-for="(item, key) in list" :key="'list-item-' + key"

Put the v-for on the li, not the ul.
<ul>
<li v-for="value in profileData"
:key="value.id">{{value.id}}</li>
</ul>
Also , if your your profileData is an object and not an array, you need to decide if you want to loop through the keys or values.
<ul>
<li v-for="value in Object.values(profileData)"
:key="value.id">{{value.id}}</li>
</ul>
<ul>
<li v-for="value in Object.keys(profileData)"
:key="value.id">{{value.id}}</li>
</ul>
Or use Vue's default behavior.
<ul>
<li v-for="(value,key) in profileData"
:key="value.id">{{value.id}}</li>
</ul>

The api has been changed, so the working code is slightly different from the original one.
Here's the template:
<div
v-if="listData.length"
>
<ul>
<li>Name: <b>{{ profileData.user.first_name }}</b></li>
<li>Surname: <b>{{ profileData.user.last_name }}</b></li>
<li>Username: <b>{{ profileData.user.username }}</b></li>
<li>Car: <b>{{ profileData.if_cars_owned }}</b></li>
<li v-if="profileData.if_cars_owned === true">
Car model: {{ profileData.user_car_type }}
</li>
<li v-if="profileData.if_cars_owned === true">
Car power: {{ profileData.user_car_powered_by }}
</li>
<li>Motorcycle: <b>{{ profileData.if_motorcycle_owned }}</b></li>
<li v-if="profileData.if_motorcycle_owned === true">
Motorcycle model: {{ profileData.user_motorcycle_characteristic }}
</li>
</ul>
</div>
Script:
created(){
const profileData = this.$store.getters.profileData
this.profileData = profileData
console.log('profile data in profilo: ', profileData)
},
I've also updated
<div
v-if="listData.length"
>
and in the script
computed: {
...,
listData() {
let list = Object.values(this.profileData);
return list;
}
},
following the advice of #Adrián S. Basave.
Thanks to anyone who tried to help.
x

Related

Can't display datetime from v-for

I'm trying to show the datatime in a v-for, but it just keeps showing the same time over and over.
Is there a way to do this?
v-for -
<div class="location-box-container">
<ul class="location-box-list">
<ol v-for="(location, index) in lineStringData" :key="lineStringData.id">
<p class="locations">{{ location_time }} New Location</p>
</ol>
</ul>
</div>
JS -
data() {
return {
location_time: new Date().toLocaleTimeString(),
}
},
Use a method to lookup time. Not sure where you are storing the time, but you can look up timezone from coords if needed.
<div class="location-box-container">
<ul class="location-box-list">
<ol v-for="(location, index) in lineStringData" :key="lineStringData.id">
<p class="locations">{{ getTime(location) }} New Location</p>
</ol>
</ul>
</div>
methods: {
getTime(location) {
// lookup your timezone, etc here.
return new Date(location.theTime).toLocaleTimeString()
}
}

How to do a v-model for an array of objects with multiple fields

So I have 2 checkbox inputs for each element in an array. The first represents a field in a form and the second represents the fact that the field is required or not, I need to construct and array of objects like so
[
{
name: 'fieldName',
required: true
},
{
name: 'anotherFieldName'
}
]
If the first checkbox is checked I need to add an object with the "name" property in my array, and if the second one is checked too I also need to add the "required" field.
try this
<li v-for="(item, index) of items">
{{ item.prop2 }}
<input type="text" v-model="items[index].prop2">
</li>
or
<li v-for="(item, index) of items">
{{ item.prop2 }}
<input type="text" #input="updateMyProp(index)">
</li>
...
methods: {
updateMyProp ($event, index) {
// your update logic here
// you can use 'this.items', Object.assign, Vue.set, etc... to update your value
}
...

Dynamic computed property in html

I'm using php for creating set of computed properties in my app based on ID property of each object in my main array of data stored in property deals. So i have now computed properties like list_10_deals_cnt, list_20_deals_cnt, list_30_deals_cnt etc. Now, how can I create these dynamic created properties in span with class dials__cnt while looping my array of data? {{'list_'+el.id+'_deals_cnt'}} is not working as i wish, its display just a string like list_10_deals_cnt instead to display a computed value.
P.S. sorry about my english.
<div class="dials" id="app">
<div class="dials__column" v-for="(el, index) in deals">
<div class="dials__header">
<div>{{el.title}}</div>
<div>сделок: <span class="dials__cnt">{{`'list_'+el.id+'_deals_cnt'`}}</span>, <span></span> руб</div>
</div>
<draggable drag-class="draggable-ghost__class" class="dials__block" :list="el.items" group="deal" #change="log(el.id, $event)">
<div
class="dials__card"
v-for="(el, index) in el.items"
:key="el.title"
>
<div class="card__header">
<div class="card__title">{{ el.customer_name }}, {{ el.customer_company_name }}</div>
<div class="card__date">{{ el.created_at }}</div>
</div>
<div class="card__body">
<a :href="'/deal/detail/'+el.id" class="card__link">{{ el.title }}</a>
</div>
<div class="card__footer">
<span class="card__price">{{ el.price }} руб </span>
<span v-for="(tag, index) in el.tags" class="card__tag">{{ tag }}</span>
</div>
</div>
</draggable>
</div>
</div>
<script>
new Vue({
el: '#app',
data: {
deals: <?php echo json_encode($deals, JSON_UNESCAPED_UNICODE); ?>
},
computed: {
<?php
foreach ($deals as $k=>$v) {
echo 'list_'.$v->id.'_deals_cnt: function() {return this.deals['.$k.'].items.length},';
}
?>
},
methods: {
log: function(id, evt) {
if (evt.hasOwnProperty('added')) {
let dealID = evt.added.element.id;
console.log('сделка ID '+dealID+' перемещена в статус '+id+'. Отправляем аякс запрос на обновление статуса в бд');
// ajax for update
}
}
}
});
</script>
Hi
Problem 1
you will not be able to get the value of computed property by using this
{{`'list_'+el.id+'_deals_cnt'`}}
for the same reason as console.log('vari' + 'able') doesn't print out value of variable to the console.
( Vue evaluates whatever is in between {{ }} as an expression ).
Solution
I suppose, you can either use the deals property directly in html as shown below without using a computed property
<div class="dials__column" v-for="(el, index) in deals">
<div class="dials__header">
<div>{{el.title}}</div>
<div>сделок: <span class="dials__cnt">{{ el.items.length }}</span>, <span></span> руб</div>
</div>
----------- rest of the code
or you can create a computed property based on deals data property and use that to loop in html using v-for.
Problem 2
I don't think below code is valid php string. although it becomes irrelevant if you use first solution above.
<?php
foreach ($deals as $k=>$v) {
echo 'list_'.$v->id.'_deals_cnt: function() {return this.deals['.$k.'].items.length},';
}
?>
the ' inside ['.$k.'] should be escaped.
Solution
echo 'list_'.$v->id.'_deals_cnt: function() {return this.deals[\'.$k.\'].items.length},';

Cannot assign value to checkbox in vue.js

I am creating a list of check boxes via a result set. I can see the correct values but I am not able to set the value correctly
<ul>
<li v-for="role in roles">
<input type="checkbox" :value="role.id" v-model="form.roleIds" > {{role.name}}
</li>
</ul>
When I click on one of the check boxes, I see all of them clicked.
That's what I see in console:
I think your data property roleIds is not defined properly, it should be like this -
roleIds: []
Test.vue
<template>
<ul>
<li v-for="(role, i) in roles" :key="i">
<label>
<input type="checkbox" :value="role.id" v-model="form.roleIds" >
{{role.name}}
</label>
</li>
</ul>
</template>
<script>
export default {
data: () => ({
form: {
roleIds: [] // **this is the catch**
},
roles: [{
id: 1,
name: 'Siddharth'
},
{
id: 2,
name: 'Arora'
}]
})
}
</script>
Console the roles array and confirm there is value for id in every entries of roles. It seems like the value for id is null.

For loop of objects

I'm trying to do a for loop of a set of objects but since they all aren't named the same, I'm stuck.
<div id="components-demo">
<div>Travel Information</div>
<ul>
<li
v-for="(todo, index) in todos"
v-bind:id="index"
v-bind:title="todo"
>{{todo}}</li>
</ul>
</div>
var newData = #Html.Raw(Json.Encode(Model));
// Object returns like { Passenger: "Tom Jones", Airline: "United Airways", Destination: "Atlanta, GA", etc. }
var vm = new Vue({
el: '#components-demo',
data: {
todos: [
{ newData }
]
}
})
In the developer tools in Vue, it lists out the object fine like:
todos: Array [1]
0: Object
Passenger: "Tom Jones"
Airline: "United Airways"
Destination: "Atlanta, GA"
etc.
At the end I'm looking to list out li's containing these items but can't seem to loop through unless I specify exactly each one.
According to the object you say is constructed.
<div id="components-demo">
<div>Travel Information</div>
<ul>
<li v-for="(item, index) in todos" :key="index">{{ item.Passenger }}</li>
</ul>
</div>
To list out dynamic objects using nested loop:
<div id="components-demo">
<div>Travel Information</div>
<ul>
<li v-for="(item, index) in todos" :key="index">
<ul>
<li v-for="(value, key) in item" :key="key">{{ key }} : {{ value }}</li>
</ul>
</li>
</ul>
</div>
You are assigning the object to an array, you can just loop through the object directly https://jsfiddle.net/cckLd9te/4656/
data: {
todos: newData
},