Phoenix_live_view: Calling the updated hook when phx-update="ignore"

Created on 24 Sep 2019  Â·  8Comments  Â·  Source: phoenixframework/phoenix_live_view

Environment

  • Elixir version (elixir -v): 1.9.1
  • Phoenix version (mix deps): 1.4.10
  • NodeJS version (node -v): 11.3.0
  • NPM version (npm -v): 6.4.1
  • Operating system: macOS 10.14.6

Actual behavior

When using NPM's phoenix_live_view package version 0.2.0 or higher, when phx-update is set to "ignore", any updated hooks set on that DOM element don't fire.

Expected behavior

In 0.1.1, the updated hook would still fire when an update came down the wire, even if an actual DOM update was skipped due to phx-update="ignore". This is very helpful for certain situations, like I outlined in this article on using LiveView to render an HTML5 canvas. Specifically in the last half of the Resizing the Canvas section. Sometimes we want to trigger some JavaScript, without triggering an update on the DOM node itself.

From the article:

Unfortunately, our canvas doesn’t seem to be able to hold onto these [size attribute] changes. Subsequent calls to our updated callback seem to lose our resize changes, and the canvas reverts back to its original, blurry self. This is because when LiveView updates our canvas DOM node, it resets our width and height attributes. Not only does this revert our pixel density fix, it also forcefully clears the canvas’ rendering context.

LiveView has a quick fix for getting around this problem. By setting phx-update to "ignore" on our canvas element, we can instruct LiveView to leave our canvas element alone after its initial mount.

Was this considered a bug and intentionally removed? If so, how should I proceed if I want to trigger some JavaScript when LiveView updates come down from the server, without affecting the node in the DOM?

Thanks!

Most helpful comment

The next release will merge attributes on phx-update=ignore containers, so you can put data attributes on the containers and read them in the updated hooks.

That said, I'd still be interested in knowing if we can rely on this behavior in the future

ignored containers are always respected, provided they are not removed from their parent, or their parent is removed, etc. The parent/ancestors updating is not an issue because we only ignore the container once we get to that part of the tree while we morph. Stay tuned. Thanks!

All 8 comments

FYI I am seeing the same bug

  • Elixir version (elixir -v): 1.9.1
  • Phoenix version (mix deps): 1.4.9
  • phoenix_live_view node modules version: 0.3.0
  • NodeJS version (node -v): 10.6.0
  • NPM version (npm -v): 6.9.0
  • Operating system: Amazon Linux release 2 (Karoo)

I was able to get around this particular use case by wrapping a div on the canvas element and putting my phx-hook on that along with the data attributes to store the assigned socket data.

@pcorey 👋 It was great reading that article! Would you expect this to be correct by design? I would imagine that with both a hook and ignore phx- data binding, the ignore attribute would take precedence? I like @joxford531's idea.

Also, I think the root of the problem is the _diffing_. You are updating client code; however, the server only knows about particles. As a result, Phoenix only diffs out that part of the HTML and sends that down the wire, losing any client updates you may have done. So you are right that ignore is needed.

This is a very interesting problem though. How can one apply client side only updates in mounted and avoid that being wiped out by a server response that sees your client side updates as irrelevant. Assuming "phx-ignore" is not needed, I don't know if assigning the w/h and re-applying is the "right" answer, but it is "an" answer. We would essentially need a "snapshot" after JS mounted to be merged in with the server update.

@snewcomer I don't think I have enough insight into LiveView's design to say if I'd expect this to be correct by design. I guess it depends on what you perceive as being "updated" when updated is called. Is it the DOM, or is it the data from the server? If it's the DOM, I'd imagine that the current behavior is correct.

@joxford531's solution sounds good to me as well. So the final markup would look something like this?

<div phx-hook="canvas">
  <canvas phx-update="ignore">
  </canvas>
</div>

It's interesting to know that phx-update="ignore" is still respected even when it's an _ancestor_ being updated by LiveView. That's definitely a useful bit of information. I wonder if we'll be able to rely on that behavior in the future?

Now that there's another way of implementing this, I guess I'm just curious if the original behavior was considered a bug, and if the current behavior is considered correct?

Just FYI, I added an addendum to that article that outlines the fix we talked about. Don't want to lead anyone astray.

And while I was writing out a more in-depth update, I managed to convince myself that the original behavior really doesn't make sense. The "updated" in the updated hook is clearly referring to the DOM node, not the data from the server. The data from the server is only accessible through the DOM node when explicitly set as a data attribute or something like that. The new behavior seems correct and consistent.

Thanks for being my rubber ducky, everyone!

That said, I'd still be interested in knowing if we can rely on this behavior in the future:

It's interesting to know that phx-update="ignore" is still respected even when it's an ancestor being updated by LiveView. That's definitely a useful bit of information. I wonder if we'll be able to rely on that behavior in the future?

The next release will merge attributes on phx-update=ignore containers, so you can put data attributes on the containers and read them in the updated hooks.

That said, I'd still be interested in knowing if we can rely on this behavior in the future

ignored containers are always respected, provided they are not removed from their parent, or their parent is removed, etc. The parent/ancestors updating is not an issue because we only ignore the container once we get to that part of the tree while we morph. Stay tuned. Thanks!

Thanks @chrismccord!

Was this page helpful?
0 / 5 - 0 ratings