Vue.js communication Part 1: single component
4 min read

Vue.js communication Part 1: single component

About the series

Communication in Vue.js is one of the first topics you'll have to learn about. I came from writing Rails front-ends, mostly server-side rendered, and using a little jQuery here and there when I was starting to write Vue.js code.

When you're new to this, it might be complicated to wrap your head around this.
Components are being created separately but need to communicate together.

Outline

  • Vue.js communication: single components
  • Vue.js communication: parent-child components
  • Vue.js communication: any component (using vuex)

Vue.js communication: single components

Single components are pretty straightforward. From my point of view, there are a handful of things you need to know to get you started. It is about how the template and script parts of a Vue component work together. Template and script form one unit and share the same data.

The best part is that you can apply some techniques in parent-child communication later!

Template to script: Events

Use events whenever you want to do something after a user event in the UI. The @click="handleClick" part in the template will call the method handleClick.

<template>
  <button @click="handleClick">
    Tacos?
  </button>
</template>

<script>
export default {
  name: 'SingleComponent',
  methods: {
    handleClick () {
      alert('Tacos!')
    }
  }
}
</script>
<template>
  <button @click="handleClick('Tacos')">
    Tacos?
  </button>
</template>

<script>
export default {
  name: 'SingleComponent',
  methods: {
    handleClick (value) {
      alert(`${value}!`)
    }
  }
}
</script>
You can also pass arguments.
<template>
  <button
    @click="handleClick('Tacos', $event)"
    @mouseenter="handleMouseEnter"
  >
    Tacos?
  </button>
</template>

<script>
export default {
  name: 'SingleComponent',
  methods: {
    handleClick (value, event) {
      alert(`${value}!`)
      console.log('click', event)
    },
    handleMouseEnter (event) {
      console.log('mouse entered', event)
    }
  }
}
</script>
Methods can accept events.

v-for and events

Arguments are helpful when you're using events in a v-for loop. When you click one of the menu entries, the event handler knows which entry has been selected.

<template>
  <button
    v-for="(entry, index) in menu"
    :key="index"
    @click="selectEntry(entry)"
  >
    {{ entry }}?
  </button>
</template>

<script>
export default {
  name: 'SingleComponent',
  computed: {
    menu: ['tacos', 'hot dogs', 'ice cream']
  },
  methods: {
    selectEntry (value) {
      alert(`${value} it is!`)
    }
  }
}
</script>

Those were a few examples. There are way more things you can do with events and handlers. The Vue.js guide explains it very well, and there are new and more advanced options now and then.

Everything about events here:

Script to template: Reactiveness

Using the reactive system is enough in most scenarios since you'll need to change data in the script part of your component, and the template renders according to the data changes.

In this example, the script changes the traffic light every 5 seconds. The template will render every time the value  isGreen changes. No need to even access the template in any way. Note that we can change the data even though the component might not be rendered by now. created will set the interval.

To me, that's mind-blowing when you come from jQuery land. With jQuery, you must select the node and then change the text. With Vue.js, you don't need to worry.

<template>
  <div class="traffic-light">
    isGreen: {{ isGreen }}
  </div>
</template>
<script>
export default {
  name: 'TrafficLight',
  data () {
    return {
      isGreen: false,
      interval: null
    }
  },
  created () {
    this.interval = setInterval(() => {
      this.isGreen = !this.isGreen
    }, 5 * 1000)
  },
  beforeDestroy () {
    clearInterval(this.interval)
  }
}
</script>

Script to template: refs

In some cases, you might need a ref, even in a single component.

Two examples pop into my mind right away:

  • You want to access DOMNode's attributes, e.g., canvas image data or a checkbox's checked value.
  • You want to use another library and pass it the DOMNode.

Here is the canvas example.

<template>
  <div id="canvas-example">
    <canvas ref="canvas" height="200" width="200" />
  </div>
</template>

<script>
export default {
  name: 'CanvasExample',
  mounted () {
    const ctx = this.$refs.canvas.getContext('2d')
    ctx.fillStyle = 'rgb(200,0,0)'
    ctx.fillRect(10, 10, 55, 50)

    ctx.fillStyle = 'rgba(0, 0, 200, 0.5)'
    ctx.fillRect(30, 30, 55, 50)
  }
}
</script>

Dynamic refs

I have realized this way too late, and I'm almost embarrassed. The ref will be treated like any other attribute.

That means you can also pass dynamic values.

That's handy if you have loops.

<template>
  <ul id="dynamic-refs">
    <li
      v-for="entry in entries"
      :key="entry.id"
      :ref="`entry${entry.id}`"
    >
      {{ entry.title }}
    </li>
  </ul>
</template>
<script>
export default {
  name: 'DynamicRefs',
  data () {
    return {
      entries: [
        { id: 1, title: 'Uno' },
        { id: 2, title: 'Due' }
      ]
    }
  },
  mounted () {
    console.log(this.$refs.entry1)
  }
}
</script>

v-model

When building forms, you will want the current data shown in the inputs, and the user's input saved back to the data.

The convention is:

  • Pass the current data  value into the template.
  • Send input events for user inputs.

Whenever you see value and input being used in a component, then: think of v-model.

Both versions of the component behave precisely the same.

<template>
  <input
    :value="name"
    @input="handleNameInput"
  >
</template>
<script>
export default {
  name: 'ValueAndInput',
  data () {
    return {
      name: ''
    }
  },
  methods: {
    handleNameInput (name) {
      this.name = name
    }
  }
}
</script>
what self-written v-model looks like
<template>
  <input v-model="name">
</template>
<script>
export default {
  name: 'ValueAndInput',
  data () {
    return {
      name: ''
    }
  }
}
</script>
using v-model

Final words

I hope you've learned something from this. Feel free to use the comments below if you need help, feel I could have covered something in more detail, or if you want to say hi!
The following article will be about parent-child component communication. This is where it becomes more interesting. We can apply what we've learned here to child components.
I'll let you know when it's ready in my newsletter. Sign up if you want to learn more.