I am populating a table inside an Axios API call and need to add a delete button to each row.
Im not quite sure how to handle this, in my current experience:
formattedVehicles.push([
"<div class='btn btn-danger' v-on:click='deleteVehicle(id)'>Delete</div>"
]);
Ofcourse, this doesn't work. How do I go about getting a click handler for the delete button to take a parametre and handle it as a method?
In Vue.js you don't have to create div like in jQuery.
Here you have an array of vehicles. The template will update when the array change.
You just need to manage the array of vehicles like this :
new Vue({
el: "#app",
data: function() {
return {
formattedVehicles: [
{ id: 1, name: 'vehi1' },
{ id: 2, name: 'vehi2' },
{ id: 3, name: 'vehi3' }
]
}
},
methods: {
callingAxiosApi: function() {
//---> Inside your '.then(function (response) {' you do:
//---> this.formattedVehicles = response; If response is the array of vehicles
},
addVehicle: function() {
var rand = Math.floor(Math.random() * (100 - 4)) + 4;
this.formattedVehicles.push({ id: rand, name: 'vehi' + rand });
},
deleteVehicle: function(id, index) {
//---> Here you can use 'id' to do an Axios API call.
this.formattedVehicles.splice(index, 1);
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.2.5/vue.js"></script>
<div id="app">
<button #click="addVehicle">Add vehicle</button>
<div v-for="(vehicle, index) in formattedVehicles" :key="index">
id: {{ vehicle.id }}
<br />
name: {{ vehicle.name }}
<button #click="deleteVehicle(vehicle.id, index)">Delete this vehicle</button>
</div>
</div>
To understand the code above :
Use v-for when you have a list to show in html :
v-for="(anyNameYouWantForItemOfArray, index) in yourArray"
Inside the div that contains the v-for you can access the item of the aray : {{ vehicle.id }}, {{ vehicle.name }} or pass data in event handler : #click="deleteVehicle(vehicle.id, index)"
You must use key property in v-for since version 2.2.0+ key :
In 2.2.0+, when using v-for with a component, a key is now required.
To add event handler you just put v-on:click="method" or the shortcut #click="method"
In this case we put <button #click="deleteVehicle(vehicle.id, index)">Delete this vehicle</button> in the v-for so when we clicked on the button, we call the deleteVehicle method with the index of the row. In your case you can use id to do an API call with axios.
We use the v-bind directive to put javascript code in html attribute v-bind :
We are in the v-for so we have access to index variable :
v-bind:key="index" or with the shortcut ':' (a colon) : :key="index"
Related
I'm trying create a follow button on list items in Vue. My strategy is to grab the value of a particular list item property and store it in the data object. Then use this value in a method to add it to an array in my database.
<div v-for="result in results" :key="result.symbol">
{{ result.name }}
<button #click="followStock">+follow</button>
</div>
I'm not sure how to get the value of result.symbol "into" the button element to set the value symbol in the data object below.
<script>
export default {
data() {
return {
results: [ // this is populated by an api call
{
currency: "USD"
exchangeShortName: "NYSE"
name: "International Game Technology PLC"
stockExchange: "NYSE"
symbol: "IGT"
},
{...},
...
],
symbol: "",
};
},
followStock() {
// add this.symbol to database array
},
},
};
</script>
I'm guessing there might be an easier strategy I'm overlooking as I'm still new to Vue, so any other solution that essentially allows me to fire off the value of result.symbol from any rendered result to my database would be awesome.
You can just pass the result as a parameter to your method.
<div v-for="result in results" :key="result.symbol">
{{ result.name }}
<button #click="followStock(result)">+follow</button>
</div>
And in your method:
methods: {
followStock(result) {
// do something with result
console.log({result});
let symbol = result.symbol;
},
}
P.S I didn't see you put your followStock() inside a methods object, but I did so in the example. https://v2.vuejs.org/v2/api/#methods
Write directly as a function call.
The vue compiler will turn followStock(result.symbol) into function(event) {followStock(result.symbol)}.
new Vue({
el: '#app',
data() {
return {
results: [
{
name: "International Game Technology PLC",
symbol: "IGT"
},
{
name: "A name",
symbol: "A symbol"
}
]
};
},
methods: {
followStock(symbol) {
console.log(symbol)
},
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div v-for="result in results" :key="result.symbol">
{{ result.name }}
<button #click="followStock(result.symbol)">+follow</button>
</div>
</div>
As Nazaire mentioned you can access the results anywhere inside the child elements when using v-for.
(it works like a normal for-loop)
It's not only limited to the corresponding element (the element in which you do v-for)
<div v-for="result in results" :key="result.symbol">
{{ result.name }}
<button #click="followStock(result.symbol)">+follow</button>
</div>
followStock(symbol){
// you can now add symbol to db
}
I am having a h1 with v-for and i am writing out things from my array ,it looks like this:
<h1
v-for="(record, index) of filteredRecords"
:key="index"
:record="record"
:class="getActiveClass(record, index)"
>
<div :class="getClass(record)">
<strong v-show="record.path === 'leftoFront'"
>{{ record.description }}
</strong>
</div>
</h1>
as you can see i am bindig a class (getActiveClass(record,index) --> passing it my record and an index)
This is my getActiveClass method:
getActiveClass(record, index) {
this.showMe(record);
return {
"is-active": index == this.activeSpan
};
}
i am calling a function called showMe passing my record to that and thats where the problem begins
the showMe method is for my setInterval so basically what it does that i am having multiple objects in my array and it is setting up the interval so when the record.time for that one record is over then it switches to the next one. Looks like this:
showMe(record) {
console.log(record.time)
setInterval(record => {
if (this.activeSpan === this.filteredRecords.length - 1) {
this.activeSpan = 0;
} else {
this.activeSpan++;
}
}, record.time );
},
this activeSpan is making sure that the 'is-active' class (see above) is changing correctly.
Now my problem is that the record.time is not working correctly when i print it out it gives me for example if iam having two objects in my array it console logs me both of the times .
So it is not changing correctly to its record.time it is just changing very fastly, as time goes by it shows just a very fast looping through my records .
Why is that? how can i set it up correctly so that when i get one record its interval is going to be the record.time (what belongs to it) , and when a record changes it does again the same (listening to its record.time)
FOR EXAMPLE :
filteredRecords:[
{
description:"hey you",
time:12,
id:4,
},
{
description:"hola babe",
time:43,
id:1
},
]
it should display as first the "hey you" text ,it should be displayed for 12s, and after the it should display the "hola babe" for 43 s.
thanks
<template>
<h1 ...>{{ filteredRecords[index].description }}</h1>
</template>
<script>
{
data() {
return {
index: 0,
// ...
};
},
methods: {
iterate(i) {
if (this.filteredRecords[i]) {
this.index = i;
window.setTimeout(() => iterate(i + 1), this.filteredRecords[i].time * 1000);
}
},
},
mounted() {
this.iterate(0);
},
}
</script>
How about this? Without using v-for.
I have below array, that contains a number of columns. Below example contains three columns, but columns can be added/removed dynamically:
[['position', '30'], ['position', '60'], ['position', '90']]
I am facing issues when deleting the correct column (index in array) with Vue.
Consider below snippet:
new Vue({
el: '#app',
data: {
message: 'Hello Vue.js!',
columns: [['position', '30'], ['position', '60'], ['position', '90']]
},
methods: {
deleteColumn: function(index) {
this.columns.splice(index, 1);
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div v-for="(item, index) in columns" :key="index">
Column #: {{index}} - <a #click="deleteColumn(index)">Delete me</a>
</div>
</div>
If you run the above code snippet end try to delete the #1 column, it will actually remove the #2 column (last item of the array). Same goes for #0.
I thought that by providing the index to my deleteColumn function, I could remove the "right" index from the array.
Any help is appreciated.
Just give them a property name and you are done. Notice what I changed here. Columns is no more a 2D array, but objects. Use this.$delete(this.columns, index); to delete the objects.
new Vue({
el: '#app',
data: {
message: 'Hello Vue.js!',
columns: {
'1': {
position: 30
},
'2': {
position: 60
},
'3': {
position: 90
}
}
},
methods: {
deleteColumn: function(index) {
this.$delete(this.columns, index);
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div v-for="(item, index) in columns" :key="index">
Column #: {{index}} - <a #click="deleteColumn(index)">Delete me</a>
</div>
</div>
{
'1': {
position: 30
},
'2': {
position: 60
},
'3': {
position: 90
}
}
Here, '1' is a property name and it's value is another object. It's like giving ids to your data.
The format for value of object is this
{ property_name : value }
Here, value is another object, and in that object, there is another property, named "position" with your corresponding values.
When you clicked any item you are removing it in the right way, your index is your key, that's the problem, but is visually, in the logic it's right. Display your position in your template just for you can see it. ANd for me your data it's not in the right way.
<div id="app">
<div v-for="(item, index) in columns" :key="index">
Column #: {{index}}-{{item.position}} -
<a #click="deleteColumn(index)">Delete me</a>
</div>
</div>
and your script for you can see the change
new Vue({
el: '#app',
data: {
message: 'Hello Vue.js!',
columns: [{position: 30}, {position: 60}, {position: 90}]
},
methods: {
deleteColumn: function(index) {
this.columns.splice(index, 1);
}
}
})
The splice method reindexes the array, moving all elements after the splice point up or down so that any new inserted values will fit and so that the array indices remain contiguous. You can see it more clearly if you also display the values of the items in your list:
new Vue({
el: '#app',
data: {
message: 'Hello Vue.js!',
columns: ['foo', 'bar', 'baz']
},
methods: {
deleteColumn: function(index) {
this.columns.splice(index, 1);
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div v-for="(item, index) in columns" :key="index">
Column #{{index}} = {{item}} - <a #click="deleteColumn(index)" style="cursor:pointer">Delete me</a>
</div>
</div>
Initially, the snippet above will render like this:
Column #0 = foo - Delete me
Column #1 = bar - Delete me
Column #2 = baz - Delete me
If you now click the "Delete me" link on column #0 ("foo"), it will change to:
Column #0 = bar - Delete me
Column #1 = baz - Delete me
You can see that the value "foo" indeed got spliced out of the array — and the values "bar" and "baz" were shifted down by one position to become the new elements #0 and #1.
Anyway, the fix for this problem is simply "don't do that":
If you're using v-for with a simple array whose elements have no natural key value, you can just omit :key entirely and let Vue decide how to best handle changes to the underlying array. As long as the contents within the v-for loop doesn't contain any form inputs or stateful components or other fancy stuff that doesn't react well to the array being reindexed, it should work just fine.
Conversely, if you do have a natural unique key available for each array element, use it. If you don't, but can create one, consider doing that.
You should not use index as the key with CRUD operations since this will confuse Vue when it comes to deleting. The key should be a unique identifier that relates to the data.
You can create a new formatted array of objects on mount with a key generated from the data within the array (note: I haven't tested the code in a browser if there are any mistakes).
<template>
<div>
<div v-for="col in formattedColumns" :key="col.key">
{{ col.value }}
</div>
</div>
</template>
<script>
export default {
data() {
return {
columns: [['position', '30'], ['position', '60'], ['position', '90']],
formattedColumns: null,
};
},
mounted() {
let columns = [];
for (let i = 0; i < this.columns.length; i++) {
columns.push({
value: this.columns[i],
key: this.columns[i][0] + this.columns[i][1],
});
}
this.formattedColumns = columns;
},
};
</script>
Try this this.$delete(this.columns, index) which is the same as Vue.delete(this.columns, index)
https://v2.vuejs.org/v2/api/index.html#Vue-delete
I am new in Vue and still learning using it. I am learning to use the Element UI for Vue UI. Specifically, I'm trying the Input Number Component, for an array of data. Let say I have my data like this:
dataList = [{
id: 1,
productName: "ABC",
qty: 1
}, {
id: 2,
productName: "DEF",
qty: 2
}];
And the element goes like this:
<div v-for="(item, index) in dataList" v-bind:key="item.id">
<el-input-number v-model="item.qty" #change="handleChange"></el-input-number>
</div>
And for the script goes like this:
<script type="text/javascript">
handleChange = function (value) {
console.log(value); /* I need the item.id also not just the qty value */
};
</script>
from the function handleChange() I only can get the value of input number, but not the item id that I've assign in the element. How can I get both of that (item.id and value)?
I was expecting a js function like this could work, but it didnt:
handleChange = function(item, value) { /* */ }
I've been trying to google for some answer, but the answer always showing only 1 parameter that i can acquire from change event.
Any help would be appreciated, thank you.
You could pass your value ($event) as first parameter and the other parameter as the second one :
<div v-for="(item, index) in dataList" v-bind:key="item.id">
<el-input-number v-model="item.qty" #change="handleChange($event,item.id)"></el-input-number>
</div>
Script :
<script type="text/javascript">
handleChange = function (value,id) {
console.log(value,id);
};
</script>
I am using Bootstrap-Vue to display a table, and I've added in an extra column with an update button using vue-slot. I have this displaying fine, and I have a method being called when you click the button. Within that method I can access all the information on the item however I can't seem to find a way to access the button. I want to disable it and change the contents of it. How can I access the button element? I have created a codepen example here that shows what I have set up and need to do.
HTML
<div id='app'>
<div>{{ this.output }}</div>
<b-table hover head-variant="dark"
id="pages-table"
:items="items"
:fields="fields">
<template slot="actions" slot-scope="data">
<button class="btn btn-dark" #click="update(data)">Update</button>
</template>
</b-table>
</div>
JavaScript
new Vue({
el: "#app",
data: {
output: null,
items: [
{
id: 1,
name: "Tony"
},
{
id: 2,
name: "John"
},
{
id: 3,
name: "Paul"
}
],
fields: [
{
key: "id",
label: "ID",
sortable: true
},
{ key: "name" },
{ key: "actions" }
]
},
methods: {
update(data) {
// I need to disable the button here
this.output = data;
data.item.name = "Dave";
}
}
});
You could add a dynamic ref to the button
<button class="btn btn-dark" #click="update(data)" :ref="'btn' + data.index">Update</button>
And then just access the button by that ref
this.$refs["btn" + data.index].disabled = true
This is a codepen with the example
https://codepen.io/vlaem/pen/gNjGQE
Instead of the index you could also use the id property of your data to create the ref (data.item.id)
Though personally this doens't feel right, I think it would be better if we could track the status of all the buttons on the same or a different array, maybe like in the following example
https://codepen.io/vlaem/pen/GbBMLe