Imagine you’re creating a Facebook clone with Phoenix and LiveView. You are in your news feed page and there is a chat component opened in the bottom right. You typed a message in the chat component’s input and clicked on a post by a friend in your news feed and the browser followed that link.
In Turbolinks, if you want to persist an element across page loads, there is the data-turbolinks-permanent attribute. How will we achieve such behavior with LiveView?
Another scenario is opening multiple tabs in the above Facebook clone. Will every tab have another LiveView (websocket) connection, or all of the tabs will share a single connection. How will the state persist from tab to tab?
The component is tied to the current LiveView, so if you change LiveViews, due to a patch or redirect, the component is lost. In your case, it may be better to make the chat its own LiveView, separated from the rest.
Is it possible to render a stateless page (.eex template) and have a LiveView html element inside it and then have the same LiveView element in other pages too, which persists across the pages, like an element with data-turbolinks-permanent attribute in a Turbolinks application?
If by “page” you mean reloading a new page from zero with the browser, then no, your liveview will terminate and a new one will be mounted on the next page.
You would have to store your chat state outside of the liveview to be able to retrieve it from inside the new liveview.
As facebook chat is persisted, I would just fetch the last messages from the database in the mount() function, and then subscribe to the conversation to be able to display the new messages as they come.
This means that when a message is sent to the conversation you would have to store it in database but also broadcast it to a pubsub server.
Yes, this is possible with LiveView, as long as all pages in your application are LiveView pages. Then you use live_redirect and live_patch to navigate between them. Then the whole page is never reloaded and the chat will always continue on its actual state.
However, if you want to mix non-LiveViews with LiveViews and have the chat persist, then you need to use a third-party solution, such as Turbolinks itself. Has anyone tried using Turbolinks and PhoenixLiveView together? They may complement each other quite neatly if you have both “dead” and “live” views.
PS: I have edited this post to provide more background.
I have tried in the past. Ideally I wanted to replace Turbolinks with doing live_redirect or live_patch links depending on the granularity of what I had to do. I was hoping LV would have been a drop in replacement for Turbolinks so I could get rid of Turbolinks as a dependency.
Technically work both work together but it seems like a lot of duplication to use both. Especially if your plan was to use LV to have a very fast feeling site and were using live links to do page transitions.
Liveview works quite different than turbolinks. Unless you’re using router mounted liveviews it behaves more like react/vue components mounted within static html – they have nothing to do with routing / page transitions.
So unless you’re switching all your routes to be liveviews you’re not going to get the functionality of turbolinks, which is all about page transitions. Also data-turbolinks-permanent can be used to keep parts of the DOM alive, while things around it change. Liveview afaik doesn’t do that at all. Each liveview/component can change it’s children, but children cannot stay alive when switching between multiple parents.
I saw you commenting on another post two years ago, as follows,
I think there is still a lot of functionality needed in LiveView. Components which persist from page to page, while the rest of the application is rendered through normal http calls is a requirement of any (small or large) real-time application.
If you want a true SPA style liveview, you can do this, but you just do it differently than a multi page style liveview. You have a single liveview, and then use the action to switch out components on the page to simulate changing pages.
Unfortunately I had a stroke more than a year ago. From this time, I lost all of my languages (so English is not very good, sorry!), so I can’t tell you when I will take a look at the Live View (of Drab). Sorry!
I did that some time ago. I had problems with adding / removing live views, because there was no way to tell the LiveView JS that the HTML changed after a Turbolinks transition. Only the connect() call or DOMContentLoaded event seem to trigger the right logic. So I had to reinitialize a LiveView socket on every page transition, which was really slow and negated the benefits of Turbolinks.
It might not be super hard to fix that use case by having a public API to tell LiveView to reconcile its state with the HTML page.
To clarify, both use cases are possible as long as you fully migrate to LiveView. My reply was in the context of a mixed scenario, when live and non-live views are used. This seems to be what was asked but I may have misunderstood it. I have also changed my previous response to avoid confusion.
Thanks from clarifying. Yeah, it seems it could be done by exporting a proper API.
Yeah, this is what I’m doing in my app. Using a mix of live_redirect and live_patch depending on what LV I’m on. But, if this is the route you take, then you can’t pin things like Turbolinks can with its permanence feature right?
Or perhaps you could with using live_patch for every page transition in the whole site, but that’s going to make things wildly complicated if you have to manually be responsible for resetting the socket’s state depending on what LV you’re on (instead of depending on mount if you used live_redirect). That would also mean your whole app would be a single LV right? Not just a series of page transitions using live_redirect with multiple LVs.
This is the problem I was battling when I wanted to keep an iframe from being reset between page views. The only way I could do this was by having 1 LV be responsible for rendering many different “pages” while using live_patch to transition between them. Things got so complex so quickly that I ended up backing out of using LV entirely. And that was only trying to display a few pages worth of content, not the entire app.
And as I pointed out on IRC, I am doing exactly that quite successfully. I realize that there are some challenges there, in that I made mine part of the layout to make that work, but the live views do control assigns for the layout. I understand you ran into difficulties, but assertions that it is impossible are unfounded.
I never said it was impossible. But realistically speaking, if you want to pin something to a specific set of pages, you’re going to run into the same issue I had where you have to use 1 LV and live_patch between pages. Otherwise LV will start swapping it around in the DOM and cause all sorts of issues.
Why is my experience not realistic? We have customers that carry on intercom conversations with us over different pages without interruption daily. Again, I recognize that your situation didn’t work out. However the argument that you’re making over your forum posts is essentially: “An iframe across multiple pages didn’t work for me, and therefore is impractical. A single live view managing multiple psuedo-pages got too complicated, and components are too hard, so that can’t work either.”
I’m not entirely sure what conclusion you’re aiming for with those, although the impression you’re creating at least is “LV is worse than turbolinks”. Both this conclusion and the aspects of the argument leading up to it however are, amongst other things, not the right spirit to be bringing to this discussion. LV is still very new, let’s come at this from the perspective of “How can we make this work better?”, with an ethos of constructive, positive feedback.
You can by using two LiveViews. One will be rendered in the root.html.eex by calling live_render explicitly. The other is your regular LiveView which still will work just fine, with live_patch, live_redirect, whatever. Whenever you don’t want to ever change, put in your root layout.