Whoo!
Very nice! Reusable components are so convenient.
Iām curious how this will be done, just like embedded javascript or something?
Whoo!
Very nice! Reusable components are so convenient.
Iām curious how this will be done, just like embedded javascript or something?
Yes, for the first version I will just simply allow to put JS as a string. Iād like to use ElixirScript, but as you know it is not possible yet.
@grych
Hey Tomek!
Great to meet you at the ElixirConf in Warsaw! Keep up the good work!
Best, Frank
Thanks, you too, see you around, at some next event!
Ladies and Gentlemen,
Iāve just released v0.7.7. It is a very important release, may call it experimental, because Iāve completely changed the way how Drab.Live
renders the poke
updates.
All Drab.Live
limits should not exist anymore.
I strongly encourage everyone to give it a try and give me a feedback in case of failure.
rm priv/drab.live.cache
The artifact of the ancient era, DETS cache for metadata from compiled Drab.Live templates, finally reached the end. Since this release, Drab stores every template metadata in the separate module. The compilation time is a fraction of the previous now. Everyone is happy.
Hi:
I donāt know if this is the right place to ask a question but here I go.
Iām trying Drab and using it with Bootstrap eonasdan datetimepicker. That component fires a dp.change
event instead of a pure change
event when date is changed. I added on a .drab template
<%= text_input @f, :start_date, drab: "dp.change:start_date_changed", class: "form-control datepicker", "data-date-format": "YYYY-MM-DD" %>
And ofc added the appropriate function in the commander but the event is not being picked up. If I manually set an on(dp.change)
binding in the console it picks the event ok.
Is there a limitation on custom events on Drab? Iāve been reading the js code and it seems that it should not be the case.
Any help would be appreciated!
Cheers
Lorenzo
Hi @Batou,
congratulations, youāve found a bug!
This is probably because now Drab defines client side events in a very, hmm, naive way. Actually it is:
function update_event_handler(node, event, func) {
// TODO: learn more about event listeners
// node.removeEventListener(event, func)
// node.addEventListener(event, func)
node["on" + event] = func;
}
As you can see in TODO, I am aware of how poor is this āsolutionā, it supposed to be a temporary for a proof of conceptā¦ But it was always something more important to fix/improve.
Maybe someone with the better knowledge of JS may help? One of the issues is that this function may be called multiple times during the life of the page (as someone update the part of the page from the server, for example), and we donāt want the elixir event handlers to be called multiple times.
It is a right place. And, if you be so kind and create an issue on a github, so it wonāt be fogotten.
The proper way would be to use addEventListener/removeEventListener with a unique key for the function event, then using the key you can store a name in the data section on the element for later lookup (or stored somewhere else or whatever) so you can cancel it without getting many duplicates.
Things like someElement["on" + event] = blah;
should never ever ever be done.
Agreed. Unfortunately, in the complex project like Drab, I had to simplify some stuff to move forward. Otherwise I would never publish even the proof of concept In my defense, at least I realized that it is poor and TODO myself to learn more about itā¦
Hi all,
this is a request for comment on the proposed, stable API for Drab. There will be an API changes, sorry for that, but this is a last moment, when we reach 1.0 all will be fixed forever.
I think the most painful change will be that one to Drab.Live.peek
. It will not return a value, but standard {:ok, value}
tuple. Of course there will be a corresponding peek!
.
A story about rebuilding Live Engine continues, thanks to all the users who find the bugs and share with me! Especially one guy
But there is a one more thingā¦
mix drab.install
Since the beginning, one of Drabās goals is to encourage beginners to start working with modern web frameworks. I know guys, working in IT, but not professional programmers, who are using only plain php, because frameworks are too complicated. Even those, who made this one more step and moved to CherryPy or even Django, never use async model with partial page updates with Ajax. Ajax is too complicated. It may sound strange for us, who made thousands of Ajax based apps, but believe me, it is true. And here comes Drab, mimicking the standard submit
-> action
model with event
-> handler
.
But there is also an another barrier: complexity of installing stuff***. Someone read about Phoenix and Drab, want to try and start learning, but he can see the INSTALLATION.md
with bullets, use Drab.Socket
mambo-jumbo. Many people give up at this point. Now the entry level is lowered to few simple steps:
mix phx.new myapp
cd myapp
vi mix.exs
mix deps.get
mix drab.install
In the future, may it be good to add --with-drab
option to mix phx.new
?
***) This is also I am still using Floki, even if there are better alternatives (@f34nkās one, for example). You need to have compilers, rusts, etc, etc - too complex for a beginner. But I am planning to enable it as an option for power users, so you always could choose yourself.
Hey everyone,
just had my first try today with drab because I think it offers amazing functionality. Many thanks for all that hard work put in!
So, Iām working with contexts in my elixir app and for taking my first steps, I just took a random eex template, in āweb/templates/user_assets/ā, renamed it with .drab and generated a drab commander with
mix drab.gen.commander UserAssets/Structure
Drab then did
* creating lib/app_web/commanders/user_assets/structure_commander.ex
like I assumed, but inside structure_commander.ex the module was created as:
defmodule AppWeb.StructureCommander do
missing the context name in between. Is this desired for any reason?
ā edit
Created an Issue at Issue142
Hi @Sorebrez,
this is a bug in the generator, actually I did not think about nested modules while creating this taskā¦
Could you please open an issue in github, so it will not be forgotten?
In preparations to the final API, there are new functions poke!
and peek!
, throwing exceptions in case of disconnection. I did not change the API yet, so old poke
and peek
behaves as previous, but they are raising depreciation warnings.
There is a plan to introduce the final API in 0.9.0
, which will probably be the next release in a couple of weeks.
Take a look at the release notes, as many more changes and fixes are covered in this release.
Last few months Iāve been busy with refactoring, bug fixing, depreciating, etc, etc. Not very exciting stuff and most of the announcement Iāve posted here was about Drab.Live engine refactored, again or getting closer to stable version. Let me introduce next releases, which will contain a little bit more interesting features.
This release will go with two features, making life easier, especially for the newcomers to Phoenix.
Finally, you are not limited to the compile-time topic youāve set with broadcasting/1
macro in the commander. Now you can subscribe/2
to the external topic, receiving broadcasts sent to it.
iex> subscribe(socket, same_action(MyApp.MyController, :index))
:ok
iex> subscribe(socket, same_topic("product_#{42}"))
:ok
Phoenix.Presence
If configured (it is disabled by default), tracks the user presence on the topic. As an example, letās display the number of connected users, live:
defmodule MyAppWeb.MyCommander
use Drab.Commander
import Drab.Presence
broadcasting "global"
onconnect :connected
ondisconnect :disconnected
def connected(socket) do
broadcast_html socket, "#number_of_users", count_users(socket)
end
def disconnected(_store, _session) do
topic = same_topic("global")
broadcast_html topic, "#number_of_users", count_users(topic)
end
end
Actually, the similar code is already running on the Drab page. See the number in the upper right! And notice that is is actually showing the number of distinct browsers connected to the page. Yeah, Drab sets the browser UUID and stores it in the local storage. This is for anonymous pages, but you may track the presence also based on the user ID, stored in the session, with simple config :drab, :presence, id: :current_user_id
.
This will (hopefully) be the last API-chaning and breaking release before 1.0. Lots of depreciations, core API changes, so it might be painful for existing users, but it is worth. The goal is the holy grail for open source projects, v1.0.
After reaching the grail, I plan to focus on the education material, like docs, example page and the beginners guide to elixir |> phoenix |> drab. The goal is to convince more beginners that web programming of living pages does not have to be scary and painful
Then Iāll rest.
Lol, nope never.
Girls and boys,
v0.8.3 has landed.
Upgrading from the previous releases: please ensure you have :main_phoenix_app
configured in config.ex
. Iāve fixed a terrible bug of how Drab was searching for the application it is joining to.
This release introduces the final API. There is no intention to change it, unless very
significant errors are found.
If you are using Drab already, prepare for the changes in the configuration and also in the code.
Drab.Live
API changedAs described in #127, API has changed. The most painful change is Drab.Live.peek
, as it now
returns {:ok, value}
or {:error, why}
. Raising Drab.Live.peek
is for convinience.
Drab.Live.poke
returns tuple now as well, to catch update errors or disconnections.
Drab.Config
Since this version, Drab is no longer configured globally. This means that you may use it in the
multiple endpoints environments.
This requires configuration API change. Most of the Drab options are now located under
the endpoint module:
config :drab, MyAppWeb.Endpoint,
otp_app: :my_app_web,
...
The endpoint and application name are mandatory.
However, there are still few global options, like :enable_live_scripts
. Please read
Drab.Config
documentation
for more information.
All functions returning {:timeout, description}
now return just {:error, :timeout}
.
All handlers must now be strictly declared by using Drab.Commander.defhandler
or
Drab.Commander.public
macro.
defhandler my_handler(socket, payload), do: ..
or
public :my_handler
def my_handler(socket, payload), do: ...
The same is with shared commanders, if you want to use it, declare it with Drab.Controller
:
use Drab.Controller, commanders: [My.Shared.Commander]
drab-event
and drab-handler
combination no longer existsThe existing syntax drab-event
and drab-handler
is removed. Please use the new syntax of:
<tag drab="event:handler">
<input drab="focus:input_focus blur:input_blur"
<input drab-focus="input_focus" drab-blur="input_blur">
config.exs
Replace:
config :drab, main_phoenix_app: :my_app_web, endpoint: MyAppWeb.Endpoint
with:
config :drab, MyAppWeb.Endpoint, otp_app: :my_app_web
Most of the configuration options now must be placed under the endpoint. Please read
Drab.Config
documentation for more info.
A question, is there a way to run (javascript or queued command set) code on the client when the connection dies as a fallback that Iām missing? I want to display the connection is lost and disable some elements when the connection dies (which seems to happen after a few hours (24?) it seems as well as other conditions).