How do I get my delete button to delete one row of data? - vue.js

What I am doing wrong?
I am trying to get the delete button to delete one person data.
<li v-for="(person,index) in persons">
<span v-for="value in person"> {{ value }} </span>
</li>
<button #click.native="deleteQuote">
Delete
</button>
data: {
ingredients: ['meat', 'fruit', 'salad'],
persons: [
{name: 'Max', age: 27, color: 'red'},
{name: 'Mit', age: 47, color: 'red'},
{name: 'Foo', age: 37, color: 'red'},
]
},
methods: {
deleteQuote: function(person) {
this.persons.splice(index, 1);
}
}
})

Put button element inside the li tag and remove the native modifier and pass the index as a parameter to the deleteQuote method:
<li v-for="(person,index) in persons">
<span v-for="value in person"> {{ value }} </span>
<button #click="deleteQuote(index)">
Delete
</button>
</li>
the method should be defined with index as a parameter :
methods: {
deleteQuote: function(index) {
this.persons.splice(index, 1);
}
}

Related

Is it possible to make v-for variables dynamic in vue?

<div class="col-3" v-for="n in 5" :key="n">
<h3>Table {{n}}</h3>
<draggable class="list-group" :list="`list${n}`" group="people" #change="log">
<div
class="list-group-item"
v-for="`(element, index) in list${n}`"
:key="element.name"
>
{{ element.name }} {{ index }}
</div>
</draggable>
</div>
Why can't I set the v-for or :list as a concatenated string? Is there any way around this?
Full code:
<template>
<div class="row">
<component
v-for="(component, index) in components"
:key="index"
:is="component"
/>
<div class="col-3" v-for="n in listNumber" :key="n">
<h3>Table {{n}}</h3>
<draggable class="list-group" :list="list${n}" group="people" #change="log">
<div
class="list-group-item"
v-for="(element, index) in list${n}"
:key="element.name"
>
{{ element.name }} {{ index }}
</div>
</draggable>
</div>
</div>
</template>
<script>
import draggable from "vuedraggable";
let id = 1;
export default {
name: "two-lists",
display: "Two Lists",
order: 1,
components: {
draggable,
list:[],
},
data() {
return {
list1: [
{ name: "John", id: 1 },
{ name: "Joao", id: 2 },
{ name: "Jean", id: 3 },
{ name: "Gerard", id: 4 }
]
},
{
list2: [
{ name: "Juan", id: 5 },
{ name: "Edgard", id: 6 },
{ name: "Johnson", id: 7 }
],
listNumber: 3,
}
},
created(){
console.log(this.list);
},
methods: {
add: function() {
this.list.push({ name: "Juan" });
},
replace: function() {
this.list = [{ name: "Edgard" }];
},
clone: function(el) {
return {
name: el.name + " cloned"
};
},
}
};
</script>
It's a bit difficult to understand exactly what you're trying to do but it looks like you're trying to get a specific list in the v-for loop.
One way to fix your issue would be to nest your lists inside of an object in your data like this:
data() {
return {
listNumber: 3,
lists: {
list1: [
{ name: "John", id: 1 },
{ name: "Joao", id: 2 },
{ name: "Jean", id: 3 },
{ name: "Gerard", id: 4 }
],
list2: [
{ name: "Juan", id: 5 },
{ name: "Edgard", id: 6 },
{ name: "Johnson", id: 7 }
],
},
};
And then in your code you can just do lists[`list${n}`] like this:
<div class="col-3" v-for="n in listNumber" :key="n">
<h3>Table {{n}}</h3>
<draggable class="list-group" :list="lists[`list${n}`]" group="people" #change="log">
<div
class="list-group-item"
v-for="(element, index) in lists[`list${n}`]"
:key="element.name"
>
{{ element.name }} {{ index }}
</div>
There is a lot more refactoring and other cleanup you could (and should) probably do but this should at least get you over this hurdle.

Vue Element UI - html inside <el-select>

I would like to implement a select element with different colored-labels for each entry:
My code looks like this:
var Main = {
data() {
return {
selectedState: null,
processStates: [
{
value: 0,
label: 'New',
color: 'ffffff'
},
{
value: 1,
label: 'Ready',
color: 'ff9933'
},
{
value: 2,
label: 'Running',
color: '008000'
},
{
value: 3,
label: 'Rejected',
color: 'cc0000'
},
{
value: 4,
label: 'Terminated',
color: '2E9AFE'
}
]
}
},
methods: {}
}
var Ctor = Vue.extend(Main);
new Ctor().$mount('#app');
#import url("//unpkg.com/element-ui#2.4.4/lib/theme-chalk/index.css");
<script src="//unpkg.com/vue/dist/vue.js"></script>
<script src="//unpkg.com/element-ui#2.4.11/lib/index.js"></script>
<div id="app">
<el-select v-model="selectedState" style="width:200px">
<el-option
v-for="state in processStates"
:key="state.value"
:label="state.label"
:value="state.value"
>
<span>
<el-tag :style="'background-color:#' + state.color"> </el-tag> {{ state.label }}
</span>
</el-option>
</el-select>
</div>
AS you can see, I managed to inject html into the option tag and have the desired result.
However, I would like to have the same html when one option is selected.
Desired result:
Any idea how can I achieve it?
You have to use the prefix slot for this. As done below, also I changed the selectedState to an object, but you can also still use the string value, but then you have to do a lookup to get the color
var Main = {
data() {
return {
selectedState: { color: 'ffffff'},
processStates: [
{
value: 0,
label: 'New',
color: 'ffffff'
},
{
value: 1,
label: 'Ready',
color: 'ff9933'
},
{
value: 2,
label: 'Running',
color: '008000'
},
{
value: 3,
label: 'Rejected',
color: 'cc0000'
},
{
value: 4,
label: 'Terminated',
color: '2E9AFE'
}
]
}
},
methods: {}
}
var Ctor = Vue.extend(Main);
new Ctor().$mount('#app');
#import url("//unpkg.com/element-ui#2.4.4/lib/theme-chalk/index.css");
.el-input--prefix .el-input__inner {
padding-left: 40px;
}
<script src="//unpkg.com/vue/dist/vue.js"></script>
<script src="//unpkg.com/element-ui#2.4.11/lib/index.js"></script>
<div id="app">
<el-select v-model="selectedState" value-key="value" style="width:200px">
<template slot="prefix">
<el-tag class="prefix" :style="`background-color: #${selectedState.color}`"/>
</template>
<el-option
v-for="state in processStates"
:key="state.value"
:label="state.label"
:value="state"
>
<span>
<el-tag :style="'background-color:#' + state.color"> </el-tag> {{ state.label }}
</span>
</el-option>
</el-select>
</div>

vue dynamic vlaue based on multiple data

based on most of vue docs that have mentioned to single parameter,
I used the v-on:mouseover and leave to control style dynamically based on each item color because i need to change each item color by hover based on its color and although I used !important with styles, it doesn't change
<li v-for="item in items" v-bind:key="item.id">
<a class="my-link"
v-on:mouseleave="mouseLeave(item)"
v-on:mouseover="mouseOver(item)">
{{ item.title }}
</a>
</li>
data() {
return {
items: [
{
id: 1,
title: "one",
color: "#ccc"
},
{
id: 2,
title: "two",
color: "#000"
},
{
id: 3,
title: "three",
color: "#c7c7c7"
}
]
}
},
methods: {
mouseOver: function(item){
this.$el.children[0].style.color = 'red !important';
},
mouseLeave: function(item){
this.$el.children[0].style.color = `${item.color} !important`;
}
}
Another approach without using mouseleave and mouseover, only CSS:
Apply the main color with :style for each list item from its data definition. Also add class on the parent element class="list" with the color for hover effect. And finally class="list-item" which inherits color from the parent on hover only. Thus color red is inherit on hover only:
<li v-for="item in items" v-bind:key="item.id" class="list" :style="{ color: item.color }">
<a class="list-item">
{{ item.title }}
</a>
</li>
<style scopped>
.list-item {
color: red;
}
.list-item:hover {
color: inherit !important;
}
</style>
Live example:
new Vue({
el: '#app',
data: {
items: [
{
id: 1,
title: "one",
color: "red",
},
{
id: 2,
title: "two",
color: "green",
},
{
id: 3,
title: "three",
color: "blue",
}
]},
template: `
<div>
<li v-for="item in items" v-bind:key="item.id" class="list" :style="{ color: item.color }">
<a class="my-link list-item">
{{ item.title }}
</a>
</li>
</div>`
})
.list-item {
color: #ccc;
}
.list-item:hover {
color: inherit !important;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">

vue #click not changing class

sorry I'm still new to reactive vue models and updating I'm trying to draw a line through an input element if a box is checked.
so far I have this setup:
data: {
selected: null,
checked: null,
list: [
{
id: 0,
category: 'Bakery',
food: ['bread','muffins','pie']
},
{
id: 1,
category: 'Fruits',
food: ['apple','bananna','orange']
},
{
id: 2,
category: 'Diary',
food: ['cheese','milk','yogurt']
}
],
isHidden: true,
form: {},
},
my html is as follows (this is a single page app)
<li v-for="food in item.food" class="list-group-item">
<input :class="{marked:food == checked}" #click="checked = food" type="checkbox"> {{ food }}</input>
</li>
this is the css i'm trying to implement
.marked{
text-decoration: line-through;
}
I'm not sure what I need to do to my #click to make it work but so far nothing happens and the class is not applied. Can someone give me tips?
An <input> element can't have content.
So you've got this structure:
<input>{{ food }}</input>
But that's misleading as the <input> tag will be closed automatically. What you'll end up with will actually be some text next to a checkbox, not inside it.
You probably want something similar to this:
<label :class="{marked: food === checked}" #click="checked = food">
<input type="checkbox"> {{ food }}
</label>
There are some other problems involving deselection and multiple selections. I've tried to fix those in the example below:
new Vue({
el: '#app',
data: {
checked: [],
list: [
{
id: 0,
category: 'Bakery',
food: ['bread','muffins','pie']
},
{
id: 1,
category: 'Fruits',
food: ['apple','bananna','orange']
},
{
id: 2,
category: 'Diary',
food: ['cheese','milk','yogurt']
}
]
}
})
.marked{
text-decoration: line-through;
}
<script src="https://unpkg.com/vue#2.6.11/dist/vue.js"></script>
<div id="app">
<ul v-for="item in list">
<li v-for="food in item.food" class="list-group-item">
<label :class="{marked: checked.includes(food)}">
<input type="checkbox" v-model="checked" :value="food">{{ food }}
</label>
</li>
</ul>
</div>

bootstrap-vue datatable show row details issue

trying to achieve the same result as https://bootstrap-vue.js.org/docs/components/table#row-details-support
My code:
<b-table ref="propertydata" striped hover
:items="datatable.items"
:fields="datatable.fields"
:current-page="datatable.currentPage"
:per-page="datatable.perPage"
:filter="datatable.filter"
:sort-by.sync="datatable.sortBy"
:sort-desc.sync="datatable.sortDesc"
:sort-direction="datatable.sortDirection"
#filtered="onFiltered">
<template slot="action" slot-scope="row">
<!-- we use #click.stop here to prevent emitting of a 'row-clicked' event -->
<b-button size="sm" #click.stop="row.toggleDetails" class="mr-2">
{{ row.detailsShowing ? 'Hide' : 'Show'}} Details
</b-button>
</template>
<template slot="row-details" slot-scope="row">
<b-card>
<ul>
<li v-for="(value, key) in row.item" :key="key">{{ key }}: {{ value}}</li>
</ul>
</b-card>
</template>
</b-table>
<b-row>
<b-col md="6" class="my-1">
<b-pagination :total-rows="datatable.totalRows" :per-page="datatable.perPage" v-model="datatable.currentPage" class="my-0" />
</b-col>
</b-row>
/* Datatable related */
datatable: {
fields: [
{
key: 'account_id',
sortable: true
},
{
key: 'account_name',
sortable: true
},
{
key: 'property_count',
sortable: true,
},
{
key: 'commission',
sortable: true,
variant: 'success'
},
{
key: 'action',
}
],
items: [],
currentPage: 1,
perPage: 20,
totalRows: 0,
pageOptions: [ 20, 100, 300, 500, 1000, 2000, 3000 ],
sortBy: null,
sortDesc: false,
sortDirection: 'asc',
filter: null
}
computed: {
sortOptions () {
// Create an options list from our fields
return this.datatable.fields
.filter(f => f.sortable)
.map(f => { return { text: f.label, value: f.key } })
}
}, // END COMPUTED
methods: {
onFiltered (filteredItems) {
// Trigger pagination to update the number of buttons/pages due to filtering
this.datatable.totalRows = filteredItems.length
this.datatable.currentPage = 1
}
}, // END METHODS
The result is:
As you can see, the show details is isolated to a single column instead of the full row.
What I want to achieve is for this show details section to be the full row width and if I could click the button to go to a method to call additional data to be displayed here as oppose to the native bootstrap-vue functionality.