Completely agree, as already mentioned I’m also not sure for js_* prefix, so let’s see how people would like to write a code if they would prefer alias over import/use:
defmodule Chart do
alias Hologram.JS
def draw(element_id, width, height, data_points) do
element =
"document"
|> JS.ref()
|> JS.call("getElementById", [element_id])
if is_nil(JS.unwrap(element)) do
# handle case when element is missing
end
"Chart"
|> JS.ref()
|> JS.create([element, %{width: width, height: height}])
|> JS.call("draw", [data_points])
end
end
I’m not only sure about JS.unwrap/1 … It would be absolutely amazing if we could use unwrapped element in JS API, see:
defmodule Chart do
alias Hologram.JS
def draw(element_id, width, height, data_points) do
element =
"document"
|> JS.ref()
# already unwrapped after this call
|> JS.call("getElementById", [element_id])
if is_nil(element) do
# handle case when element is missing
end
"Chart"
|> JS.ref()
|> JS.create([element, %{width: width, height: height}])
|> JS.call("draw", [data_points])
end
end
This would not only simplify the code, but would be a lot easier for creating a said high-level APIs. We could use a special map key. Let’s call it a __hologram_unwrap__ (instead of __struct__ special key) for now. What do you think about it?
Maybe instead of taking ref from String.t() we could use atoms in low-level API. Think that instead of JS.ref("Chart") we simply use :Chart and JS.ref("document") would be changed to :document. Hologram should not care what way is used and this solution could really improve the DX.
If both ideas would be accepted this is how the updated code would look like:
defmodule Chart do
alias Hologram.JS
def draw(element_id, width, height, data_points) do
# already unwrapped
element = JS.call(:document, "getElementById", [element_id])
if is_nil(element) do
# handle case when element is missing
end
# no extra calls just to create JS reference - it would be done by Hologram itself
:Chart
|> JS.create([element, %{width: width, height: height}])
|> JS.call("draw", [data_points])
end
end
Look that we don’t really need a high-level API to make code much cleaner. It perfectly follows Elixir’s 10x less code rule, so we only focus on the logic of our application. From here the high-level API would in fact be something like a syntax sugar, see:
defmodule MyHologramLib.HighLevelJS do
alias Hologram.JS
def get_element_by_id(atom_or_unwrapped \\ :document, id) do
JS.call(atom_or_unwrapped, "getElementById", [id])
end
end
It’s so simple! Doesn’t it look just amazing? ![]()






















