Vue.js 2 components parent child item not defined - javascript

I am new to vue and I am getting the error referenceError: items is not defined. Can anyone see why this happens or give me some pointers?
I think it has something to do with the items not being set on first look at the template.
My code:
<div id="root">
<task-list></task-list>
<template id="my-parent">
<table>
<thead>
<tr>
<th>Name</th>
<th>id</th>
</tr>
</thead>
<tbody>
<tr is="task" v-for="item in items" :item="item"></tr>
</tbody>
</table>
</template>
<template id="my-child">
<tr>
<td></td>
<td>{{ item.name }}</td>
<td>{{ item.id }}</td>
</tr>
</template>
</div>
<script>
Vue.component('task-list', {
template: '#my-parent',
data: function() {
return {
items: []
}
},
methods: {
getMyData: function(val) {
var _this = this;
$.ajax({
url: 'vuejson.php',
method: 'GET',
success: function (data) {
console.log(data);
_this.items = data;
},
error: function (error) {
alert(JSON.stringify(error));
}
})
}
},
mounted: function () {
this.getMyData("0");
}
});
Vue.component('task', {
template: '#my-child',
props: ['item'],
data: function() {
return {
item: {}
}
}
});
new Vue({
el: "#root",
});
</script>

Here is working modified code:
<template id="my-child">
<tr>
<td>{{ item.name }}</td>
<td>{{ item.id }}</td>
</tr>
</template>
<template id="my-parent">
<table>
<thead>
<tr>
<th>Name</th>
<th>id</th>
</tr>
</thead>
<tbody>
<tr is="task" v-for="item in items" :item="item"></tr>
</tbody>
</table>
</template>
<div id="root">
<task-list></task-list>
</div>
And js:
Vue.component('task-list', {
template: '#my-parent',
data: function() {
return {
items: []
}
},
methods: {
getMyData: function(val) {
var _this = this;
_this.items = [{name: '1.name', id: 1}];
}
},
mounted: function () {
this.getMyData("0");
}
});
Vue.component('task', {
template: '#my-child',
props: ['item'],
data: function() {
return {
}
}
});
new Vue({
el: "#root",
});
jsfiddle
It would be much easier to you to work with vue, if you do some tutorials first:)
edit:
And one more thing: if you declare property(item in your case), dont use that name in data.
So, what I did:
- placed templates outside of your root element
- removed "item" from data

You should describe templates outside div#root.
Example
<div id="root">
<task-list></task-list>
</div>
<template id="my-parent">
<table>
<thead>
<tr>
<th>Name</th>
<th>id</th>
</tr>
</thead>
<tbody>
<tr is="task" v-for="item in items" :item="item"></tr>
</tbody>
</table>
</template>
<template id="my-child">
<tr>
<td></td>
<td>{{ item.name }}</td>
<td>{{ item.id }}</td>
</tr>
</template>
Because if they are in #root they are part of vue instance for it, and there is no items in it.
new Vue({
el: "#root",
//no items
});

Related

Uncaught (in promise) TypeError: Cannot use 'in' operator to search for 'path' in undefined

I am a new learner. I am trying to add cart feature using vue. Here is my view name Cart.vue for the cart.
<template>
<div class="page-cart">
<div class="columns is-multiline">
<div class="column is-12">
<h1 class="title">Cart</h1>
</div>
<div class="column is-12 box">
<table class="table is-fullwidth" v-if="cartTotalLength">
<thead>
<tr>
<th>Product</th>
<th>Price</th>
<th>Quantity</th>
<th>Total</th>
<th></th>
</tr>
</thead>
<tbody>
<CartItem
v-for="item in cart.items"
v-bind:key="item.product.id"
v-bind:initialItem="item" />
</tbody>
</table>
<p v-else>You don't have any products in your cart...</p>
</div>
</div>
</div>
</template>
<script>
import axios from 'axios'
import CartItem from '#/components/CartItem.vue'
export default {
name: 'Cart',
components: {
CartItem
},
data() {
return {
cart: {
items: []
}
}
},
mounted() {
this.cart = this.$store.state.cart
},
computed: {
cartTotalLength() {
return this.cart.items.reduce((acc, curVal) => {
return acc += curVal.quantity
}, 0)
},
}
}
</script>
This is the CartItem.vue component that I used:
<template>
<tr>
<td><router-link :to="item.product.get_absolute_url">{{ item.product.name }}</router-link></td>
<td>Rs {{ item.product.price }}</td>
<td>
{{ item.quantity }}
</td>
<td>Rs {{ getItemTotal(item).toFixed(2) }}</td>
<td><button class="delete"></button></td>
</tr>
</template>
<script>
export default {
name: 'CartItem',
props: {
initialItem: Object
},
data() {
return {
item: this.initialItem
}
},
methods: {
getItemTotal(item) {
return item.quantity * item.product.price
}
},
}
</script>
I cannot see any product and the related values in the cart. I am getting this error -
Uncaught (in promise) TypeError: Cannot use 'in' operator to search for 'path' in undefined.
I am unable to find out the mistake in my code. Please help me out. When I am removing the component from the cart.vue, then the error gets eliminated. But I need that component.

