How to properly iterate on array of objects in Vue/Nuxt - javascript

<template>
<div>
<h1>Hello World</h1>
<div>
<span :for="day in days">{{ day }} </span>
</div>
</div>
</template>
<script>
export default {
name: 'Hello',
data() {
return {
days: ['Mon', 'Tue', 'Wed', 'Thurs', 'Fri', 'Sat', 'Sun'],
}
},
}
</script>
I am not able to loop through days array. I am getting below error.
Error: [Vue warn]: Property or method "day" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property. See: https://v2.vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties.

Here is a similar question: Nuxt how to loop on an array and display the data properly with a v-for
And same as there, I do recommend generating some ids for properly handling of :key, otherwise you'll get an ESlint error.
<template>
<div>
<h1>Hello World</h1>
<div>
<span v-for="day in days" :key="day.id">
{{ day.name }}
</span>
</div>
</div>
</template>
<script>
export default {
name: 'Hello',
data() {
return {
days: [
{ id: 1, name: "Mon" },
{ id: 2, name: "Tue" },
{ id: 3, name: "Wed" },
{ id: 4, name: "Thurs" },
{ id: 5, name: "Fri" },
{ id: 6, name: "Sat" },
{ id: 7, name: "Sun" },
]
}
},
}
</script>
:key is essential, more info here: https://v2.vuejs.org/v2/style-guide/#Keyed-v-for-essential
Here a blog article explaining this: https://michaelnthiessen.com/understanding-the-key-attribute#dont-use-an-index-as-the-key

You should use v-for directive like :
<span v-for="day in days">{{ day }}</span>
the directives are prefixed by v- and they are bound by default to the component methods and properties

Related

How do I display one object of an array in Vue.JS

Let's say I have this list of objects in Vue.JS
data () {
return{
examples: [
{
exampleID: 5,
exampleText: 'foo'
},
{
exampleID: 3,
exampleText: 'bar'
}
]
}
}
Now let's say I want to display the object with the exampleID of 3 in an element i created before
<Task
v-for="example in examples"
:key="example.exampleID"
:example="example"
/>
I want to display everything, that is in the object (the ID and the text)
Task component :
<template>
<div class="exercise">
<div class="exercise-id">
<h1>ID NUMBER: {{ example.exampleID }}</h1>
</div>
<div class="exercise-task">
<h2>{{ example.exampleText}}</h2>
</div>
</div>
</template>
<script>
export default {
name: 'Task',
props: ['example']
}
</script>
You shouldn't use v-if and v-for in the same element, in this case i suggest to use a computed property that only return the desired example :
data () {
return{
examples: [
{
exampleID: 5,
exampleText: 'foo'
},
{
exampleID: 3,
exampleText: 'bar'
}
]
}
},
computed:{
myExample(){
return this.examples.find(ex=>ex.exampleID===3)
}
}
then render it like :
<Task :example="myExample"/>
Another efficient way of doing it without v-for is
data () {
return{
examples: [
{
exampleID: 5,
exampleText: 'foo'
},
{
exampleID: 3,
exampleText: 'bar'
}
],
id: 3
}
},
computed:{
myExample(){
return id => this.examples.find(ex=>ex.exampleID===id)
}
}
rendering part will be like
<Task :example="myExample(id)"/>
In this way you no need to hardcode the value as 3 in the computed property.

Vue js props no data

I cant pass data to props in VueJS.
Here is my code:
const projects = [{ id: 1, name: 'First', img: "https://randomwordgenerator.com/img/picture-generator/53e0d7414855ac14f1dc8460962e33791c3ad6e04e5074417d2e72d2964cc6_640.jpg" },
{ id: 2, name: 'Second', img: "https://randomwordgenerator.com/img/picture-generator/paper-1100254_640.jpg" },
{ id: 3, name: 'Third', img: "https://randomwordgenerator.com/img/picture-generator/5fe2d4414352b10ff3d8992cc12c30771037dbf85254794075287cd69145_640.jpg" },
{ id: 4, name: 'Forth', img: "https://randomwordgenerator.com/img/picture-generator/5fe1d3414256b10ff3d8992cc12c30771037dbf8525478487c2f79d5924e_640.jpg" }
]
const Project = {
props: ['img', 'name'],
template: `
<div class="container projectbox">
<div class="textandimage"> Name: {{ projects.name }} </div>
</div>
`,
data() {
return {
projects
}
}
}
img:undefined
name:undefined
Please help.
Projects is a list (Array) of Objects. if you want to access an Object in the list, you need to reference its position. for example:
<div class="textandimage"> Name: {{ projects[0].name }} </div>
This will access the first Object in your list, and return the value of the key name
EDIT: for-loop
If you want to loop through the data to the template, do something like this:
<div v-for="(item, index) in projects" class="container projectbox" :key="index">
<div class="textandimage"> Name: {{ item.name }} </div>
</div>
Hope that makes more sense.

vuejs select default option does not work

