Vue3 undefined error
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 Thanks for flagging. This is a README issue, and I'll update it shortly.
Same here!
@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/
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 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");
});