Drab: remote controlled frontend framework for Phoenix

Sounds like you are not running the unpoly calls to tell it the DOM updated so it needs to update things and handle events back from it, see:
https://unpoly.com/up.dom
https://unpoly.com/up.bus
https://unpoly.com/up.syntax
Lot of registration handling here: up.compiler() - Unpoly
But what command specifically I use the most is: up.replace() - Unpoly

Thanks, I suppose Iā€™m a bit confused as to how to deal with state now that there are 3 things all trying to work together (unpoly view state, phoenix controllers, phoenix sockets). In the above example I am starting with the controllerā€™s assign state and then updating the assign ā€œliveā€ via the socket, however the controller doesnā€™t know anything about that and if unpoly asks the controller for something else it doesnā€™t have the updated state. Maybe authentication is a bad first use case to learn about unpoly + drabā€¦ leaves me wanting some examples to see what patterns work and how you are thinking about state with these tools?

Maybe this should be forked into a new topic?

Hi all,
news from the Drab world: 0.5.0 is coming to town soon!

This will be a major update. Drab.Query (jQuery-based module) will not be a default one anymore, so by default Drab will not need jQuery to operate.

Two new modules are coming:

  • Drab.Live, introducing living expressions. Yes, you may update your Phoenix template:

     <a href="https://<%= @url%>" @style.backgroundColor=<%= @color%>><%= @url %></a>
    

    by setting up new assigns values

     poke socket, url: "tg.pl/drab", color: "red"
    

    live, without re-rendering and reloading the page.

  • Drab.Element, with easy-to use query and update functions on html elements:

      set_prop socket, "p", style: %{"backgroundColor" => "red"} # awesome effect
    

The new demo page will has been rewritten to use new modules only. You may check it out now, before it went live: https://tg.pl/drab/live

I will try to release it this weekend.

2 Likes

Whooooo!

Cannot wait to try this out fully. :slight_smile:

Fascinating, useful.

2 Likes

Drab 0.5.0 released (2017-07-17)

This version is a major update. The default module, Drab.Query has been replaced with Drab.Live and Drab.Element. Drab is not jQuery dependent by default anymore.

New modules

Drab.Live

Allows to remotely (from the server side) replace the value of the assign in the displayed paged, without re-rendering and reloading the page.

Such template:

<a href="https://<%= @url%>" @style.backgroundColor=<%= @color%>>
  <%= @url %>
</a>

can be updates live with poke/2:

poke socket, url: "tg.pl/drab", color: "red"

Drab.Element

Query and update displayed page from the server side.

set_prop socket, "p", style: %{"backgroundColor" => "red"} # awesome effect

Broadcasting

Broadcasting functions now get subject instead of socket. There is no need to have an active socket to broadcast anymore. Useful when broadcasting from background servers or ondisconnect callback.

Form parameters in sender

If the event launching element is inside a <FORM>, it gets a values of all input elements within that form. This is a map, where keys are the elementā€™s name or id.

Upgrading from 0.4

Add Drab.Query and Drab.Modal to your commanders:

use Drab.Commander, module: [Drab.Query, Drab.Modal]

Depreciations

All soft depreciations up to 0.4.1 became hard.

5 Likes

Hi, firs of all thank you for this wonderful library and for all your commitment! :hugs:

Iā€™m trying the latest version of Drab (i.e. 0.5) inside a Phoenix 1.3 project (hereā€™s the repo) but Iā€™m kind of stuck with the following error:
I know that Drab isnā€™t quite ready for Phoenix 1.3 but as stated here it seems that it can work in someway.

Anyway, I tried ā€œto follow the white rabbitā€ and as far as I understand the problem may reside in the wrong population of the cache. The paths of the drab template seem to be correct.
Btw I tried to clean the cache but nothing changed.

Is there something that Iā€™m missing? :thinking:

@fusillicode,
The issue is in your app.html.eex. You should call Drab.Client after rendering your templates. Now, you are doing it before:

<head>
...
<script src="<%= static_path(@conn, "/js/app.js") %>"></script>
<%= Drab.Client.js(@conn) %>
</head>

<body>
  <main role="main">
    <%= render @view_module, @view_template, assigns %>
  </main>
<script src="<%= static_path(@conn, "/js/app.js") %>"></script>
</body>

Just move Drab.Client.js/1 call at the bottom, after second <script src="/js/app.js">. BTW why to render the javascripts twice?

Second thing: you are trying to poke some assign to the template like this:

poke socket, nil, "index.html", text: String.upcase(text)

https://hexdocs.pm/drab/Drab.Live.html#poke/4

It should work, but is not very elegant :slight_smile: poke/3 and poke/4 are functions working on partials (partial is a template you rendered inside other templates). As far as I see, you donā€™t have any partials rendered in the template, so you should use poke/2 instead

poke socket, text: String.upcase(text)

I really want a commander per template instead of a commander per controller, that way I could instance different templates on different pages or even multiple times in the same page and drab could control each of those. ^.^

/me coughs

It can be done.