I have a json data that i've been loading into the <select>
This is a sample json data that I have:
let plans = [{id: 20, name: "test", default: 0},
{id: 19, name: "haha", default: 0},
{id: 18, name: "okok", default: 1}];
This is my select html/vue.
<select id="plans" class="form-control" v-model="company.plan_id">
<option v-for="plan in plans" :value="plan.id" :selected="plan.default">{{plan.name}}</option>
</select>
It seems it doesn't select the "okok" value even if the default is 1.
Those plans data are coming from my database which is loaded using ajax.
I'm new to VueJS, any help is greatly appreciated!
Thanks.
selected attribute no longer makes sense when you using v-model.
You can't use selected attribute if you are using v-model on the <select>, Set the v-model value to the default value instead:
<template>
<div id="app">
<select id="plans" class="form-control" v-model="company.plan_id">
<option v-for="plan in plans" :value="plan.id" :key="plan.id" :selected="plan.default">{{plan.name}}</option>
</select>
</div>
</template>
<script>
export default {
name: "App",
data() {
return {
company: {
plan_id: 18
},
plans: [
{ id: 20, name: "test" },
{ id: 19, name: "haha" },
{ id: 18, name: "okok" }
]
};
}
};
</script>
Demo here: https://codesandbox.io/s/beautiful-sound-gxmzu?file=/src/App.vue

Live filter in custom select with input

I am trying to make a custom list filter on input using computed property. In one file I create a widget, in another I use it. Here is the code from the widget creation file:
<template>
<input value="Гарантийный случай"
v-model="searchText"
:class="{'w-autocomplete__input_completed': completed}"
ref="input"
#click="areOptionsVisible = !areOptionsVisible"/>
<div v-if="areOptionsVisible"
:style="{maxHeight: maxHeight, overflow: 'auto', zIndex: zIndex}"
class="w-autocomplete__items">
<div v-for="option in options" class="w-autocomplete__item_first" >
{{ option.name }}
<div v-for="item in option.children" class="w-autocomplete__item"
:class="{'w-autocomplete__item_active': currentIndex === item}"
#mouseenter="setActive(item)"
#keyup.up="changeCurrent('up', item)"
#keyup.down="changeCurrent('down', item)"
#click="doChoose(item)">
{{ item.name }}
</div>
</div>
</div>
</template>
<script>
export default {
name: 'dropdown',
props: {
placeholder: {
type: String,
required: false,
default: '',
},
options: {
type: Array,
default(){
return []
}
},
},
data: function () {
return {
counter: 0,
currentIndex: null,
completed: false,
chosenItem: null,
areOptionsVisible: false,
searchText: '',
data: [],
}
},
computed: {
options(){
return this.props.options.filter(elem => {
return elem.name.toLowerCase().includes(this.searchText.toLowerCase());
});
},
},
.......
}
</script>
This is how I pass the array to this list in another file:
<template>
........
<div class="complaint-form__line-item">
<div class="form-group">
<label>Гарантийный случай</label>
<dropdown :options="options" />
</div>
</div>
........
</template>
<script>
........
export default {
name: 'complaint-form',
components: {LockedImport, UploadFiles, CarNumberInput, Autocomplete, Dropdown},
props: {
......
}
},
data() {
const complaint = new Complaint();
return {
........
options: [
{name: 'Выход детали из строя в процессе эксплуатации', value: null,
children: [{name: 'Увеличение зазора, люфт (дробь/стуки)', value: 53},
{name: 'Обрыв детали', value: 54}]},
{name: 'Поломка при установке', value: null},
{name: 'Брак до установки', value: null,
children: [{name: 'Недокомплект', value: 55},
{name: 'Заводской брак (замятия, отсутствие резьбы, пробой пыльника и т.д.)',
value: 56}]},
],
}
},
Tell me please why computed doesn't work? Only I add computed and the list is not displayed at all when clicking on the field, but should. That is, it breaks down completely. I want to be filtered when entering text in input
Vue.js cannot have more than one element inside a <template> tag, so I would suggest that you enclose the whole code of the dropdown component within a <div> tag or something of the sort.
Also, and this is just a comment, I would suggest that you use the focus event for the input because with click it will still be showing even if you aren't focusing on the input.

Vue Tables 2 with Slots. How to pass data id to event handler?

I'm using a slot to display a button in Vue Tables 2. How can I pass the id of the warehouse i.e. 123 or 456 to the edit() event handler?
I've tried adding props (as this is what the docs show). But I haven't had any luck. I'm using Vue Tables 2 in a component.
<template>
<div>
<h1>How to pass warehouse id to edit() method?</h1>
<v-client-table :columns="columns" :data="warehouses" :options="options">
<span slot="actions" slot-scope="{ WarehousesMin }">
<button v-on:click="edit">Edit</button>
</span>
</v-client-table>
</div>
export default {
name: 'WarehousesMin',
data() {
return {
warehouses: [
{"id": 123, "name": "El Dorado", "loc": "EDO"},
{"id": 456, "name": "Tartarus", "loc": "TAR"}
],
options: {
headings: {name: 'Name', code: 'Loc', actions: 'Actions'}
},
columns: ['name', 'loc', 'actions'],
}
},
methods: {
edit (warehouseId) {
// How to get id of warehouse here? i.e. 123 or 456
}
}
}
I haven't used this library before, but as far as I know about Vue slots, you can change your code into this and try again:
<template>
<div>
<h1>How to pass warehouse id to edit() method?</h1>
<v-client-table :columns="columns" :data="warehouses" :options="options">
<span slot="actions" slot-scope="{row}">
<button v-on:click="edit(row.id)">Edit</button>
</span>
</v-client-table>
</div>
and in script part, change to:
export default {
name: 'WarehousesMin',
data() {
return {
warehouses: [
{"id": 123, "name": "El Dorado", "loc": "EDO"},
{"id": 456, "name": "Tartarus", "loc": "TAR"}
],
options: {
headings: {name: 'Name', code: 'Loc', actions: 'Actions'}
},
columns: ['id', 'name', 'loc', 'actions'],
}
},
methods: {
edit (warehouseId) {
// The id can be fetched from the slot-scope row object when id is in columns
}
}
}
I think this ought to work, but if not please let me know.

Categories