3.1.0 • Published 6 months ago

actioncable-vue v3.1.0

Weekly downloads
3,382
License
MIT
Repository
github
Last release
6 months ago

🚀 Installation

npm install actioncable-vue --save
// Vue 3.x
import { createApp } from "vue";
import App from "./App.vue";
import ActionCableVue from "actioncable-vue";

const actionCableVueOptions = {
  debug: true,
  debugLevel: "error",
  connectionUrl: "ws://localhost:5000/api/cable", // If you don"t provide a connectionUrl, ActionCable will use the default behavior
  connectImmediately: true,
  unsubscribeOnUnmount: true,
};

createApp(App)
  .use(store)
  .use(router)
  .use(ActionCableVue, actionCableVueOptions)
  .mount("#app");
// Vue 2.x
import Vue from "vue";
import ActionCableVue from "actioncable-vue";
import App from "./App.vue";

Vue.use(ActionCableVue, {
  debug: true,
  debugLevel: "error",
  connectionUrl: "ws://localhost:5000/api/cable", // or function which returns a string with your JWT appended to your server URL as a query parameter
  connectImmediately: true,
});

new Vue({
  router,
  store,
  render: (h) => h(App),
}).$mount("#app");
ParametersTypeDefaultRequiredDescription
debugBooleanfalseOptionalEnable logging for debug
debugLevelStringerrorOptionalDebug level required for logging. Either info, error, or all
connectionUrlString/FunctionnullOptionalActionCable websocket server url. Omit it for the default behavior
connectImmediatelyBooleantrueOptionalActionCable connects to your server immediately. If false, ActionCable connects on the first subscription.
unsubscribeOnUnmountBooleantrueOptionalUnsubscribe from channels when component is unmounted.
storeObjectnullOptionalVuex store

Table of content

Wall of Appreciation

  • Many thanks to @x88BitRain for adding Vue 3 compatibility

🌈 Component Level Usage

If you want to listen to channel events from your Vue component:

  1. If you're using Vue 3 setup script define a channels object in the setup function.
  2. If you're using Vue 3 defineComponent define a channels property.
  3. You need to either add a channels object in the Vue component (Vue 2 only)
  4. If you're using vue-class-component define a channels property. (Vue 2 only)

Each defined object in channels will start to receive events provided you subscribe correctly.

1. Vue 3 setup script
<script setup>
import { onMounted, onUnmounted } from "vue";

const channels = {
  ChatChannel: {
    connected() {
      console.log("connected");
    },
  },
};

onMounted(() => {
  this.$cable.registerChannels(channels);
  this.$cable.subscribe({
    channel: "ChatChannel",
  });
});

onUnmounted(() => {
  this.$cable.unregisterChannels(channels);
  this.$cable.unsubscribe("ChatChannel");
});
</script>
2. Vue 3 defineComponent
import { onMounted } from "vue";

export default defineComponent({
  channels: {
    ChatChannel: {
      connected() {
        console.log("connected");
      },
      rejected() {
        console.log("rejected");
      },
      received(data) {},
      disconnected() {},
    },
  },
  setup() {
    onMounted(() => {
      this.$cable.subscribe({
        channel: "ChatChannel",
      });
    });
  },
});
3. Vue 2.x.
new Vue({
  data() {
    return {
      message: "Hello world",
    };
  },
  channels: {
    ChatChannel: {
      connected() {},
      rejected() {},
      received(data) {},
      disconnected() {},
    },
  },
  methods: {
    sendMessage: function () {
      this.$cable.perform({
        channel: "ChatChannel",
        action: "send_message",
        data: {
          content: this.message,
        },
      });
    },
  },
  mounted() {
    this.$cable.subscribe({
      channel: "ChatChannel",
      room: "public",
    });
  },
});
4. Vue 2.x vue-class-component
@Component
export default class ChatComponent extends Vue {
  @Prop({ required: true }) private id!: string;

  get channels() {
    return {
      ChatChannel: {
        connected() {
          console.log("connected");
        },
        rejected() {},
        received(data) {},
        disconnected() {},
      },
    };
  }

