In my Fable app with Elmish I have a view that uses react-slick and a button that should be able to change the slide number on click:
Fable.Import.Slick.slider
[ InitialSlide model.SlideNumber
AfterChange (SlideTo >> dispatch) ]
children
Button.button
[ Button.OnClick (fun _ev -> dispatch (SlideTo 5)) ]
[ str "Go to slide 5" ]
The react component for the slider is defined by react-slick
.
The fable wrapper I had to write on my own, so it's not complete because I only defined the properties I need.
module Fable.Import.Slick
open Fable.Core
open Fable.Core.JsInterop
open Fable.Helpers
open Fable.Helpers.React.Props
open Fable.Import.React
type SliderProps =
| InitialSlide of int
| AfterChange of (int -> unit)
interface IHTMLProp
let slickStyles = importAll<obj> "slick-carousel/slick/slick.scss"
let slickThemeStyles = importAll<obj> "slick-carousel/slick/slick-theme.scss"
let Slider = importDefault<ComponentClass<obj>> "react-slick/lib/slider"
let slider (b: IHTMLProp list) c = React.from Slider (keyValueList CaseRules.LowerFirst b) c
So while react-slick
defines a property InitialSlide
to set the slide that should initially be shown, there's no property to update the slide afterwards. There is a method slickGoTo
that should do what I want. But I don't know how or where to call that method while still being compliant with Elmish.
I could imagine that I have to extend the react component and listen to the model property and then call slickGoTo
whenever that property changes. But I don't know if that's possible.
So my question is: How can I have a button that changes the slide number on click using slickGoTo
that is defined by the component while not hacking the Elmish architecture?
An alternative to storing the reference to the slider object in the model is to use a mutable variable:
let mutable sliderRef : Browser.Element option = None
let gotoSlide n =
match sliderRef with None ->
| None -> ()
| Some slider -> slider?slickGoTo n
the rest is similar:
type Msg =
| CurrentSlide of int
| GotoSlide of int
...
let update msg model =
match msg with
| CurrentSlide n -> { model with slideNumber = n } , []
| GotoSlide n -> gotoSlide n ; model, []
Create your slider like this:
slider
[ Ref (fun slider = sliderRef <- Some slider)
AfterChange (CurrentSlide >> dispatch)
InitialSlide 0
]
slides