Interactive Nodes
Note: Blazor by default renders the content as static from dotnet 8 with blazor.web.js, so if you're rendering from the server you won't have any dynamic behavior, for that you need to set server interactivity for the component or use client side blazor (WASM). If your project was created with the
fun-wasm
template then you don't have to do anything else for this to work. For server interactivity and more information please check the Working With Blazor section.
While much of a website content is static, there are times where you have to match the content based on a value you had previously.
Adaptive Data
Fun.Blazor's way to deal with this is by using Adaptive Data which is included out of the box. Adaptive values behave a lot like excel cells, where a change propagates through the rest of the connected cells.
This concept has also been used within the javascript ecosystem in recent times often named signals
.
The adaptiview
builder will keep track of adaptive values and re-render the component when a change has been detected, this is provides an efficient rendering mechanism while also providing an immutable way to handle state changes in a view.
module DynamicViews =
open FSharp.Data.Adaptive
open Fun.Blazor
let adaptiveNode =
adapt {
let! age, setAge = cval(10).WithSetter()
section {
$"Age: {age}"
br
input {
type' "number"
value age
onchange (fun event -> unbox<string> event.Value |> int |> setAge)
}
}
}
Stores and Observables
Note: This requires the Fun.Blazor.Reactive package
Observables
Note: The examples here use the FSharp.Control.Reactive package due the functions it provides to help, but it is not required, any
IObservable<T>
works with Fun.Blazor
If you have observable information around it is quite simple to hook it up with Fun.Blazor by using the html.watch
API
module ReactiveViews =
open System
open Fun.Blazor
open FSharp.Control.Reactive
let obs = Observable.interval (TimeSpan.FromSeconds(1.))
article {
h1 { "My View" }
p {
html.watch(obs, (fun num -> fragment { $"Number: {num}" }), 0)
}
}
Stores
Another popular way to handle state changes in the frontend ecosystem is the usage of stores which are containers that keep data around for you. they are very similar to observables but they provide a simpler API to work with. Stores are also useful to bind dynamic attributes
module ReactiveViews =
open Fun.Blazor
let store: IStore<int> = new Store<int>(initialAge)
let view() =
let storeNode =
html.watch(store, (fun num -> fragment { $"Store: {num}" }))
article {
p { storeNode }
}
Both Observables and Stores can be converted into adaptive values to have a uniform data interface to work with