  sendMessage() {
    this.$cable.perform({
      channel: "ChatChannel",
      action: "send_message",
      data: {
        content: this.message,
      },
    });
  }

  async mounted() {
    this.$cable.subscribe({
      channel: "ChatChannel",
      room: "public",
    });
  }
}

👂🏾 Subscriptions

1. Subscribing to a channel

Define a channels object in your component matching the action cable server channel name you passed for the subscription.

<script setup>
import { onMounted } from "vue";

const channels = {
  ChatChannel: {
    connected() {
      console.log("connected");
    },
  },
};

onMounted(() => {
  this.$cable.registerChannels(channels);
  this.$cable.subscribe({
    channel: "ChatChannel",
  });
});
</script>

Important ⚠️

ActionCableVue automatically uses your ActionCable server channel name if you do not pass in a specific channel name to use in your channels. It will also override clashing channel names.

2. Subscribing to the same channel but different rooms
<script setup>
import { onMounted } from "vue";

const channels = {
  chat_channel_public: {
    connected() {
      console.log("I am connected to the public chat channel.");
    },
  },
  chat_channel_private: {
    connected() {
      console.log("I am connected to the private chat channel.");
    },
  },
};

onMounted(() => {
  this.$cable.registerChannels(channels);

  this.$cable.subscribe(
    {
      channel: "ChatChannel",
      room: "public"
    },
    "chat_channel_public"
  );

  this.$cable.subscribe(
    {
      channel: "ChatChannel",
      room: "private"
    },
    "chat_channel_private"
  );
});
</script>
3. Subscribing to a channel with a computed name
// Conversations.vue

<script setup>
import { onMounted } from "vue";
const router = useRouter();

