Starlet9334

Starlet9334

Reactivity in hologram or, why do my buttons don't do anything

Hello there,

I am trying to understand reactivity in hologram.

I’ve create a simple component calculator.ex that I am calling like this <Calculator cid="calculator" value="20" />

This is my component definition:

defmodule Calculator do
  use Hologram.Component

  prop :value, :integer

  def template do
    ~HOLO"""
    <button class="btn" $click="plus">Plus</button>
    <button class="btn" $click="minus">Minus</button>

    <p>The value is {@value}</p>
    """
  end

  def init(props, component) do
    put_state(component, :value, props.value)
  end

  def action(:plus, _params, component) do
    put_state(component, :value, component.state.value + 1)
  end

  def action(:minus, _params, component) do
    put_state(component, :value, component.state.value - 1)
  end
end

However, the displayed value doesn’t change when I hit any of the buttons.

What am I doing wrong?

Marked As Solved

bartblast

bartblast

Creator of Hologram

Thank you!

There a few problems in the code:

1)
You’ve got duplicate :only option in the Plug.Static config:

plug Plug.Static,
  at: "/",
  from: :hologram_tutorial,
  gzip: not code_reloading?,
  only: HologramTutorialWeb.static_paths(),
  only: ["hologram" | HologramTutorialWeb.static_paths()]

should be:
only: ["hologram" | HologramTutorialWeb.static_paths()]

2)
You can’t use Phoenix routing-related stuff (like ~p sigil) in Hologram templates.
instead:
<link phx-track-static rel="stylesheet" href={~p"/assets/css/app.css"} />
use:
<link rel="stylesheet" href={asset_path("assets/css/app.css")} />

3)
Don’t use Phoenix CSRF tokens inside Hologram layouts.
remove:
<meta name="csrf-token" content={get_csrf_token()} />
CSRF protection is managed automatically by Hologram, you don’t have to think about it at all.

4)
You’re layout is broken, you need to use html as the root element, and nest header and footer elements inside the body element.

instead:

<head>
  <title>{@page_title}</title>
  <Hologram.UI.Runtime />
  <link rel="stylesheet" href={asset_path("assets/css/app.css")} />
</head>
<header>Header with menu</header>
<body>
  <slot />
</body>
<footer>Footer</footer>

use:

<!DOCTYPE html>
<html>
  <head>
    <title>{@page_title}</title>
    <Hologram.UI.Runtime />
    <link rel="stylesheet" href={asset_path("assets/css/app.css")} />
  </head>
  <body>
    <header>Header with menu</header>
    <slot />
    <footer>Footer</footer>
  </body>
</html>

5)
When initializing Hologram components server-side (e.g. when using the given component in a page template - since pages are always loaded from the server) you need to use init/3 instead of init/2.


For #5 the DX could be better and Hologram could allow to use init/2 in cases where there is no init/3 defined - added that to the backlog.

Also Liked

bartblast

bartblast

Creator of Hologram

Since fixing #5 alone solved everything, the repo you shared was probably different from your original code. No worries! Just want to make sure it’s clear - for you and anyone else reading this with similar issues: each of those 5 issues will cause Hologram to break in different ways, so if any are in your actual codebase, they’ll need addressing.

bartblast

bartblast

Creator of Hologram

Thanks, I’ll look at it!

Btw, this:

def init(props, component, server) do
  component = put_state(component, :value, props.value)

  {component, server}
end

Can be just this:

def init(props, component, _server) do
  put_state(component, :value, props.value)
end

you don’t have to return server struct if it’s not modified :slight_smile:

bartblast

bartblast

Creator of Hologram

I noticed that you initialized the value as a string, but you’re treating it as an integer using the plus/minus operators.

The runtime prop type validation isn’t working yet, which might be misleading you into thinking the value gets automatically converted to an integer. Is that what’s happening?

Where Next?

Popular in Questions Top

_russellb
I want to try my hand at web scraping. What tools/libraries do I need to use. I’m hoping to turn this into something professional so don’...
New
vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod – where is this set? Thanks.
New
minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
mgjohns61585
Could someone help me? I’m making my first elixir program, number guessing game. I can’t figure out how to convert the user’s guess from ...
New
shahryarjb
Hello, I get Persian date from my client and convert it to normal calendar like this: def jalali_string_to_miladi_english_number(persi...
New
Fl4m3Ph03n1x
About me? ( if you have nothing better to do than reading about some random guy in the internet :stuck_out_tongue: ) Hello all, this is ...
New
Qqwy
Original source of discussion: This topic on the Pragmatic Programmers’ Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
RisingFromAshes
I’ve read in another post that it may be possible with a router helper - but I couldn’t find an appropriate one, and tbh, I’m still just ...
New
svb
Hi! Currently I want to submit a form by pressing the Enter key. However, since my input field is of type “textarea” this is just adds a...
New

Other popular topics Top

hariharasudhan94
lets say i have a sample like a = 20; b = 10; if (a &gt; b) do {:ok, "a"} end if (a &lt; b) do {:ok, b} end if (a == b) do {:ok, "equa...
New
9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod – where is this set? Thanks.
New
minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
chrismccord
This release brings a number of exciting features, including integration with the new Phoenix LiveDashboard and Phoenix LiveView. There h...
New
freewebwithme
Using vs code and installed ElixirLS: support and debugger. And I got an error popped up on start up says Failed to run ‘elixir’ comma...
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
fayddelight
I tried installing elixir 1.11.2 erlang 23.3.4 via asdf in my zsh shell. Enabled the versions locally and globally. When I list them ...
New
klo
Got a question about when to concat vs. prepending items to list then reversing to achieve appending. So i know lists boil down to [1 | ...
New
hariharasudhan94
Lets say I have map like this fetching from my database %{"_id" =&gt; #BSON.ObjectId&lt;58eb1a7a9ad169198c3dXXXX&gt;, "email" =&gt; ...
New

We're in Beta

About us Mission Statement