Phoenix LiveView is now... live!

can +1 on a “backgrounded tab” in latest safari not recovering after some time…

1 Like

I’m already working on an alpha version of phoenix application.

We were waiting for Phoenix Live view. Since it was not on github. So we created our own structure to update UI based on socket, as can be seen in action here

And recently I have integrated Phoenix live view.
After Phoenix Live view all our dependencies with javascripts have gone away :smile:

Thanks Chris and team for such an awesome package.

We will be experimenting with some complex UI with phoenix live view. Will share any updates on that or raise issue if found one on github.

9 Likes

Yes, we need it desperately, as our heroku(free dyno with least resources) demo sometimes crashes when editing forums. How about have something like a phx-blur so that changeset is not triggered every ms.

phx-debouce will surely fix this. Also will be use full on search suggestions.

Also what are your thoughts on rxjs. Can it be used or be helpfull in any way to you.
We use it with angular. It really helps us in controlling/workupon stream of data coming in from socket.

1 Like

phx-debounce will support a blur value. I have no experience with rxjs so can’t speak to that

2 Likes

will be a nice addition.

Here is small code snippet for tyahead search written using rxjs observable pattern.

const typeahead = fromEvent(searchBox, 'input').pipe(
  map((e: KeyboardEvent) => e.target.value),
  filter(text => text.length > 2),
  debounceTime(10),
  distinctUntilChanged(),
  switchMap(() => ajax('/api/endpoint'))
);

This will only call endpoint when all the pipeline from map to distinctUntilChanged is clear.
And switchMap will also give additional functionality to discard any previous request if new one comes. Like let’s say you type a word phoenix and it reached the endpoint call, and at the few ms delay you have typed live then switchMap would discard phoenix and take phoenix live as the new endpoint parameter.

In short switchMap could cancel a request if the source emits quickly enough.

This is quite usefull when working with typeadhed search on websites with high search traffic.

Looks neat! RxJS is 120k minified, so it’s not something we would include ourselves, but you’re free to use it if it meets your needs :slight_smile:

2 Likes

No, so RxJS supports micro feature imports too. You can only import what you need. So the size of general usable operators are as little under 10K.

imports look like this

import { range } from 'rxjs';
import { map, filter } from 'rxjs/operators';
1 Like

I briefly talked about LiveView at the bar yesterday. One of my friend said that this kind of server-driven stateful views looked like the stuff that was done in the old days in the Java world.

I haven’t touched a line of Java since college (doctor’s order) and frankly I was not really sure we were on the same concepts here.

But today I came across similar remarks on the internet from people who just heard about Phoenix LiveView. It made them think about JSF (Java Server Faces) and they were pretty pessimistic about this approach :

https://twitter.com/leisurelefty/status/1107118130055299072

Maybe they’re comparing apples to oranges here, but could someone with a Java background (or maybe @chrismccord ?) make a comparison between the two approaches (JSF vs LiveView) ?

For a starter, I suppose JSF didn’t use websockets at all. I also suppose Erlang processes are much lighter.

1 Like

In the Java-World, there is also the Vaadin framework. Earlier versions (couple of years ago) seemed to have latency problems and did not perform well under load. I have just seen that there is now Vaadin Flow as a newer release. They claim:

Vaadin Flow is a completely new Java web framework for automated bi-directional communication between the server and the browser. Forget REST, JSON parsing or DTOs between the browser and the server. With Vaadin Flow you have direct access to the DOM from the server.

More can be found here.

Not sure if this is against the forum’s guideline, but here I wrote about my experience in migrating a feature using ajax to live view.

A few people said it had been helpful for them, so I thought I’d share here too!

2 Likes

So there are a couple important differences but some of the concerns are indeed shared.

One of the major differences is that LiveView is not trying to reinvent the wheel on the UI side of things. LiveView is not “UI running on the server”, it is not about accessing the DOM from the server, nor it requires a special client side notation. In LiveView, the server simply emits HTML and the LiveView state is not intrinsically tied to the UI in anyway.

This is an oversimplification but you can consider the previous approaches are closer to the MVC client-side framework side of things (i.e. with UI elements modelling the state) while LiveView is more on the React/Redux side of things (i.e. you keep the state on its own and use it to drive changes in the UI).

You also mentioned websockets and processes, which can lead to better performance, but the main importance of websockets is that a persistent connections implies you don’t need a storage for the “component state”. For example, if JSF uses AJAX, it means that every AJAX request can go to a different server, so you need to either persist the state in a shared storage or route requests through a cluster, both leading to overhead.

However, having a different model does not necessarily imply we won’t run into same limitations. One of the Hacker News comments posed a very good list of questions which I will try to answer below:

  1. Freezes and needing a refresh/logout after the server-side “actor” or connection fails.
  2. Refresh won’t actually work, you need to login again.

LiveView does not intend to fully replace your stateless actions. While you could do the login through LiveView and keep it as part of the connection state, that would indeed be a horrible idea! LiveView does not force you in anyway to drive all actions through the “actor”.

  1. Neither does back/forward, hence the big warnings not to hit back button, for example in a paginated list. Hitting back makes it freeze.