const openConversation = (conversationId) => {
  router.push({name: "conversation", params: {id: conversationId});
}
</script>
// Chat.vue

<script setup>
import { onMounted } from "vue";
const route = useRoute();

const channels = {
  computed: [
    {
      channelName() {
        return `chat-convo-${route.params.conversationId}`;
      },
      connected() {
        console.log("I am connected to a channel with a computed name.");
      },
      rejected() {},
      received(data) {},
      disconnected() {},
    },
  ],
}

onMounted(() => {
  this.$cable.registerChannels(channels);
  this.$cable.subscribe({
    channel: `chat-convo-${route.params.conversationId}`,
  });
});
</script>

🔇 Unsubscriptions

For Vue 2.x and when using Vue 3.x defineComponent, when your component is destroyed ActionCableVue automatically unsubscribes from any channel that component was subscribed to.

1. Unsubscribing from a channel (Vue 3.x setup script)
<script setup>
import {onUnmounted } from "vue";
onUnmounted(() => {
  this.$cable.unsubscribe("ChatChannel");
});
</script>
2. Unsubscribing from a channel Vue 2.x
new Vue({
  methods: {
    unsubscribe() {
      this.$cable.unsubscribe("ChatChannel");
    },
  },
});

🔌 Manually connect to the server

ActionCableVue automatically connects to your Action Cable server if connectImmediately is not set to false during setup. If you do set connectImmediately to false you can manually trigger a connection to your ActionCable server with this.$cable.connection.connect.

<script setup>
const connectWithRefreshedToken = (token) => {
  this.$cable.connection.connect(`ws://localhost:5000/api/cable?token=${token}`);
}
</script>

✂️ Disconnecting from the server

<script setup>
const disconnect = () => {
  this.$cable.connection.disconnect();
}
</script>

💎 Performing an action on your Action Cable server

Requires that you have a method defined in your Rails Action Cable channel whose name matches the action property passed in.

<script setup>
import { onMounted } from "vue";

const sendMessage = () => {
  this.$cable.perform({
    channel: "ChatChannel",
    action: "send_message",
    data: {
      content: "Hi",
    },
  });
};

const channels = {
  ChatChannel: {
    connected() {
      console.log("Connected to the chat channel");
    },
    received(data) {
      console.log("Message received");
    },
  },
};

onMounted(() => {
  this.$cable.registerChannels(channels);
  this.$cable.subscribe({
    channel: "ChatChannel",
  });
});
</script>

🐬 Usage with Vuex (Vue 2.x)

ActionCableVue has support for Vuex. All you have to do is setup your store correctly and pass it in during the ActionCableVue plugin setup.

// store.js

import Vue from "vue";
import Vuex from "vuex";

Vue.use(Vuex);

export default new Vuex.Store({
  state: {},
  mutations: {
    sendMessage(state, content) {
      this.$cable.perform({
        action: "send_message",
        data: {
          content,
        },
      });
    },
  },
  actions: {
    sendMessage({ commit }, content) {
      commit("sendMessage", content);
    },
  },
});
import store from "./store";
import Vue from "vue";
import ActionCableVue from "actioncable-vue";

Vue.use(ActionCableVue, {
  debug: true,
  debugLevel: "all",
  connectionUrl: process.env.WEBSOCKET_HOST,
  connectImmediately: true,
  store,
});

💪 Usage with Nuxt

ActionCableVue works just fine with Nuxt 2 or 3. All you need to do is set it up as a client side plugin.

Nuxt 3
// /plugins/actioncablevue.client.js
import ActionCableVue from "actioncable-vue";

export default defineNuxtPlugin(({ vueApp }) => {
  const config = useRuntimeConfig();

  vueApp.use(ActionCableVue, {
    debug: true,
    debugLevel: "all",
    connectionUrl: config.public.WEBSOCKET_HOST,
    connectImmediately: true,
  });
});


// /pages/chat.vue
<script setup>
const { vueApp } = useNuxtApp();

let $cable;
const channels = {
  ChatChannel: {
    connected() {
      console.log("connected");
    },
  }
};

onMounted(() => {
  $cable = vueApp.config.globalProperties.$cable;

  $cable.registerChannels(channels, vueApp);
  $cable.subscribe({
    channel: "ChatChannel",
  });
});

onUnmounted(() => {
  $cable.unregisterChannels(channels, vueApp);
  $cable.unsubscribe("ChatChannel");
});
</script>
Nuxt 2
// /plugins/actioncable-vue.js

import Vue from "vue";
import ActionCableVue from "actioncable-vue";

if (process.client) {
  Vue.use(ActionCableVue, {
    debug: true,
    debugLevel: "all",
    connectionUrl: process.env.WEBSOCKET_HOST,
    connectImmediately: true,
  });
}

// nuxt.config.js
plugins: [{ src: "@/plugins/actioncable-vue", ssr: false }];
3.1.0

6 months ago

3.0.4

9 months ago

3.0.3

9 months ago

3.0.2

9 months ago

3.0.1

9 months ago

3.0.0

9 months ago

2.5.1

4 years ago

2.5.0

4 years ago

2.4.5

4 years ago

2.4.6

4 years ago

2.4.3

4 years ago

2.4.4

4 years ago

2.4.2

4 years ago

2.4.1

4 years ago

2.4.0

4 years ago

2.3.2

5 years ago

2.3.1

5 years ago

2.3.0

5 years ago

2.2.2

5 years ago

2.2.1

5 years ago

2.2.0

5 years ago

2.1.5

5 years ago

2.1.4

5 years ago

2.1.3

5 years ago

2.1.2

5 years ago

2.1.1

5 years ago

2.1.0

5 years ago

2.0.2

5 years ago

2.0.0

5 years ago

1.7.0

5 years ago

1.6.2

5 years ago

1.6.1

5 years ago

1.6.0

5 years ago

1.5.1

6 years ago

1.5.0

6 years ago

1.4.2

6 years ago

1.4.1

6 years ago

1.4.0

6 years ago

1.3.0

6 years ago

1.2.4

6 years ago

1.2.3

6 years ago

1.2.2

6 years ago

1.2.1

6 years ago

1.2.0

6 years ago

1.1.0

6 years ago

1.0.0

6 years ago