I am using v-model="item1" in a form which calls a method AddItem().
<form #submit.prevent="AddItem">
<input type="text" name="items" v-model="item1">
...
The method AddItem sends the input data to the database and also pushes to an array called info[].
This array is defined in data(){...}.
data () {
return {
info: [],
item1: null
}
},
The method,
AddItem(){
db.collection('things').add({
item1: this.item1,
}).then(() => {
this.info.push(this.item1)
}).catch(err => {
console.log(err);
})
}
But the info is also used in a v-for in next in the template just after this form. I thought if the info array was updated that any use of it in the template would also update. But after I successfully send this data to the db and update info, the new item is not visible in v-for iteration in the template.
<li v-for="(item, index) in info" :key="index">
<span class="item">{{ item.item1 }}</span>
</li>
How can I get this for loop to take account of the updated info array?
I am new to vue but guess that maybe I should be using data binding some way.
Solved
I was pushing the value to the info array instead of pushing an object like this,
this.info.push({item1: this.item1})
Try
<li v-for="(item, index) in info" :key="index">
<span class="item">{{ item }}</span>
</li>
The value that you push into the array is a string instead of an object (this.item1).
Also to make it more simple try to only do this in AddItem(). Then you are sure its not a faulth with your backend.
AddItem(){
this.info.push(this.item1)
}
Otherwise your code looks correct. In the future it is always handy to create a fiddle so its easier for others to help you.
Related
I want to access a nested object using v-for in nuxtjs,I have a get request using Axios to an API and response data is stored in a variable named CategoriesData look at the code below.
asyncData(context) {
return axios
.get("https://lavazemesakhteman.com/wp-json/wc/v3/products/categories", {
params: {
per_page: 10,
page: 1,
},
})
.then((res) => {
return {
CategoriesData: res.data,
};
})
.catch((e) => context.error(e));}
at this point, everything is good and all API response is stored in CategoriesData, my problem starts when I want to iterate over the nested object and display or use its property, pay attention to the code below:
<ul>
<li v-for="categories in CategoriesData" :key="categories.id">
{{ categories.name }}
{{ categories.image }}
</li>
</ul>
the result is:
I want to display and use categories.image[0].src for example src only not the whole object, the API response is pictured below:
this is a part of JSON code:
"display": "default",
"image": {
"id": 10443,
"date_created": "2022-04-30T05:45:44",
"date_created_gmt": "2022-04-30T01:15:44",
"date_modified": "2022-04-30T05:46:36",
"date_modified_gmt": "2022-04-30T01:16:36",
"src": "https://lavazemesakhteman.com/wp-content/uploads/2022/04/Benkan-Connections2.jpg",
"name": "Benkan Connections",
"alt": "فروشگاه لوازم ساختمان عرضه کننده محصولاتی باکیفیت و همچنین با بهترین قیمت در تمام کشور هست."
},
when is used categories.image.src:
<ul>
<li v-for="categories in CategoriesData" :key="categories.id">
{{ categories.name }}
{{ categories.image.src }}
</li>
</ul>
I get the below error:
Cannot read properties of null (reading 'src')
You can access nested data using the same . notation you already use to get the first field, so you would need to write something like {{ categories.image.src }}.
<template>
<ul>
<li v-for="category in CategoriesData" :key="category.id">
{{ category.name }}
<img :src="category.image.src">
</li>
</ul>
</template>
Note: You named the variable in your v-for as a plural, while the data it holds is singular. As each item in the list of categories is an individual category.
Going to the API itself, located here: http://lavazemesakhteman.com/wp-json/wc/v3/products/categories
Showed that sometimes your image can be null, hence checking for this exception is a nice thing to do
<img v-if="category.image" :src="category.image.src">
Depending on your project and how it's setup, you could even use Optional Chaining like this
<img :src="category.image?.src">
Otherwise, this uglier form is also available
<img :src="category.image && category.image.src">
<li v-for="(size, index) in sizes" :key="index">{{ size }}</li>
I'm new to VueJS and I'm playing around with Vue Directives. I wanna know where to get the list of :key values in the console log or developer tools. For now, I'm setting it to id attribute and reading it. Appreciate any kind of help
If you're just playing around with it and want to be able to log it to console, you could add a log function to your methods
methods:{
log(..args){
console.log(...args)
}
}
then you can use the log function anywhere and pass it the same value
<li v-for="(size, index) in sizes" :key="index">{{ size }}{{log(index)}}</li>
...but that only works if you can pass the same value to both
Example:
Vue.createApp({
data: () => ({
items: ['a', 'b', 'c']
}),
methods: {
log(...args) {
console.log(...args)
},
},
}).mount("#app");
<script src="https://unpkg.com/vue#3.2.0/dist/vue.global.prod.js"></script>
<div id="app">
<li v-for="(item, index) in items" :key="index">{{ item }}{{log(index)}}</li>
</div>
JSBin and Stackoverflow snippet are below.
I am trying to have a list of input components. If all input components are filled with a value (not blank), then there should be a "new blank field" visible at the end for the user to type into. When he types into it, it should make this field apart of the list above it, maintaining focus in it.
However the problem I'm having is, focus maintains in the new field, and never moves into the array. Here is my code:
JSBIN and stackoverflow snippet - https://jsbin.com/cudabicese/1/edit?html,js,output
const app = new Vue({
el: '#app',
data: {
inputs: [
{ id:'foo', value:'foo' },
{ id:'bar', value:'bar' }
]
},
methods: {
addRow(e) {
this.inputs.push({
id: Date.now(),
value: e.target.value
})
},
deleteRow(index) {
this.inputs.splice(index, 1)
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.0.3/vue.js"></script>
<div id="app">
<ul>
<li v-for="(input, index) of inputs">
<input type="text" v-model="input.value">
</li>
<li v-if="inputs.filter(input => !!input.value).length">
<input type="text" #input="addRow">
</li>
</ul>
</div>
I'd recommend you put the input for the list within a computed function vs directly using the data. The examples at https://v2.vuejs.org/v2/examples/ are a good place to start.
I have v-for looping and elements inside it have :click calling a function. That function is being triggered automatically on every single element on page load!
<li v-if="itemSaved.length > 0" v-for="(item, index) in items" class="list-group-item">
<div class="pull-right m-l">
<i v-if="itemSaved[index] == 'not saved'" class="icon-plus" :click="addItem(item.id)"></i>
<i v-else class="icon-check" :click="removeItem(item.id)"></i>
</div>
</li>
export default {
data: () => ({
itemSaved: [{"id":1, "name":"Jim"},{"id":2, "name":"Max"}]
}),
methods: {
addItem: function(id){
console.log('add item ' + id)
},
removeItem: function(id){
console.log('remove item ' + id)
}
}
}
Basically I get a list of add item 1 and add item 2 in the console log
Should be:
#click="removeItem(item.id)"
Not:
:click="removeItem(item.id)"
When you have :click="removeItem(item.id)" you are actually binding the result of the removeItem(item.id) method call to the click property. Which is why the method executes "automatically".
#click="handler" is a shorthand to v-on:click="handler" - the event handling directive.
:click="handler" is a shorthand to v-bind:click="handler", the property binding directive.
it is possible to remove specific element from lists. i tried this functions for remove element
pop() = remove last element
$remove(index) = not remove any element from lists
remove( index ) = undefined function
unshift( index ) = add new and empty element
splice( index ) = remove all element from index
please help me to remove specific element from lists.
below is my js code
var example2 = new Vue({
el: '#example-2',
data: {
items: [
{ message: 'Foo' },
{ message: 'Bar' },
{ message: 'Bar1' },
{ message: 'Bar2' },
{ message: 'Bar3' },
{ message: 'Bar4' }
]
},
methods : {
removeElement : function(index){
this.items.$remove(index);
}
}
})
below is my HTML code
<ul id="example-1">
<li v-for="(key, item) in items">
{{ item.message }}
<button v-on:click="removeElement(key)">remove</button>
</li>
</ul>
$remove is deprecated in Vue.js 2.0 and replaced by splice as stated in the docs. Make sure you add the 2nd parameter of splice for it to work.
Migration From Vue 1.x - 2.0
methods: {
removeElement: function (index) {
this.items.splice(index, 1);
}
}
You can use Vue.delete if your Vue version is 2.2.0+
Vue.delete(this.items, index);
The $.remove feature has been replaced with $.delete.
You can call it like so:
this.$delete(this.someItems, itemIndex).
It works on Object as well as Array. With objects, you need to use a keyed object. With arrays, you pass in the index of the item you want to delete.
Here is a fiddle example: https://jsfiddle.net/james2doyle/386w72nn/
EDIT
I added an example for an array as well
$delete can use inline in #click:
<ul id="example">
<li v-for="(item, key) in items">
{{ item.message }}
<button #click="$delete(items, key)">remove</button>
</li>
</ul>
https://v2.vuejs.org/v2/api/#vm-delete
Firstly, you should fix the methods key.
Then, you should pass the item to the $remove method, not the index. [ref]
https://jsfiddle.net/790og9w6/
If anyone wonders: $delete has been removed in VueJS 3 ( https://v3-migration.vuejs.org/breaking-changes/introduction.html#removed-apis ). Now it is possible to use javascripts native splice(index, count of objects to be deleted).