S
S
Sasha2018-06-28 10:39:03
Vue.js
Sasha, 2018-06-28 10:39:03

Vue component interaction: Property or method "updatebalance" is not defined?

Hey! I'm using Laravel + Vue JS 2 . There are 2 vue components - the order button ( Order.vue ) and the balance label ( Balance_label.vue ). They exchange events through the Event Bus (that is, they do not obey each other, like a parent-child, but are on the same level). Clicking on the Order button fires the updbalance event , which listens to the Balance_label.vue component and executes the updatebalance method when it occurs . As a result, after the order, the balance is written off and the balance label is immediately updated without reloading the page (implemented via axios).
In npm run dev modethey work as intended: they press the button - the balance is immediately updated, only there is a problem - 2 warnings appear in the Browser Console:
[Vue warn]: Property or method "updatebalance" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property. See: https://vuejs.org/v2/guide/reactivity.html#Declari... (found in )
[Vue warn]: Invalid handler for event "updbalance": got undefined found in ---> at resources/ assets/js/components/Balance_label.vue
It would be possible to skip these warnings, because everything works well. But in npm run production modethe web page is empty (no visible component), and in the Browser Console there is an error:
ReferenceError: updatebalance is not defined at dn.eval (eval at Ca (app.js:1), :3:465) at dn.t. _render(app.js:1) at dn. (app.js:1) at Ie.get (app.js:1) at new Ie (app.js:1) at app.js:1 at dn.$mount (app.js:1) at dn.$ mount (app.js:1) at dn.t._init (app.js:1) at new dn (app.js:1)

Details of all files with code below

Лейбл баланса "Balance label" рендерится так на html-страничке:
<balancelabel @updbalance="updatebalance"></balancelabel>

Кнопка заказа "Order":
<order
           :product={{ $product->id }}
           :ordered={{ $product->ordered() ? 'true' : 'false' }}
           productname= "<b>{{ $product->name }}</b>"
></order>

Balance_label.vue
<template> 
        <label id="balance_view" class="btn btn-default tp-icon chat-icon">
                    {{ balance }}  dollars     
        </label>
</template> 

<script>
    import { bus } from '../bootstrap';
    import 'vuejs-noty/dist/vuejs-noty.css'
    export default {

        data: function () {
            return {
                balance: 0
            }    
        },

        created(){
            bus.$on('updbalance', (data) => {
               this.updatebalance(); 
            });
        },
        mounted : function() {
            this.updatebalance();
        },

       methods: {

            updatebalance: function (){
            axios
                .get('/api/v1/balance')
                .then(response => {
                    this.balance = response.data.data[0][0]
                })        
                .catch(response => console.log(response.data));
             },
        }
    };
</script>

Order.vue
<template> 
        <span>
            <button v-if="isOrdered" 
                @click.prevent="unOrder(product)" 
                type="button" 
                class="btn btn-block btn-warning btn-xs" 
                name="order-button">
                    <i class="fa fa-heart"></i>&nbsp; Cancel Order
            </button>
            <button v-else-if="!isOrdered" 
                @click.prevent="order(product)" 
                type="button" 
                class="btn btn-block btn-success btn-xs" 
                name="order-button">
                    <i class="fa fa-heart-o"></i>&nbsp; Order
            </button>
       </span>    
 </template> 

<script>
    import { bus } from '../bootstrap';
    import 'vuejs-noty/dist/vuejs-noty.css'
    export default {
        props: ["product", "ordered", "productname", "resp"],

        data: function() {
            return { 
                isOrdered: '',
            }
        },

        mounted() {
            this.isOrdered = this.isOrder ? true : false;
        },
        computed: {
            isOrder() {
                return this.ordered;
            },
         },
        methods: {

            order(product) {
            axios
                .post('/order/' + product)
                .then(response => {this.isOrdered = true;
                                   this.$noty.success("The product " + this.productname + " is Ordered!");
                                   bus.$emit('updbalance'); //send update balance event
                                   })
               .catch(response => console.log(response.data));
            },

            unOrder(product) {
             axios
                .post('/unorder/' + product)
                .then(response => {this.isOrdered = false;
                                   this.$noty.warning("The product order " + this.productname + " cancelled"); 
                                   bus.$emit('updbalance'); //send update balance event
                                   })
                .catch(response => console.log(response.data));
            }
         }
    };
</script>

app.js
require('./bootstrap');
window.Vue = require('vue');

Vue.component('order', require('./components/Order.vue'));
Vue.component('balancelabel', require('./components/Balance_label.vue'));

app = new Vue({
    el: '#app',
});

bootstrap.js
window._ = require('lodash');
try {
      require('bootstrap-sass');
} catch (e) {}

window.axios = require('axios');
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';

let token = document.head.querySelector('meta[name="csrf-token"]');

if (token) {
    window.axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content;
} else {
    console.error('CSRF token not found: https://laravel.com/docs/csrf#csrf-x-csrf-token');
}

window.Vue = require('vue');
window.events = new Vue();

import Vue from 'vue'
import VueNoty from 'vuejs-noty'

//connect event bus
export const bus = new Vue();

Vue.use(VueNoty)

package.json
{
  "private": true,
  "scripts": {
    "dev": "npm run development",
    "development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
    "watch": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
    "watch-poll": "npm run watch -- --watch-poll",
    "hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js",
    "prod": "npm run production",
    "production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
  },
  "devDependencies": {
    "axios": "^0.17",
    "bootstrap-sass": "^3.3.7",
    "cross-env": "^5.2.0",
    "jquery": "^3.2",
    "laravel-mix": "^1.0",
    "lodash": "^4.17.4",
    "vue": "^2.5.16"
  },
  "dependencies": {
    "noty": "^3.2.0-beta",
    "sweetalert": "^2.1.0",
    "vuejs-noty": "^0.1.3"
  }
}


Googling and reading the Stackoverflow forums, vuejs forum did not give anything.
Everywhere they solve the problem in the case of using properties, not methods.
Here they write that it is necessary to add a method declaration to the parent component, but I do not have a "parent-child" scheme, since they communicate through the event bus (Event bus).
The steps I took to solve the problem myself, which did not help:
  • declaration of the "updatebalance" method in the root Vue instance ( app.js file )
  • declaration of "updatebalance" method in Event bus instance of Vue ( bootstrap.js file )
  • declaration of the "updatebalance" method in the Order.vue component

Answer the question

In order to leave comments, you need to log in

1 answer(s)
0
0xD34F, 2018-06-28
@lipasite

<balancelabel @updbalance="updatebalance"></balancelabel>

Why is there an event handler here? You handle this event inside the component, you don't do emit... Maybe, I don't know, REMOVE it?!

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question