Vue.js updating html inside websocket onmessage event

Viewed 942

I am a Vue.js newbie. I am trying to catch data inside websocket's onmessage event and update an HTML component(span or div). console.log or alert functions work in onmessage but couldn't update span.

There is template part at the begining which contains an input box(message), a button fires sendmessage, and a span binded with result.

<template>
  <div id="app">
    <h2>Vue.js WebSocket</h2> 
    <input v-model="message" placeholder="Type command here"/>
    <button v-on:click="sendMessage()">Send Message</button><br><br>
    <span v-text="result"></span>
  </div>
</template>

Here is the script part;

<script>
export default {
  name: 'App',
  
  data: function () {
    return {
      connection:null,
      message:"",
      result:null
    }
  },

  methods: {
    sendMessage: function() {
      console.log("Sent command:" + this.message);
      console.log(this.connection);
      this.connection.send(this.message);
    },
  },

  created: function() {
    console.log("Starting connection to WebSocket Server");
    this.connection = new WebSocket("ws://localhost:3000");
    
    //THAT WORKS
    this.result = "Result of command";

    this.connection.onmessage = function(event) {
      console.log(event);
    }
    this.connection.onopen = function(event) {
      console.log(event);
      console.log("Successfully connected to the echo websocket server...")
    }
    this.connection.onmessage = function(event) {
      //THAT WORKS
      console.log("Resultttt:" + event.data);
      
      //THAT DOESN'T WORK
      this.result = event.data;
    }
    this.connection.onopen = function(event) {
      console.log(event);
      console.log("Successfully connected to the echo websocket server...");
    }
  }
}
</script>
2 Answers

This could be a context problem. Try changing as shown below and see if it works.

this.connection.onmessage = (event) => {
  // no new context ----------------^
  this.result = event.data;
}

or

const v = this;
this.connection.onmessage = function(event) {
  v.result = event.data;
}

The reason for the issue is that the this keyword behaves differently in regular functions() than it does with arrow functions, hence the this keyword would become the WebSocket Object instead of the Vue App.

The solution would be to use arrow functions.

Arrow function

this.connection.onmessage = (event) => {
    // this = Vue App
    console.log(this)

    this.result = event.data;
}

Regular function (using TJs recommendation)

const v = this;
this.connection.onmessage = function (event) {
    // this = WebSocket object
    console.log(this)

    v.result = event.data;
}

Here are a couple of articles that helped me get a better understanding:

Related