actioncable-vue icon indicating copy to clipboard operation
actioncable-vue copied to clipboard

Vue3 undefined error

Open acovrig opened this issue 1 year ago • 5 comments

Describe the bug When trying the vue3 example in the Readme:

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",
      });
    });
  },
});

I get ReferenceError: defineComponent is not defined, so if I change the first line to: import { onMounted, defineComponent } from 'vue';

I then get Cannot read properties of undefined (reading '$cable') .

I was able to get it to work using this:

<script>
import { defineComponent } from 'vue';

export default defineComponent({
  channels: {
    ChatChannel: {
      connected() {
        console.log('connected');
      },
      rejected() {
        console.log('rejected');
      },
      received(data) { console.log(data); },
      disconnected() { console.log('disconnected'); },
    },
  },
  setup() {},
  mounted() {
    this.$cable.subscribe({
      channel: "ChatChannel",
    });
  },
});
</script>

Am I missing something or should the Readme be updated?

Plugin version (please complete the following information):

versions: {
  "actioncable-vue": "^3.0.4",
  "vue": "^3.4.29"
}

acovrig avatar Oct 08 '24 00:10 acovrig

@acovrig Thanks for flagging. This is a README issue, and I'll update it shortly.

mclintprojects avatar Oct 13 '24 18:10 mclintprojects

Same here!

joaoVictorDeAndrade avatar Oct 18 '24 12:10 joaoVictorDeAndrade

@joaoVictorDeAndrade @acovrig Are you using Nuxt or just Vue? Have you found a solution yet? ActionCableVue sets a Vue globalProperty for $scable, so you should be able to do this.$cable.

Context: https://blog.logrocket.com/vue-js-globalproperties/

mclintprojects avatar Nov 08 '24 12:11 mclintprojects

Has anyone figured out how to run this in Vue3 with composition API? Is there a composable that can be imported or something similar? The readme still seems out of date.

adamreisnz avatar Jan 08 '25 22:01 adamreisnz

@adamreisnz You should use the provide / inject API when loading the VueActionCable plugin into the VueApp

// in your main entry file (e.g. main.ts)
import { createApp } from 'vue'
import ActionCableVue from 'actioncable-vue'

const app = createApp(App)
app.use(ActionCableVue, actionCableVueOptions)
app.provide('cable', app.config.globalProperties.$cable)

Then in your component file (e.g. App.vue) you can read the cable value with inject

<script setup lang="ts">
import { inject, onMounted, onUnmounted } from 'vue'

type CableVueChannels<T = unknown, C extends string = string> = Record<
  C,
  Partial<{
    connected(): void
    disconnected(): void
    received(data: T): void
    rejected(): void
  }>
>

type CableVueContext<T = unknown, C extends string = string> = {
  connection: { connect: (websocketUrl: string) => void; disconnect: () => void }
  registerChannels: (actions: CableVueChannels<T, C>) => void
  subscribe: ({ channel }: { channel: string }) => void
  unregisterChannels: (actions: CableVueChannels<T, C>) => void
  unsubscribe: (channel: string) => void
}

const cable = inject<CableVueContext>('cable');

// Next you can use the classic way to initialize your connection
const channels = {
  ChatChannel: {
    connected() {
      console.log("connected");
    },
  },
} as const;

onMounted(() => {
  if (!cable) return
  cable.registerChannels(channels);
  cable.subscribe({
    channel: "ChatChannel",
  });
});

onUnmounted(() => {
  if (!cable) return
  cable.unregisterChannels(channels);
  cable.unsubscribe("ChatChannel");
});

pascalvaccaro avatar Aug 25 '25 09:08 pascalvaccaro