I can just simply add a possibility to choose the module where you run the exception handler:

<button drab-click="MyModule.clicked">

But in this case MyModule would not be a real commander - some handlers, like onconnect or ondisconnect can not be launched. So it could confuse users - some commanders launches callbacks, some not.

Or, we can ensure that all the commanders are declared in the controller:

defmodule MyController
  use Drab.Controller, commander: [MyCommander, MyModule]
end

In this case we can launch all callbacks, in order of appearance.

Or, we can create a new type of commander, like Drab.EventHandler which will only contain handler functions with some callbacks (before execution, after execution, but not onload or ondisconnect).

1 Like

HI, just out of curiosity, in which extend is the drab approach different from nitrogen and n2o ?
early days Erlang Web tools.

http://nitrogenproject.com/
http://synrc.com/apps/n2o/

1 Like

Interesting, I never heart of nitrogen before. I will take a look, thanks!

is there any progress in thinking about drab-polymer? This was jumping to my mind as well whaile reading the posts here. Is not drab + client side web components a good fit?

Finally, I am not planning to integrate Drab with any client side library, myself.

The reason for this is I would rather focus on the core Drab. I made Drab modules (like Drab.Live or Drab.Query - for jquery) independent from others, and there is a Drab.DrabModule behaviour, so it is not very complicated to create your own module for polymer, or angular or other. Simply, I will not have time to learn all the client side libraries :slight_smile: - and there are plenty of people who understand it better than me.

So far I am developing the whole thing myself, but if someone is interested to create Drab module for any client-side library, I will give all the help. There is still no documentation or howto about this topic yet, sorry.

4 Likes

Oh I used to use nitrogen back in my old erlang days, it was an awesome server-side-driven web framework. You might indeed get some ideas from it, but Iā€™d not go its whole route of html defined in code.

In the process so in one of my projects, it might be something I can rip out over time. ^.^

In my case it would have to be every single commander in every single controller. What Iā€™m wanting to accomplish is this:

  • User goes to my site, some URL, does not matter where, it loads like normal.
  • User clicks (most of) a link on my site and instead of navigating to that page it instead fetches the page (via unpoly, not drab, although if drab could do thisā€¦) and swaps the main page body (not touching the header/footer).
  • On any page load or change, anything decorate with some drab thing, like say <div drab-commander="BlahCommander"> ... </div> then drab should load up BlahCommander and link it to this element for it to then control (and to control only this element).
  • When page changes then when such an element vanishes then drab should let it die and unhook it. There might even be multiple elements on the page going to the same commander, each should be unique in their control.

Right now Iā€™m playing with a Drab module idea that enhances a Commander to do something similar. Right now you just use it in a command, then use that same commander from every controller (easy to add to your webā€™s using for controllers), and it then maps elements to names, so for a given <div drab-commander="blah">...</div> it will use the command :blah, BlahModule so the BlahModule will become the callback module. It has itā€™s own set of helper functions that basically copy the normal drab ones but constrain to the element that it is bound to.

Sadly is is still in early dev because Iā€™m basically having to rewrite drab to add this functionality it seems, hence why I would love it baked in to it. ^.^;

EDIT: But with the above ability Iā€™d be able to, say, put a notification handler on the header, a chat popup on the footer, various other drab things in the body that get swapped in and out on unpoly changing the pages, and so forth. All a single, unified, server controlled view. :slight_smile:

2 Likes

Oh gosh @grych Iā€™m really sorry for the lateness of my reply :persevere:

Anyway everything you pointed out were my silly errors and all your suggestions just worked fine without any hassle! :top:

Thank you really a lot for your quick support and sorry once again for the bother and for the lateness of my feedback.

Cheers! :beers: :hugs:

1 Like

Here you are:
https://hexdocs.pm/drab/Drab.Browser.html#set_url/2

1 Like

Man, this is awesome!

Just about the time I was reading through Vue docs to build a dashboard. This could be way better. I will test it, even build a simple server monitoring dashboard (using simple commands as data source) and put it here to give and receive more feedback.

One thing that came to me while reading docs and this topic, is how much drab is dependent on phoenix?

I mean, if it is decoupled enough, maybe think about a new SPA server-side framework? Maybe named Brad? :smile:

Just thinking though, I just ran the through the example provided in readme.

1 Like

Haha I love that - Brad - Drab spelt backwards :lol:

1 Like

It is completely dependent on Phoenix. And I think it is not worth to build completely new framwork, if we can just extend the existing one (and such great and reliable as Phoenix).

Perhaps that was the problem with project which tried to accomplish the same, like nagare or volt. They tried to build a new framework, which is a lot of work. My job is much easier :slight_smile:

1 Like

I agree - fitting in nicely with Phoenix is a smart move.

Incidentally, I actually think it was Phoenix that ā€˜killedā€™ Volt - when Phoenix came on the scene I noticed interest in Volt declined significantly. Volt was trying to offer many of the things Phoenix does and that Phoenix does much more performantly, albeit with the notable omission of the front end side.

2 Likes