module OptionInfix = Operators.Binding (Option) module State = struct type t = { word : string; len : int; counter : int; selected : Jstr.t } let repr_html : t -> Brr.El.t list = fun { word; len; counter; selected } -> [ Brr.El.div ~at:Brr.At.[ class' (Jstr.v "card") ] [ Brr.El.div ~at:Brr.At.[ class' (Jstr.v "card-header") ] [ Brr.El.header ~at:Brr.At.[ class' (Jstr.v "card-header") ] [ Brr.El.p ~at:Brr.At.[ class' (Jstr.v "card-header-title") ] [ Brr.El.txt' "Response from the server" ]; ]; ]; Brr.El.div ~at:Brr.At.[ class' (Jstr.v "card-content") ] [ Brr.El.form [ Elements.Form.input_field ~label:(Jstr.v "Word received") ~value':(Jstr.v word) (); Elements.Form.input_field ~label:(Jstr.v "Nb of car") ~value':(Jstr.of_int len) (); Elements.Form.input_field ~label:(Jstr.v "Request sent") ~value':(Jstr.of_int counter) (); Elements.Form.input_field ~label:(Jstr.v "Selected method") ~value':selected (); ]; ]; ]; ] end (** Service transforming the response from the request into the state *) module WordCount = struct type t = Services_impl.Nb_car.response let process response state = Brr.Console.log [ Jstr.v response.Services_impl.Nb_car.value; Int64.to_int response.Services_impl.Nb_car.nbcar; ]; State. { state with counter = state.counter + 1; word = response.Services_impl.Nb_car.value; len = Int64.to_int response.Services_impl.Nb_car.nbcar; } end module Capitalize = struct type t = Services_impl.Capitalize.response let process response state = Brr.Console.log [ Jstr.v response.Services_impl.Capitalize.value ]; State. { state with counter = state.counter + 1; word = response.Services_impl.Capitalize.value; } end (** Show how to react to a user event *) module SelectOption = struct type t = Jstr.t let process v state = State.{ state with selected = v } end module App = Application.Make (State) let main () = let open OptionInfix in let- content_div = Brr.Document.find_el_by_id Brr.G.document (Jstr.v "content") in let radio = Elements.Form.radio ~label:(Jstr.v "Method") ~name:(Jstr.v "method") ~values: [ { id' = None; label = Jstr.v "Count the letters"; value = Jstr.v "count"; checked = true; }; { id' = None; label = Jstr.v "Capitalize"; value = Jstr.v "capitalize"; checked = false; }; ] () in (* Catch the change event from the radio button list. Each radio button triggers it’s own event when selected, but the event bubbles, so we just listen the parent, and target the event source for reading the value. *) let radio_value = Note_brr.Evr.on_el Brr.Ev.change (fun evt -> let target_as_element : Brr.El.t = Brr.Ev.target evt |> Obj.magic in let raw_value = Brr.El.prop Brr.El.Prop.value target_as_element in App.dispatch (module SelectOption) raw_value) radio in let form = Brr.El.form [ Elements.Form.input_field ~name:(Jstr.v "text") ~id':(Jstr.v "text") ~label:(Jstr.v "Text") (); radio; Elements.Form.submit ~value':(Jstr.v "Send") (); ] in (* Listen the submit event on the form. This is an example of event of event : First we listen for the click event, and then for the request response event. *) let post_event : Brr.El.t -> App.event Note.event = fun form -> Note.E.join @@ Note_brr.Evr.on_el Brr_io.Form.Ev.submit (fun ev -> (* Do not send the query, we use it with javascript *) Brr.Ev.prevent_default ev; (* Extract the data from the form *) let data = Brr_io.Form.(Data.of_form (of_el form)) in let text_value = Brr_io.Form.Data.find data (Jstr.v "text") in let value = match text_value with | Some (`String s) -> Jstr.to_string s | _ -> "" in let service_name = Option.bind (Brr_io.Form.Data.find data (Jstr.v "method")) (function `String s -> Some (Jstr.to_string s) | _ -> None) in match service_name with | Some "count" -> (* Send the request *) Js_handler.send (module Services_impl.Nb_car) () { value } |> Note_brr.Futr.to_event |> Note.E.map (function | Error _ -> App.dispatch (module App.ID) () | Ok response -> App.dispatch (module WordCount) response) | Some "capitalize" -> (* Send the request *) Js_handler.send (module Services_impl.Capitalize) () { value } |> Note_brr.Futr.to_event |> Note.E.map (function | Error _ -> App.dispatch (module App.ID) () | Ok response -> App.dispatch (module Capitalize) response) | _ -> Note.E.never) form in let bottom = Brr.El.div [] in Brr.El.append_children content_div [ Brr.El.div ~at:Brr.At.[ class' (Jstr.v "card") ] [ Brr.El.div ~at:Brr.At.[ class' (Jstr.v "card-header") ] [ Brr.El.header ~at:Brr.At.[ class' (Jstr.v "card-header") ] [ Brr.El.p ~at:Brr.At.[ class' (Jstr.v "card-header-title") ] [ Brr.El.txt' "Request to the server" ]; ]; ]; Brr.El.div ~at:Brr.At.[ class' (Jstr.v "card-content") ] [ form ]; ]; Brr.El.hr (); bottom; ]; let state = App.run { word = ""; len = 0; counter = 0; selected = Jstr.v "count" } (Note.E.select [ post_event form; radio_value ]) in Note_brr.Elr.def_children bottom (Note.S.map State.repr_html state); let log state = ignore state in Note.Logr.hold (Note.S.log state log) let () = Brr.Console.(debug [ Jstr.v "Js started" ]); let open Jv in let post = obj [| ("start", repr main) |] in set global "client" post