Doc.Checkbox 'change' 事件未发生在 Websharper.UI.Next

Doc.Checkbox 'change' event does not occur in Websharper.UI.Next

我有响应式 Var 变量 varDone 和 Doc.Checkbox 用于其名为 cbDoc 的表示。更改 varDone 的值后,我需要调用我的函数。为此,我编写了如下伪代码所示的代码:

open WebSharper
open WebSharper.UI.Next
open WebSharper.UI.Next.Html
open WebSharper.UI.Next.Notation

// declaring reactive bool variable
let varDone = Var.Create false

(* something else *)

// creting Doc-representation of my model
let renderModel model = 

    // declaring its representation Doc element
    let cbDone = Div0 [ Doc.CheckBox [ "type" ==> "checkbox" ] varDone ]

    let result'doc = // a Doc-representation, that contains cbDone

    let my'handler()  : unit -> unit = // a function that should be called when changing the value of varDone

    // add an event handler for the element cbDone changes
    (Doc.AsPagelet cbDone).Body.AddEventListener( "change", my'handler, false )

    result'doc

但不幸的是,更改复选框时没有发生任何事件。问题是,我做错了什么,是否有另一种方法来响应 varDone 变量值的变化?

UPD

最可悲的是,带有复选框的元素甚至没有我的事件处理程序。这在浏览器中调试时很明显。

编辑:下面的第二个解决方案是如何用当前 WebSharper.UI:

实现的
let cbDone =
    div [] [
        Doc.CheckBox [
            attr.``type`` "checkbox"
            on.viewUpdate varDone.View (fun _ _ -> my'handler())
        ] varDone
    ]

发生的事情是 Doc.AsPagelet 在文档周围添加了一个包装器,因此您正在向该包装器添加一个事件侦听器。即使没有,您也会向您创建的 Div0 添加一个事件侦听器,而不是 CheckBox 本身。

也就是说,这里有两个解决方案:

  • 简单的解决方案是在 CheckBox:

    中使用 Attr.Handler
    let cbDone =
      Div0 [
        Doc.CheckBox [
          "type" ==> "checkbox"
          Attr.Handler "change" (fun _ -> my'handler())
        ] varDone
      ]
    
  • 更复杂但通常更可取的解决方案是通过 View 监听对 varDone 的更改,而不是监听元素上的事件。

    现在,UI.Next 的工作方式是,只有连接到接收器(即呈现的文档)的视图才会被实际计算,因此如果您只执行以下操作,则不会发生任何事情:

    let _ = varDone.View |> View.Map (fun _ -> my'handler())
    

    相反,上述表达式的结果值(其类型为 View<unit>)需要连接到返回的文档。您可以使用以下助手(我们可能很快会以某种形式添加到 UI.Next):

    let AddViewListener (view: View<'T>) (f: 'T -> unit) (doc: Doc) =
      view
      |> View.Map (fun x -> f x; Doc.Empty)
      |> Doc.EmbedView
      |> Doc.Append doc
    

    您可以这样使用:

    let cbDone =
      Div0 [ Doc.CheckBox [ "type" ==> "checkbox" ] varDone ]
      |> AddViewListener varDone.View (fun _ -> my'handler())
    

    以上代码基本意思是"as long as cbDone is in the rendered document, any change to varDone will trigger my'handler".