How to share data between two component in vuejs with Event Bus

I am trying to implement a global event bus in order to send a variable from component A to component B.
Here is the component A code:
data () {
return {
commandes: [],
}
},
envoyer() {
this.$eventBus.$emit('commande', this.commandes);
},
Here is the component B code:
<template>
<div class="container">
<div class="row justify-content-center">
<!-- Table row -->
<div class="row">
<div class="col-12 table-responsive">
<table class="table table-striped">
<thead>
<tr>
<th>Qté</th>
<th>Produit</th>
<th>Subtotal</th>
</tr>
</thead>
<tbody>
<tr v-for="(commande, index) in commandes" :key="index">
<td>{{ commande.quantite }}</td>
<td>{{ commande.produit_id }}</td>
<td>{{ commande.montant }}</td>
</tr>
</tbody>
</table>
</div>
<!-- /.col -->
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
commande: [],
}
},
methods: {
},
mounted() {
this.$eventBus.$on('commande', (commandes) => {
this.commande = commandes;
console.log(commandes);
})
}
}
</script>
I'm getting this error when component B is displayed:
[Vue warn]: Property or method "commandes" is not defined on the instance but referenced during render.
How to solve this?
In your template you are referencing commandes
<tr v-for="(commande, index) in commandes" :key="index">
but your data doesn't return it, it returns commande
data() {
return {
commande: [],
}
}
Update your data and bus listeners:
data() {
return {
commandes: [],
}
}
...
this.$eventBus.$on('commande', (commandes) => {
this.commandes = commandes;
console.log(commandes);
})

How to Check All table Vue.js

i want create web crud with vue+axios. but i don't understand how create checbox check all use vue use data api, which later for delete all,
I use this method but the data doesn't appear
sorry i just learned vue + axios
https://pastebin.com/iJDPU0AB
<table id="" class="table table-bordered table-striped">
<thead>
<tr>
<th><input type="checkbox" v-model="selectAll"></th>
<th>Name</th>
<th>Position</th>
<th>Office</th>
<th>Age</th>
<th>Start date</th>
<th>Salary</th>
</tr>
</thead>
<tbody id="target_listing">
<tr v-for="tl in target_listing">
<td><input type="checkbox" v-model="selected" :value="user.id" number></td>
<td>{{ tl.id_target_mst_status }}</td>
<td>{{ tl.category }}</td>
<td>{{ tl.first_name }}</td>
<td>{{ tl.last_name }}</td>
<td>{{ tl.revisit }}</td>
<td>{{ tl.visit_status }}</td>
</tr>
</tbody>
</table>
my app.js
var myTable = new Vue({
el: '#target_listing',
data(){
return{
target_listing:null
}
selected: []
},
mounted(){
axios
.get('http://localhost/warna2/public/api/target_listing')
.then(response => (this.target_listing = response.data.data))
.catch(error => {
console.log(error)
this.errored = true
})
},
computed: {
selectAll: {
get: function () {
return this.target_listing ? this.selected.length == this.target_listing.length : false;
},
set: function (value) {
var selected = [];
if (value) {
this.target_listing.forEach(function (user) {
selected.push(user.id);
});
}
this.selected = selected;
}
}
}
})

Vue.js data table only showing data in first column