This is currently a limitation in LiveView. For example, if you have a paginated table and you are traversing the paginated table with LiveView, then you won’t have the back/forward buttons, you won’t be able to link to page 10, etc. We are aware of this and it is in the ROADMAP to provide tools to allow this. This is similar to SPA/JavaScript apps that do not leverage pushState accordingly. It can be addressed in JS and it will be addressable in LiveView too.

  1. Extreme latency.

I talked about this elsewhere but:

i. If you are using LiveView for things that can be addressed with CSS animations or do not involve the server at all (such as opening a menu), then yes, you are introducing latency when you wouldn’t have any latency before. But as said above, LiveView is not trying to hijack your UI in anyway, nor is it trying to replace HTML+CSS+JS.

ii. On the other hand, for applications with moderate latency, there is a chance that LiveView can reduce the amount of data sent over the wire thanks to the diff-tracking mechanism (and the upcoming binary serializer) and maybe even reduce latency altogether. For example, with a regular AJAX request, you have to do a HTTP request, then authenticate that request on the server, load the data from the database, etc. With LiveView, you have an established connection, so you skip the authentication and a lot of the data-loading on every action, so for a moderate latency, the application may be more responsive because there is generally less work to be done. This would of course have to be measured but it is a point worth considering.

iii. Finally, I think LiveView is in a very good position to tackle Optimistic UIs because any change that you do after a client action, such as clicking a button, will be undone on the next LiveView update. So it is straight-forward to do something like: click a button and enter into a loading state and the loading state is automatically undone when the update arrives. So we can provide feedback to the user on the client side as we wait for a reply and we will put more emphasis on those transitions as we move forward. And this feedback is important when latency is involved.

  1. No shareable urls or hyperlinks possible, two tabs in same browser will sync with each other.

About no shareable URLs, this is true for actions happening inside LiveView, such as in the paginated table, but solving this is part of the roadmap and remember that LiveView does not force all actions to go through the LiveView “actor”.

And two tabs in the same browser won’t sync with each other. Each LiveView session is distinct.

15 Likes

Thanks a lot for the thorough explanation about JSF vs LiveView!

And from what I’ve seen on the Vaadin webpage @priojk shared with us above, it seems that Vaadin tries to reinvent the wheel as well (OOP abstraction of the DOM, special client side notation…)

1 Like

Posted in the Phoenix LiveView blog posts - #6 by AstonJ thread for you :023:

For anyone else writing blog posts on LV - please don’t forget to add them there :smiley:

1 Like

Nice job guys, congratulations!

2 Likes

I’ve led a 5-7 person group session this week, adding LiveView into our Lucidboard project. (Think Trello clone.) It’s been going just swimmingly and we are very excited to share our newfound superpowers with a wider audience.

Two things that we haven’t worked out yet are (1) drag & drop, and (2) capturing DOM attributes to send along with the event. (We wanted to measure the .scrollHeight of a textarea so it could be expanded to show all its content without scrollbars.) I wonder if we can evaluate evaluate an actual JS expression for these features, if we will need to implement certain things in pure JS using the phoenix_live_view.js APIs, or if there is already some trickery to allow us to solve for these things.

Incidentally, anyone is welcome to pull up a chair and help us out with this MIT-licensed, community effort!

We’re looking forward to exploring further how we can supercharge our projects with LiveView & Elixir! Thank you so much, Chris, José & Co. for your amazing contributions!

6 Likes

That feels like the stuff you wouldn’t want to do with live view as it’s not benefiting from being calculated on the server. You already have all the information on the client to do the job. No need to add latency and involve another party.

2 Likes

This is an entirely valid point of view.

That said, if you measure the value of Live View at least in part by how much basic interactivity you can get without writing Javascript, it would be nice to be able to access parts of the DOM that aren’t tied to assigns. Drab does this, it is very pleasant and has worked fine for me even if it is not optimally efficient.

That said, it feels to me like Live View only allowing DOM updates via modified assigns is a conscious design choice, and as I try to get familiar with it by rewriting a Drab-powered application in Live View, I see how introducing this constraint has advantages, too.

Drab also provides a map of the attributes of the DOM element to the event handler, (the sender map) as opposed to just one attribute (e.g. phx-value). You can work around that in Live View, but unlike the absence of direct DOM manipulation discussed above, I don’t yet see any advantage to this limitation; it’s just kind of a pain (at least from my vantage point of having become accustomed to having it with Drab).

2 Likes

In master we have already changed phx-value to be a map, so we can allow extra data to be given but it is not yet clear how this extra data will be retrieved/computed. Maybe a custom function that is evaluated with the DOM element? But it is unlikely we would send anything extra out of the box.

3 Likes

Sorry, I must be missing something really obvious but I can’t find any examples that point the way to re-usable components.

For example, if I have a page/view with:
<div>
<%= live_render(@socket, DemoWeb.ImageLive) %>
<%= live_render(@socket, DemoWeb.ImageLive) %>
</div>

… each DemoWeb.ImageLive is mounted with the same socket.id, no client events appear to be generated by the second DemoWeb.ImageLive and so the second DemoWeb.ImageLive “doesn’t work”.

What’s the recommended strategy for using multiple identical liveViews/re-usable components alongside one another please? Thanks …

1 Like

This was a bug with child id generation, and is fixed :slight_smile:

7 Likes