Scrolling to error messages outside of view? Listening to right event?

Hi there.

I’ve got a form with inputs outside of the view on small screens. I am adding an event listener to phx:update that then scrolls to the first object with .has_errors. This only seems to work if I add a 1ms delay to my event listener (presumably to let the dom finish updating). Without it, the target node is correctly queried, but the call to scrollIntoView isn’t executed. Should I be listening to a separate event? It seems there is no phx:updated.

I import and call the following hook on the parent form using phx-hook="":

// assets/js/hooks/error-scroll.js

const errorScroll = {
  mounted() {
    window.addEventListener("phx:update", (event) => {

      let firstError = document.querySelector("label.has-error");

      if (firstError) {
        setTimeout(function () {
          firstError.scrollIntoView({ behavior: "smooth", block: "end", inline: "nearest" });
          console.log("scrolling to:", firstError);
        }, 1)
      }
    });
  }
}

export default errorScroll;

What am I missing?

There’s an updated callback for client hooks that’s available alongside mounted and other lifecycle callbacks. The updated callback runs whenever “the element has been updated in the DOM by the server”. So if the parent form has phx-hook="ErrorScroll", the hook could be something like the below.

let Hooks = {}
Hooks.ErrorScroll = {
  updated() {
    // `this.el` references the parent form
    let firstError = this.el.querySelector("label.has-error");
    if (firstError) {
      firstError.scrollIntoView({ behavior: "smooth", block: "end", inline: "nearest" });
    }
  }
}
let liveSocket = new LiveSocket("/live", Socket, { hooks: Hooks, ... })

Check out the Client hooks via phx-hook section of LiveView’s JavaScript interoperability docs for the entire list of callbacks as well as the attributes availiable to these callbacks.

1 Like