Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Calling the updated hook when phx-update="ignore" #388

Open
pcorey opened this issue Sep 24, 2019 · 8 comments

Comments

@pcorey
Copy link

commented Sep 24, 2019

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!

@joxford531

This comment has been minimized.

Copy link

commented Sep 27, 2019

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)
@joxford531

This comment has been minimized.

Copy link

commented Sep 27, 2019

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.

@snewcomer

This comment has been minimized.

Copy link
Contributor

commented Sep 29, 2019

@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.

@pcorey

This comment has been minimized.

Copy link
Author

commented Sep 30, 2019

@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?

@pcorey

This comment has been minimized.

Copy link
Author

commented Sep 30, 2019

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

@pcorey

This comment has been minimized.

Copy link
Author

commented Sep 30, 2019

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?

@chrismccord

This comment has been minimized.

Copy link
Member

commented Oct 1, 2019

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!

@chrismccord chrismccord self-assigned this Oct 1, 2019
@pcorey

This comment has been minimized.

Copy link
Author

commented Oct 1, 2019

Thanks @chrismccord!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
4 participants
You can’t perform that action at this time.