Access the underlying Socket impl in JS with Liveview

I need to be able to access the underlying socket in liveview hooks so I can call its methods. Can it be done?

import { Socket } from "phoenix";
import { LiveSocket } from "phoenix_live_view";

let Hooks = {};
Hooks.El = {
  mounted() {
    document.addEventListener("start", e => {
      console.log(this)
      Socket.push({ event: e.detail.event, payload: e.detail.payload });
    });
  }
};

let liveSocket = new LiveSocket("/live", Socket, {
  params: params,
  hooks: Hooks
});

Why can’t you use this.pushEvent?

It simply does not work…

see above, meant to to tag

It sounds like you really didn’t solve your other issue. It should work and accessing the socket directly I don’t think is going to help. If you really want to try, it’s available via this.liveSocket but maybe you could post a minimal app that reproduces your issue? Based on an answer in the other thread and another recent issue you had it sounds like you are doing things a little unconventionally, which is totally fine, but it means there is a lot of missing context for people trying to help you.

Below message() returns a message with ref, topic, payload and event. ex

Object { topic: "lv:phx-F7OHvM86h336dEsC", event: "start", payload: {}, ref: "3" }

This crashes the view:

    document.addEventListener("start", e => {
      console.log(this)
      const topic = this.liveSocket.main.channel.topic;

      console.log(topic)

      const test = message({ topic, event: "start", payload: {} });

      console.log(test)
      
      this.liveSocket.socket.push(test);
    });
phx-F7OHvM86h336dEsC error: view crashed -  
Object {  }

Im not doing anything all that out of the box. The Heex and live_view file is just in a diff directory.

Heex defined in lib/session/gatekeeper/gatekeeper.html.heex

Liveview via use Client, :live_view is defined in lib/session/gatekeeper/socket.ex

  @impl true
  def handle_event("start", msg, socket) do
    Logger.warn("Starting: #{inspect(msg)}")

    {:noreply, socket}
  end

mount and terminate are defined along with some handle_info callback, which work fine.

this causes it to crash too

    document.addEventListener("start", e => {
      this.pushEventTo(this.el, "start", (reply, ref) => {
        console.log(reply);
        console.log(ref);
      });
    });

I don’t know what to tell you other than you need to share more actual code for context. Just describing what you’ve done isn’t enough since something small could be wrong.

Just out of curiosity, I tried to reproduce somewhat in a brand new phoenix app. I added:

# lib/app_web/router.ex
live "/", PageLive, :index
# lib/app_web/live/page_live
defmodule AppWeb.PageLive do
  use AppWeb, :live_view

  @impl true
  def render(assigns) do
    ~H"""
    <div id="some-id" phx-hook="El" class="h-10 px-4 mb-2 border border-black flex items-center" />

    <button phx-click={JS.dispatch("started")} class="border border-black px-4">Click me</button>
    """
  end

  @impl true
  def handle_event("clicked", _params, socket) do
    {:reply, %{message: "clicked"}, socket}
  end
end
// assets/app.js
const Hooks = {}

Hooks.El = {
  mounted() {
    document.addEventListener("started", e => {
      this.pushEvent("clicked", {}, reply => {
        this.el.innerHTML = reply.message
      })
    })
  }
}

// ...

let liveSocket = new LiveSocket("/live", Socket, {
  longPollFallbackMs: 2500,
  params: {_csrf_token: csrfToken},
  hooks: Hooks
})

I get no errors here and when I click the button the hook div shows the reply text.

I had this

<div id="some-id" phx-hook="El" />

In lib/client_web/components/layouts/root.html.heex, because its used across pages.

If I move it in app or directly in the template. It works fine.

Is there a way around this?

No. The root template doesn’t have access to the socket as documented here. You can use the app layout, though. There’s more info on that doc page.

Can you reply on my other post as well so I can give you the solution.

Ha, thanks for the consideration but it’s cool, just update it yourself and link back here and you can mark that as the answer :slight_smile: Just pleeeeease share more context in future questions! If we had seen you were putting this stuff in the root template it would have been solved off the bat. In any event, happy you figure it out!