Phoenix LiveView Hooks: window scroll issues

I have a LiveView form where an error message is displayed along with the form if the form was invalid. Pretty standard stuff. I am trying to implement a hook on this element to scroll to the top of the page when it is mounted. The hook is being called, it just won’t scroll the page. Is this a limitation? I’ve tried both this.el.scrollIntoView as well as window.scrollTo(0, 0). Neither moves the page at all.

1 Like

I just tried your code on a DOM element that appears conditionally and the window is scrolled to the top:

def mounted() { window.scrollTo(0, 0); }

Can you share more code?

Sure.

The element is:

      <%= if @changeset.action do %>
        <div
          id="complaint-form-errors"
          class="alert alert-danger"
          phx-hook="formScrollToError">There was a problem saving this complaint!</div>
      <% end %>

And the formScrollToError hook is:

export const formScrollToError = {
  mounted () {
    window.scrollTo(0, 0);
  }
} as Hook;

this looks fishy… can you make it look like:
https://hexdocs.pm/phoenix_live_view/Phoenix.LiveView.html#module-js-interop-and-client-controlled-dom
eg:

let Hooks = {}
Hooks.PhoneNumber = {
  mounted() {
    this.el.addEventListener("input", e => {
      let match = this.el.value.replace(/\D/g, "").match(/^(\d{3})(\d{3})(\d{4})$/)
      if(match) {
        this.el.value = `${match[1]}-${match[2]}-${match[3]}`
      }
    })
  }
}

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

I have a separate hooks script that imports all of the hooks and adds them.

The hook is definitely being called…if I change the content to alert("TESTING") the alert appears when I would expect it to. It just won’t scroll the window for whatever reason.

1 Like

If you open the browser’s dev console and manually run the command what happens?

Another idea: try calling it with a timeout and see if it makes a difference: setTimeout(() => { window.scrollTo(0,0) }, 1000)

That was a good thought! The timeout works. Strangely, it also works using setTimeout if the time is 0. I wasn’t going to be happy with a delay but as long as I can set the timeout to 0, it’s just a curiosity why it won’t work directly.

I appreciate the help.

2 Likes