View Source Methods
This guide will cover methods - the main way to add interactions to your app. Methods are functions that are used to change your app's state.
The State
A Tamnoon app maintains a state for each client - a map of key-value pairs that can be read and updated in response to user interactions. This state is initialized as part of your Tamnoon options, either directly or as a function returning a map:
def start(_type, _args) do
children = [
{Tamnoon, [[
# Could also have been `initial_state: %{...}`
initial_state: fn -> %{
message: "Hello World!",
button_hidden: true,
username: "user"
} end,
# Other options...
]]}
]
...
endNote: State keys must be atoms - not strings.
To interact with the application state, you'll need to use Tamnoon HEEx, which is covered in the next guide.
Methods
Methods are Elixir functions triggered by user interactions in the UI. They allow you to perform logic and update the application state. Methods are defined using the Tamnoon.MethodManager.defmethod/2 macro inside designated methods modules.
Defining a Methods Module
To define a methods module, create a new Elixir module - typically placed under lib/methods/ - and register it in your Tamnoon options:
def start(_type, _args) do
children = [
{Tamnoon, [[
methods_modules: [
MyApp.Methods.MyMethodsModule
]
# Other options...
]]}
]
...
endDefining a Method
Inside your methods module, import Tamnoon.MethodManager and use the Tamnoon.MethodManager.defmethod/2 macro to define methods:
defmodule MyApp.Methods.MyMethodsModule do
import Tamnoon.MethodManager
defmethod :ping do
IO.inspect("pong")
{%{}}
end
endIn this example:
:pingis the name of the method.The method prints
"pong"to the console.It returns a tuple
{diffs}, wherediffsis a map of state changes.
Method Parameters
The Tamnoon.MethodManager.defmethod/2 macro provides your method with two arguments:
state: The current application state as a map.req: A map containing metadata about the method invocation::value: The value of the element that triggered the method.:key: A custom key provided when invoking the method (optional, only included if one is provided).:element: The raw HTML string of the invoking element.
Method Return Values
A method must return one of the following:
An empty tuple
{}.A single-element tuple
{diffs}.A two-element tuple
{diffs, actions}.A three-element tuple
{diffs, actions, new_state}.
The second element,
actions, will be explained in the Actions guide.
diffs: A map of state changes that will be sent to the client.new_state: The updated full state after the method is executed. If not provided,diffswill be merged into the state automatically.
Example
The snippet below is a full example of a methods module containing a method :increment which increments a :counter value:
defmodule MyApp.Methods.CounterMethods do
import Tamnoon.MethodManager
defmethod :increment do
current_count = Map.get(state, :counter)
{%{counter: current_count + 1}}
end
endCalling Methods From Other Methods
Tamnoon allows you to call one method from another, which is useful for composing logic and avoiding duplication.
There are two main ways to do this:
- Manual invocation
You can directly invoke a method from within another by calling the underlying function it defines.
Built-in methods can be called using
Tamnoon.Methods.<function_name>.Custom methods defined using
Tamnoon.MethodManager.defmethod/2are available as regular functions with the prefixtmnn_in the defining module.
The result of the invoked method must be manually handled and returned from the calling method.
Example
In the example below, triggering the :ping_and_color method will update the :message to "pong" and set its color to "green":
defmethod :ping do
{%{message: "pong"}}
end
defmethod :ping_and_color do
{%{message: message}} = tmnn_ping(%{}, state)
{%{message_color: "green", message: message}}
endHere:
tmnn_ping/2 is called with an empty req and the current state.
Its result is destructured and merged with additional changes before returning.
- Using
trigger_method/3
Tamnoon also provides the Tamnoon.MethodManager.trigger_method/3 function, which allows you to invoke a method by name from within another method.
trigger_method(method_name :: atom, req :: map, timeout_ms :: integer)method_name- The name of the method to trigger (as an atom).req- A map that will be passed as the method’s req argument.timeout_ms- (Optional) Time in milliseconds before the method runs. Omit or use 0 for immediate execution.
Key Difference
Unlike manual invocation, trigger_method/3 automatically sends the result of the called method to the client. This means you don't need to merge or return the result yourself - the response is handled for you.
Example
defmethod :ping do
{%{message: "pong"}}
end
defmethod :ping_and_color do
Tamnoon.MethodManager.trigger_method(:ping, %{}, 1000)
{%{message_color: "green"}}
endIn this example:
When
:ping_and_coloris triggered, the:message_coloris immediately updated to"green".After 1 second, the
:pingmethod is triggered, updating the:messageto"pong".
This is especially useful for delayed interactions, animations, or chaining state updates over time.
Built-In Methods
Tamnoon includes a set of built-in methods available for use in your application. Their documentation is located in the Tamnoon.Methods module.