Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

shealan's avatar

Trying my first Vue 2.0 + Vueify

I've been playing with Vue on jsfiddle for a while, so thought I would drop an example app into a new Laravel project and try the Gulp/Vueify pipeline.

I'm getting errors and I am a bit too new to understand where I am going wrong. Would really appreciate some pointers.

app.js

var bus = new Vue();

Vue.component('cart', require('./components/Cart.vue'));

const app = new Vue({
  el: '.container',
  data: function() {
    return {
      quantity: 0
    };
  },
  created: function() {
    // store this to use with Vue.set
    var temp = this;
    // on number event set data
    bus.$on('event-qty-changed', function (qtyNew) {
      // vm.$set deprecated
      Vue.set(temp, 'quantity', qtyNew);
    })
  },
  computed:{
    gold: function(){
      return this.quantity * 200;
    }
  }
});

Cart.vue

<template>
    <div>
      <h2>How many gems would you like to buy?</h2>
      <p>1 emerald costs 100 pieces of gold.</p>
      <input type="number" v-model="quantity" class="form-control">
    </div>
</template>

<script>
    export default {
      data () {
        return {
            quantity : 0
        }
      },
      watch: {
        'quantity': function (qtyNew, qtyOld) {
          console.log('quantity changed from %s to %s', qtyOld, qtyNew);
          bus.$emit('event-qty-changed', qtyNew);
        }
      }
    }
</script>

index.blade.php

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Laravel</title>
        <link rel="stylesheet" href="{{ elixir('css/app.css') }}">
    </head>
    <body id="app">
        <div class="container">
            <h1>Gem Market</h1>
            <hr>
            <cart></cart>
            <hr>
            <h3>You have to pay <strong>@{{ gold }}</strong> pieces of gold.</h3>
        <div>
        <script src="/js/app.js"></script>
    </body>
</html>

Errors: vue.js?3de6:2611[Vue warn]: Templates should only be responsible for mapping the state to the UI. Avoid placing tags with side-effects in your templates, such as . [Vue warn]: Error in watcher "quantity" (found in component at /home/vagrant/vueplay/resources/assets/js/components/Cart.vue) Uncaught (in promise) ReferenceError: bus is not defined(…)

0 likes
5 replies
gabrielbuzzi's avatar

Ok something you will need to change

First the import, you can use ES6 import, this is the best way to import components with vueify and you will need to import Vue too

Change

Vue.component('cart', require('./components/Cart.vue'));

to

import Vue from 'vue'
import Cart from './components/Cart.vue'

and you need to add this item in your Vue object

render: h => h(Cart) // the same as function (h) { return h(Cart) }

Other thing, the issue is refering that bus is not defined in the Cart component, so i think you should change for "this"

I think this should resolve the issue.

shealan's avatar

@gabrielbuzzi thank you very much. That fixed the first error about "mapping the state".

I have taken out the bus and used this instead. I am no longer getting an error but the number isn't being updated as the listener isn't being triggered.

I tried adding the render bit you mentioned but that just resulted in my entire page being replaced with my cart component code?

New code:

app.js

import Vue from 'vue'
import Cart from './components/Cart.vue'

const app = new Vue({
  el: '.container',
  components: {
    Cart
  },
  data: function() {
    return {
      quantity: 0
    };
  },
  created: function() {
    // on number event set data
    this.$on('event-qty-changed', function (qtyNew) {
      // vm.$set deprecated
      Vue.set(this, 'quantity', qtyNew);
    })
  },
  computed:{
    gold: function(){
      return this.quantity * 200;
    }
  }
});

Cart.vue

<template>
    <div>
      <h2>How many gems would you like to buy?</h2>
      <p>1 emerald costs 100 pieces of gold.</p>
      <input type="number" v-model="quantity" class="form-control">
    </div>
</template>

<script>
    export default {
      data () {
        return {
            quantity : 0
        }
      },
      watch: {
        'quantity': function (qtyNew, qtyOld) {
          console.log('quantity changed from %s to %s', qtyOld, qtyNew);
          this.$emit('event-qty-changed', qtyNew);
        }
      }
    }
</script>

index.blade.php

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Laravel</title>
        <link rel="stylesheet" href="{{ elixir('css/app.css') }}">
    </head>
    <body>
        <div class="container">
            <h1>Gem Market</h1>
            <hr>
            <cart></cart>
            <hr>
        <div>
        <h3>You have to pay <strong>@{{ gold }}</strong> pieces of gold.</h3>
        <script src="/js/app.js"></script>
    </body>
</html>
gabrielbuzzi's avatar
Level 8

@shealan Not sure but change this (instanciate this in a var)

created: function() {
    var vm = this
    vm.$on('event-qty-changed', function (qtyNew) {
      // vm.$set deprecated
      Vue.set(vm, 'quantity', qtyNew);
    })
  },

Add $root before $emit

   watch: {
        'quantity': function (qtyNew, qtyOld) {
          console.log('quantity changed from %s to %s', qtyOld, qtyNew);
          this.$root.$emit('event-qty-changed', qtyNew);
        }
      }

Let me know if it works now.

shealan's avatar

That's it, it's updating as expected now. Makes sense too as the cart is now a sub component. Thank you very much.

I just noticed the original error about "mapping the state to the UI" remains without that render method you mentioned. However as I said using it overwrites my whole page with the cart template code.

The error is not actually breaking anything, but any idea what may be happening there?

gabrielbuzzi's avatar

@shealan The render is just like the method template from a component, i setted that you vue applications will render the Cart.vue as the first component, in always create a App.vue component that is like a layout of my app and use vue-router to change the component is showing.

In this case you can create a App.vue that have just the Vue el(#app) and import the cart inside and other components

e.g.

main.js

import Vue from 'vue'
import App from './App.vue'

new Vue ({
    el: '#app',

    render: h => h(App)
})

App.vue

<template>
    <div id="#app">
        <h1>VueJS Applications</h1>

        <h2>This is the cart</h2>
        <Cart></Cart>
    </div>
</template>

<script>
    import Cart from './components/Cart.vue'

    export default {
        name: 'App',

        components: { Cart }        
    }
</script>

Please or to participate in this conversation.