How to Extend a Vuex Plugin with a Custom Function?

I have recently started learning Vue and I just finished creating my first application. I'm using vuex and have a webSocket plugin to handle communication with the server. Initially, everything was working fine with messages sent from the server to the browser.

Now, I want to add a feature to send messages through the socket when connected, but I am struggling to access the exported function. My experience with JavaScript programming is also limited, as I am still a beginner in this field.

Below is the code for the webSocket plugin:


var store = null;
var ws = null;

function startWebsocket() {
    ws = new WebSocket(process.env.VUE_APP_WEBSOCKET_URL)
    ws.onmessage = function (event) {
        console.log("webSocket: on message: ", event.data);
        store.dispatch('remoteMessage', event.data);
    }
    ws.onopen = function (event) {
        console.log("webSocket: on open: ", event)
        store.dispatch('connectionOpened');
    }
    ws.onclose = function (event) {
        console.log("webSocket: on close: ", event)
        store.dispatch('connectionClosed');
        ws = null
        setTimeout(startWebsocket, 5000)
    }    
    ws.onerror = function (event) {
        console.log("webSocket: on error: ", event)
    }
}

export default function createWebSocketPlugin() {
    return store_param => {
        store = store_param;
        startWebsocket();
    };
}

I would like to enhance the plugin by adding the following function, so that I can call it from a vuex action:

export function sendWebSocketMsg(msg) {
    if (ws) {
        ws.sendMsg(msg)
    }
}

In the vuex index.js file, I have included the following:

. . .
import webSocket from '../plugins/webSocket'
. . .
export default new Vuex.Store({
  . . .
  actions: {
    connectionOpened({ commit }) {
      commit('SET_CONNECTION', true);
    },
    connectionClosed({ commit }) {
      commit('SET_CONNECTION', false);
    },
    connectionError({ commit }, error) {
      commit('SET_ERROR', error);
    },
    remoteMessage({commit}, message) {
      commit('SET_MESSAGE', message);
    },
    pause() {
      sendWebSocketMsg('{"pause":true}')
    },
    play() {
      sendWebSocketMsg('{"pause":false}')
    }
  }
}

The webSocket functionality is functioning smoothly and automatically reconnects when needed. The only thing left now is to implement the ability to send messages via webSocket.

How should I modify the webSocket plugin to achieve this?

Answer №1

After discovering the solution, I am now able to answer my own question. The key information was found in a helpful tutorial that I followed.

Surprisingly, the crucial element turned out to be a vuex plugin.

The solution involves subscribing to a vuex method - specifically, I included an empty method called SEND_MESSAGE into the vuex mutations section.

  mutations: {
    SET_ERROR(state, errStr) {
      state.error = errStr;
    },
    SET_CONNECTION(state, status) {
      state.connected = status;
    },
    SET_MESSAGE(state, message) {
      let msg = JSON.parse(message);
      . . .
    },
    SEND_MESSAGE() {
    },
  },

I then proceeded to add application-specific actions:

    pause({commit}) {
      commit('SEND_MESSAGE', '{"pause":true}');
    },
    play({commit}) {
      commit('SEND_MESSAGE', '{"pause":false}');
    },

In order to call the store actions from my components, I utilized the following approach:

  methods: {
    pause() {
      this.$store.dispatch("pause");
    },
    play() {
      this.$store.dispatch("play");
    }
  },

The final step requires adjustments to the plugin. By subscribing a method to trigger the SEND_MESSAGE mutation, the process can be completed as shown below:

export default function createWebSocketPlugin() {
    return store_param => {
        store = store_param;
        startWebsocket();
        store.subscribe((mutation, state) => {
            if (state.connected && mutation.type === 'SEND_MESSAGE' && ws) {
                console.log("webSocket send "+mutation.payload);
                ws.send(mutation.payload);
            }
        });          
    };
}

The addition of the store.subscribe instruction ensures that the operation is only carried out when the mutation type aligns with expectations and the web socket connection is active.

Answer №2

ws variable is scoped to the module where it was declared, necessitating adjustments to the plugin module to enable a function to access ws, for example:

export function sendWebSocketMessage(message) {
    if (ws) {
        ws.sendMessage(message)
    }
}

export default function initializeWebSocketPlugin() {...}

Subsequently, the named export can be imported into the relevant module:

import webSocket, {sendWebSocketMessage} from '../plugins/webSocket'

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Prevent the execution of a Javascript function if it is already in progress

I've developed a function that retrieves records from a third party, and this function runs every 10 seconds. However, as I debug through Firefox, I notice a long queue of ajax requests. I'm contemplating including a statement that can signal to ...

Add value to a progress bar over time until it reaches the designated timeout

I'm struggling to implement a loading bar with a fixed timeout requirement. The goal is for the bar to be completely filled within 5 seconds. While I have successfully created the HTML and CSS components, I am facing difficulty in developing the JavaS ...

Guide on showcasing an alert notification when the data is already existing within an array through javascript

Need help with displaying an alert message in JavaScript for duplicate values in an array? var names = []; var nameInput = document.getElementById("txt1"); var messageBox = document.getElementById("display"); function insert() { names. ...

The meteorite experienced a crash as startup.js attempted to connect with Mongo

Setting up a Mongo database for a meteor project has been tricky for me. I've created a startup.js file to load the necessary files, but as soon as I start meteor, it crashes. Can anyone lend a hand, please? Here is a snippet from the HTML file: < ...

The checkbox allows for the activation and deactivation of the textarea

Can someone help me? I have a textbox that needs to turn into a textarea when clicked. It works fine on its own, but with other JavaScript code it's not working properly. Any assistance is appreciated. P.S. the code is messy, I will clean it up soon! ...

Encountering a 404 error while attempting to upload files with multer in node.js

I am currently developing a website using node.js where users can create small adverts with various information and upload images. I have successfully set up a mongodb database to store the data, but I am encountering a 404 error when trying to upload imag ...

Adjust the settings of a CSS element

Apologies as I am still new to this and struggling to implement the correct code. I am attempting to modify the background color of a custom marker in leaflet.js. Essentially, I need to adjust the CSS element's value. I have the CSS code and how I am ...

Tips for transferring information between two distinct pages utilizing the jQuery POST technique

I'm dealing with two PHP files called card_process.php and payment.php. My goal is to transfer data from the cart_process page to the payment page. Here's a snippet of the code: In cart_process.php: $paynow = "<button type='submit' ...

Creating a div overlay triggered by the addition of a child tag

Using the Paypal zoid feature, I have a button that opens an iframe in the parent div when clicked. However, the iframe causes the other contents of the website to shift around, making it look messy. I'm wondering if there is a way to make the parent ...

Attempting to establish a login system using MongoDB

I am currently working on a function to verify user login details entered in a form and compare them with data stored in MongoDB, such as email and password. However, the function seems to be malfunctioning. The expected behavior is that when a user ente ...

Unable to retrieve element by ID from an external source

I've been attempting to conceal a div after submitting a form, but unfortunately, I have not been successful. I am curious about the process of creating a div when utilizing an external JavaScript file. Here is the code to consider: HTML: <!DOCTY ...

The dynamic data for ng-repeat failed to load properly due to an

Hey guys, I've encountered a problem that I can't seem to figure out. It appears that Google Chrome rearranges JSON data when rendering it in a way that affects 'ng-repeat'. As a result, when I load the data into the grid, the columns g ...

Dependency management in ReactJS components

I am grappling with the optimal structure for a React component that is composed of other components. Let's look at the first example: <ColorSelect id="color" label={this.state.selectLabel} trigger={{ color: "lime", text: "Lime"}} onPropagateCli ...

What is the reason for a type narrowing check on a class property failing when it is assigned to an aliased variable?

Is there a way to restrict the type of property of a class in an aliased conditional expression? Short: I am trying to perform a type narrowing check within a class method, like this._end === null && this._head === null, but I need to assign the r ...

Tips for accessing the information received from an AJAX call

When making an AJAX post request for processed data from the database in the form of an array [value1, value2, value3,...,valueN], I aim to use it on a ChartJS object. Here is the AJAX Request: $(document).ready($.post('callMeForAJAX.jsp', func ...

Print Vue page with the same styling as the original

How can I add a print button to my application that prints the page with the original CSS styles? I am currently using window.print() function and have a separate file called print.scss with specific print styles. @media print { header {display:none; ...

List being dynamically split into two unordered lists

Could someone help me with a JS/jQuery issue I'm facing? My challenge is to populate a modal when a link is clicked. Upon clicking the link, a UL is created from a data attribute. However, the problem is that only one UL is being generated whereas I ...

What is the best way to extract data from a table and transmit it to the server using AngularJS?

I'm attempting to extract all the content from a table in HTML. Is it possible to retrieve all rows from one side and send them in a post request to the server? I've been struggling to figure out how to do this. Do I need to bind each row using n ...

The v-model for two-way binding seems to be malfunctioning, with a browser error or warning stating that the use of withDirectives is restricted to render functions

Currently utilizing VITE v5.0.8. This file is dex.html <!doctype html> <html lang="en"> <head> <!-- Required meta tags --> <meta charset="utf-8"> <meta name="viewport" content=&q ...

What is the best way to integrate asynchronous computed observable with several concurrent $.ajax requests?

I'm currently working on implementing an asynchronous computed observable following the guide provided here. While I have successfully achieved this for a single ajax call, I am facing a challenge in figuring out how to perform multiple ajax calls in ...