Vue.js $remove not removing element after deleted from database - javascript

I am using Laravel and trying to learn Vue.js. I have a delete request that is working properly and deleting the object from the database. The problem is that it is not being removed from the DOM after the successful deletion. I am using the $remove method and passing it the full object, so I know I'm missing something.
As a side note, I have a main.js as an entry point with a PersonTable.vue as a component. The PersonTable.vue holds the template and script for that template.
Here is my Laravel view:
<div id="app">
<person-table list="{{ $persons }}">
</person-table>
</div>
And here is my `PersonTable.vue:
<template id="persons-template">
<div class="container">
<div class="row">
<div class="col-sm-12">
<h1>Persons List</h1>
<table class="table table-hover table-striped">
<thead>
<tr>
<td>First Name</td>
<td>Last Name</td>
<td>Email</td>
<td>Gender</td>
</tr>
</thead>
<tbody>
<tr v-for="person in list">
<td>{{person.first_name }}</td>
<td>{{person.last_name }}</td>
<td>{{person.email }}</td>
<td>{{person.gender }}</td>
<td><span #click="deletePerson(person)">X</span>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</template>
<script>
export default {
template: '#persons-template',
props: ['list'],
methods: {
deletePerson: function(person) {
this.$http.delete('/person/' + person.id).then(
function(response) {
this.persons.$remove(person);
}
);
}
},
created: function() {
this.persons = JSON.parse(this.list);
}
};
</script>
And my main.js entry point:
var Vue = require('vue');
Vue.use(require('vue-resource'));
var Token = document.querySelector('meta[name="_token"]').getAttribute('content');
Vue.http.headers.common['X-CSRF-TOKEN'] = Token;
import PersonTable from './components/PersonTable.vue';
new Vue({
el: '#app',
components: { PersonTable },
})

I think you need to bind this to the response function:
function(response) {
this.persons.$remove(person);
}.bind(this)
That way when you do this.persons you are still referring to the Vue component
edit: could try -
props:['personJson'],
data:function(){
return {
persons:[]
}
},
ready:function(){
this.persons = JSON.parse(this.personJson)
}
Thinking maybe since persons is a string initially, Vue isn't binding the reactive capabilities properly?

I think that you need to use the this.$set in your created method, if you don't, I am afraid that Vue would lose reactivity.
In your created method, could you try the following:
export default {
template: '#persons-template',
props: ['persons'],
methods: {
deletePerson: function(person) {
var self = this;
this.$http.delete('/person/' + person).then(
function(response) {
self.persons.$remove(person);
}
);
}
},
created: function() {
this.$set('persons',JSON.parse(this.persons));
}
};

Finally figured it out. I needed to pass the JSON data to my data property of the component. Here is the code.
In the blade file:
<div id="app">
<person-table list="{{ $persons }}">
</person-table>
</div>
In my PersonTable.vue file:
<template id="persons-template">
<div class="container">
<div class="row">
<div class="col-sm-12">
<h1>Persons List</h1>
<table class="table table-hover table-striped">
<thead>
<tr>
<td>First Name</td>
<td>Last Name</td>
<td>Email</td>
<td>Gender</td>
</tr>
</thead>
<tbody>
// Notice how I am using persons here instead of list
<tr v-for="person in persons">
<td>{{person.first_name }}</td>
<td>{{person.last_name }}</td>
<td>{{person.email }}</td>
<td>{{person.gender }}</td>
<td><span class="delete person" #click="deletePerson(person)"><i class="fa fa-close"></i></span>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</template>
<script>
export default {
template: '#persons-template',
props: ['list'],
data: function() {
return {
persons: []
}
},
methods: {
deletePerson: function(person) {
this.$http.delete('/person/' + person.id).then(
function(response) {
this.persons.$remove(person);
}
);
},
},
created: function() {
// Pushing the data to the data property so it's reactive
this.persons = JSON.parse(this.list);
},
};
</script>
Thanks to everyone for their contributions. I almost ditched Vue because of how long it has taken to fix this error.

Related

Button that adds a new row when clicked in Vue 3

First I must say that I'm a complete newbie in coding and Vue it's the first framework I'm learning and I'm terrible working with arrays at the moment. In the practice I am doing I am displaying the first five elements of the array in a table (I've filtered them in a new variable to do the v-for).
Now I need to add a button that when clicked will show me a new row of the original array, but I'm a bit stuck on how to do it. As u may see in the code below, contactList is the variable that has all the data, but I have no clue how to link it to the filtered one to show more data when clicked.
<template>
<h1 class="display-1 text-primary">Contacts</h1>
<button type="button" class="btn btn-outline-primary btn-lg" #click="addRandom">Add random</button>
<div class="container container__pos">
<table class="table table-hover">
<thead>
<tr>
<th class="col col__style">Picture</th>
<th class="col col__style">Name</th>
<th class="col col__style">Popularity</th>
<th class="col col__style">Won an Oscar</th>
<th class="col col__style">Won an Emmy</th>
</tr>
</thead>
<tbody>
<tr v-for="(element, index) of contactListed" :key="index">
<td scope="row">
<img
:src="element.pictureUrl"
:alt="element.name + ` image`"
class="image"
/>
</td>
<td> {{ element.name }}</td>
<td>{{ element.popularity }}</td>
<td>{{ wonAward(element.wonOscar) }}</td>
<td>{{ wonAward(element.wonEmmy) }}</td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
import contacts from "./contacts.json";
export default {
data() {
return {
contactList: contacts,
contactListed: contacts.slice(0, 5),
};
},
methods: {
wonAward(element) {
if (element === true || element === true){
return "winner";
} else {
return "";
}
},
},
};
</script>
You can use a computed variable that holds the first N elements of the array, and have your button increment the value of N, like this:
<script>
import contacts from "./contacts.json";
export default {
data() {
return {
contactList: contacts,
nItems: 5
};
},
computed: {
contactListed() {
return this.contacts.slice(0, this.nItems)
}
},
methods: {
addRow() {
this.nItems++;
},
wonAward(element) {
if (element === true || element === true){
return "winner";
} else {
return "";
}
},
},
};
</script>
<template>
...
<button #click="addRow()" />
</template>

How to do pagination in Vue.js table?

I have a web app, frontend using Vue.js, backend using Django.
How could I do pagination in my Vue.js table?
I have tried jQuery DataTable but it's pagination loads very slow, which could not meet user's requirements.
<div id="app">
<form ref="form" id="myform" method="post" action="/tag_course/">
<table id="myTable">
<thead>
<tr>
<th>Course Material Title</th>
</tr>
</thead>
<tbody>
<tr v-for="(row, index) in filteredRows" :key="`isbn-${index}`">
<td v-html="highlightMatches(row.title)">{{ row.title }}</td>
</tbody>
</table>
</form>
</div>
<script>
var book_rows = [{title: query_results_book[0].fields.title}]
const app = new Vue({
el: '#app',
data:() => ({
filter: '',
rows: book_rows
}),
computed: {
filteredRows() {
return this.rows.filter(row => {
const author =
String(row.author).toString().toLowerCase();
const title = String(row.title).toLowerCase();
const searchTerm = this.filter.toLowerCase();
return title.includes(searchTerm) ||
author.includes(searchTerm);
});
}
},
});
</script>

Displaying JSON data on condition using V-for and V-if in Vue.js

I am fetching data(Orders) from external Api in Vue using axios. I obtain JSON data and i am able to show it in a HTML table. Now i am trying filter the data to show only related data to use. In my Json data, i have a field called "order status: Completed / processing". Now i only want to show the json data which are have status like "Processing" to achieve my goal.
I am trying to use v-if with v-for but I m unable to get the certain orders data and view.
The table is set to update for each minute.
Here is my code:
html code
**<div class ="container mt-4" id="app">
<table class="table table-bordered">
<thead>
<tr>
<th scope="col">Order id</th>
<th scope="col">Name</th>
<th scope="col">Order Date</th>
<th scope="col">Phone</th>
<th scope="col">Address</th>
<th scope="col">Items</th>
<th scope="col">Total</th>
<th scope="col">Print</th>
</tr>
</thead>
<tbody>
<tr
v-for="(order, index) in orders" v-if="order.status === "processing""
:key="order.id"
:class="{highlight: !order.is_printed}"
>
<td>{{ order.id }}</td>
<td>{{ order.billing.first_name + " " +order.billing.last_name }}</td>
<td>{{ order.date_created }}</td>
<td>{{ order.billing.phone}}</td>
<td>{{ order.billing.address_1 + ", " + order.billing.address_2 + ", " + order.billing.city + order.billing.postcode }}</td>
<td>{{ order.line_items[0].name}} </td>
<td>{{ order.total}}</td>
<td><button class="btn btn-primary" #click="printBill(order)">Print</button>
</tr>
</tbody>
</table>**
Vue
<script>
var app = new Vue({
el: '#app',
data: {
orders: []
},
mounted: function() {
// API Call function to be implemented here....
</script>
I think this should do the trick.
According to Vue documentation it's best to put any logic into computed properties https://v2.vuejs.org/v2/guide/computed.html
new Vue({
el: "#app",
data: {
orders: [
{ id: 1, status: "processing"},
{ id: 2, status: "other" }
]
},
computed: {
filteredOrders() {
return this.orders.filter(order => order.status === 'processing');
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<table>
<thead>
<tr>
<th scope="col">Status</th>
</tr>
</thead>
<tbody>
<tr v-for="order in filteredOrders" :key="order.id">
<td>{{ order.status }}</td>
</tr>
</tbody>
</table>
</div>
its better to filter data after you get them from api.
based on vue.js document it’s not recommended to use v-if and v-for together, read this:
https://v2.vuejs.org/v2/guide/list.html#v-for-with-v-if
try this
let filteredData = this.orders.filter(order => order.status === "processing")

Vue.js Data binding issue

I am trying to bind data in my userDetails array through post request but i did not get the data , i had tried all the possible solution given in stackoverflow and also in vue.js docs but nothing helps me here is my code.
ND.user_list = new Vue({
el: '#user_list',
data: {
userDetails: []
},
mounted: function () {
$.post(ND.routes['users.get'], [], function(data) {
//console,log(data);
this.$set(this, 'userDetails', data);
//this.usersDetails = data;
}.bind(this), 'json');
//onsole.log(this.userDetailsdata);
}
});
i am getting data in console log in mounted function but not getting in userDetails array declare in data. here is my view code
<div class="ui grid container" id="user_list">
<table class="ui celled padded table">
<thead>
<tr>
<th colspan="6">Top Users</th>
</tr>
</thead>
<thead>
<tr>
<th class="ui center aligned">#</th>
<th class="ui center aligned">Name </th>
<th class="ui center aligned">Email </th>
<th class="ui center aligned">User Type</th>
<th class="ui center aligned">Action </th>
</tr>
</thead>
<tbody>
{% verbatim %}
<tr v-for="user in userDetails">
<td>1</td>
<td class="single line">{{ user.email }}</td>
<td class="ui center aligned "></td>
<td class="ui center aligned "></td>
<td class="ui center aligned ">
<select class="ui dropdown">
<option value=" ">Action </option>
<option value="1">Edit</option>
<option value="0">Delete</option>
</select>
</td>
</tr>
{% endverbatim %}
</tbody>
</table>
</div>
Thanks in advance.
The this in the callback fo $.post() does not refer to the VueJS instance. This means that this.userDetails actually will return undefined within the callback. What you can do is to create a proxy for the VueJS instance as such:
ND.user_list = new Vue({
el: '#user_list',
data: {
userDetails: []
},
mounted: function () {
// Proxy `this`
var that = this;
$.post(ND.routes['users.get'], [], function(data) {
// `that` will refer to VueJS instance
that.userDetails = data;
}, 'json');
}
});
You are using this.$set wrong: it should only be used when you got an object in the data object and want to add properties to that object that wasn't there before, or if you want to change indexes of the array. Then first argument should not be the vue object, but the data object (i.e. the object or array in the data object). See documentation here: https://v2.vuejs.org/v2/guide/reactivity.html or https://v2.vuejs.org/v2/api/#Vue-set.
Instead of: this.$set(this, 'userDetails', data); you should just do this.userDetails = data;. Have you tried this? Also, if you change elements in the array, then you should use Vue.set or splice, but read the documentation carefully before you use it.

Using v-bind to put data into a tag a in the property href (VUE.JS 2 + Laravel 5.3)

Here is my javascript/vue.js code:
import _ from 'lodash'
export default{
props:['campanha'],
data (){
return{
list:[],
filter: '',
href: '/campanha/9/edit'
}
},
methods:{
url: function (href){
return '/campanha/'+this.href+'/edit'
}
},
mounted: function (){
this.list = JSON.parse(this.campanha)
},
computed: {
filteredCampanhas(){
var self = this
return this.list.filter(function(campanhas) {
return campanhas.nome.indexOf(self.filter) > -1
})
}
}
}
And here it`s my html:
<template>
<div>
<div class="well">
Novo Cadastro <span class="glyphicon glyphicon-plus" aria-hidden="true"/><br></br>
<input type="text" class="form-control" placeholder="Filtrar Campanhas" v-model="filter">
</div>
<div class="table-responsive">
<table class="table table-borderless">
<thead>
<tr>
<th>Id</th>
<th>Nome</th>
<th>Data Início</th>
<th>Data Término</th>
<th>Hora Inícío</th>
<th>Hora Término</th>
</tr>
</thead>
<tbody>
<!--{{ url('/campanha/' . $item->id_campanha . '/edit') }}
href: '/campanha/9/edit'
<td><a v-bind:href="href">{{ c.nome }}</a></td>
!-->
<tr v-for="c in filteredCampanhas">
<td>{{ c.id_campanha }}</td>
<td><a :href="url(c.id_campanha)">{{ c.nome }}</a></td>
<td>{{ c.data_inicio }}</td>
<td>{{ c.data_termino }}</td>
<td>{{ c.hora_inicio }}</td>
<td>{{ c.hora_termino }}</td>
</tr>
</tbody>
</table>
</div>
<div>
</template>
I have tried to put some data into href section of my tag a, to link to another page, but it`s not working.
Try following:
methods:{
url: function (href){
return '/campanha/'+ href+'/edit'
}
},
When you are using this.href it will start to pick href from data of vue instance,

Categories

Resources