I am trying to iterate through an object, pulled from database using axios. I am able to make the object show up in my data table, but i am unable to make it break the data to the specified columns
first snippet is the parent component. the tr and td for the actual list i broke out to a separate component but that may need to be fixed.
<template>
<div class="container">
<router-link to="/add" class="btn btn-primary btn-sm float-
right">AddClient</router-link>
<table class="table">
<thead class="thead-dark">
<tr>
<th scope="col">#</th>
<th scope="col">Name</th>
<th scope="col">Type</th>
<th scope="col">Email</th>
<th scope="col">Phone</th>
<th></th>
</tr>
</thead>
<client-info></client-info>
</table>
</div>
</template>
<script>
import ClientInfo from '#/components/clientslistexperience/ClientInfo'
export default {
name: 'ClientsList',
components: {
ClientInfo
},
methods: {
},
}
</script>
enter code here
next is the component iterating through the data to be show in the table
<template>
<div class="client-info">
<tbody>
<tr v-for="(client, index) in clients" v-bind:key="index"
:client="client">
<th scope="row">{{ client.id }}</th>
<td>{{ client.name }}</td>
<td>{{ client.type }}</td>
<td>{{ client.email }}</td>
<td>{{ client.phone }}</td>
</tr>
</tbody>
</div>
import { mapState } from 'vuex'
export default {
name: 'client-info',
props: {
id: Array,
type: String,
name: String,
email: String,
phone: Number,
},
computed: {
...mapState ([
'clients'
])
},
created() {
this.$store.dispatch('retrieveClients')
}
}
</script>
enter code here
last is the vuex store where axios request is being made. now i know using the vuex for smaller projects is over kill but im intending for this to become rather large so this is the method ive chosen. any help would be awesome! Thanks.
import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'axios'
Vue.use(Vuex)
axios.defaults.baseURL = 'http://client-api.test/api'
export default new Vuex.Store({
state: {
clients: []
},
mutations: {
retrieveClients(state, clients) {
state.clients = clients
},
},
actions: {
retrieveClients(context) {
axios.get('/clients')
.then(response => {
// console.log(response)
context.commit('retrieveClients', response.data)
})
.catch(error => {
console.log(error)
})
}
}
})
enter image description here
In fact, you need to remove the div root element in your ClientInfo.vue component.
Replace the div by tbody and it solve your problem ;)
<template>
<tbody class="client-info">
<tr v-for="(client, index) in clients"
:key="index">
<td>{{ client.id }}</td>
<td>{{ client.name }}</td>
<td>{{ client.type }}</td>
<td>{{ client.email }}</td>
<td>{{ client.phone }}</td>
</tr>
</tbody>
</template>
Full demo here > https://codesandbox.io/s/v8vw0z89r7

Add row to one table but not the other with v-for in Vue

I need to add rows in table #dynamic but table static shouldn't be affected.
If I click the button with the code below, both tables will be updated, because they have the same v-for. And, if I put a v-for in a v-for my data won't be fetched. I can't figure out how to "unique" the first table.
vue/html:
<template>
<table id="dynamic">
<tr v-for="rows in list">
<td>Content of row {{ rows.item1 }}</td>
<td>Content of row {{ rows.item2 }}</td>
</tr>
</table>
<div #click="block = !block">click</div>
<table id="static">
<tr v-for="rows in list">
<td>Content of row: {{ rows.item3 }}</td>
<td>Content of row: {{ rows.item4 }}</td>
</tr>
</table>
</template>
js
export default {
data: function () {
return {
list: [],
};
},
props: ['channelId'],
mounted() { },
created() {
this.fetchChannel(this.channelId);
},
methods: {
fetchChannel: function (channelId) {
$.getJSON('/api/channel/' + channelId, function (data) {
this.list = data;
}.bind(this));
},
}
}
I found some examples for help like this codepen or fiddle but I am not successful with it.
If the #static table is truly never meant to update when the its data changes, this would be a case for using the v-once directive:
<table id="static" v-once>
<tr v-for="rows in list">
<td>Content of row: {{ rows.item3 }}</td>
<td>Content of row: {{ rows.item4 }}</td>
</tr>
</table>
This will tell Vue to render the table only once and then ignore it upon any re-renders.
Here's a fiddle.

Categories