-
Notifications
You must be signed in to change notification settings - Fork 963
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
support multiple livesockets #3564
base: main
Are you sure you want to change the base?
Changes from 4 commits
ab8e7f0
616bec4
04ed4eb
9f7150f
6302343
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,6 +24,12 @@ except for the following LiveView specific options: | |
* `uploaders` – a reference to a user-defined uploaders namespace, containing | ||
client callbacks for client-side direct-to-cloud uploads. See the | ||
[External uploads guide](external-uploads.md) for details. | ||
* `rootViewSelector` - the optional CSS selector to scope which root LiveViews to connect. | ||
Useful when running multiple liveSockets, each connected to a different application. | ||
See the [Connecting multiple livesockets](#connecting-multiple-livesockets) | ||
section below for details. | ||
|
||
a CSS selector to scope which | ||
|
||
## Debugging client events | ||
|
||
|
@@ -313,3 +319,42 @@ Hooks.Chart = { | |
``` | ||
*Note*: In case a LiveView pushes events and renders content, `handleEvent` callbacks are invoked after the page is updated. Therefore, if the LiveView redirects at the same time it pushes events, callbacks won't be invoked on the old page's elements. Callbacks would be invoked on the redirected page's newly mounted hook elements. | ||
### Connecting multiple liveSockets | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wouldn't document this as prominently. I think the documentation for the liveSocket option is enough. |
||
LiveView allows connecting more than one `liveSocket`, each targeting different HTML nodes. This is useful to | ||
isolate the development cycle of a subset of the user interface. This means a different Phoenix application hosted | ||
in a different domain, can fully support an embedded LiveView. Think of it as Nested LiveViews, but instead of | ||
process-level isolation, it is a service-level isolation. | ||
Annotate your root views with a unique HTML attribute or class: | ||
```elixir | ||
# Main application serving a regular LiveView | ||
use GreatProductWeb.LiveView, container: {:div, "data-app": "root"} | ||
|
||
# Cats application, which will serve the cats component | ||
use CatsWeb.LiveView, container: {:div, "data-app": "cats"} | ||
``` | ||
And initialise the liveSockets: | ||
```javascript | ||
# Fetch the disconnected render | ||
let disconnectedCatsHTML = await fetch("https://cats.io/live", { credentials: 'include' }) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. would that be a controller doing a |
||
.then((response) => response.text()) | ||
.catch((error) => console.error(error)); | ||
|
||
# Append it to HTML | ||
document.queryElementById("#cats-slot").innerHTML = disconnectedCatsHTML | ||
|
||
|
||
# Connect main liveSocket | ||
let liveSocket = new LiveSocket("https://root.io/live", Socket, {rootViewSelector: "[data-app='root']"}) | ||
liveSocket.connect() | ||
|
||
# Connect the cats liveSocket | ||
let liveSocketCats = new LiveSocket("https://cats.io/live", Socket, {rootViewSelector: "[data-app='cats']"}) | ||
liveSocketCats.connect() | ||
``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be inversed, so people could do
#foo-bar
as the root view selector if they want to? In such cases, should they end it with a space?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking it would simplify things if we just ignore the
PHX_VIEW_SELECTOR
and only use the user-defined selector?The initial idea behind composing both together was because I didn't notice we could customise the
container
of the LiveView. So my initial implementation had something like::has(.some-class-inside-the-lv-template)
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any reason not to just replace
PHX_VIEW_SELECTOR
completely with a user defined selector?We can document users need to customise the LiveView
:container
in that case. It can be done globally inuse MyAppWeb, :liveview
or easily extend to accept as paramuse MyAppWeb.LiveView, :liveview, app: :something
🤔There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that would be my vote but we need to tell people they will want to check for [data-phx-session] unless their selector points directly to the LiveView container.