使用Fable获取文件输入内容

vil*_*asv 8 javascript html5 f# fable-f#

我已经看到了使用HTML5 File API从JavaScript文件输入中读取内容的简单方法.

这是我的view方法,在一个小  fable-arch应用程序中:

let view model =
    div [
        attribute "class" "files-form"
    ] [
        form [
            attribute "enctype" "multipart/form-data"
            attribute "action" "/feed"
            attribute "method" "post"
        ] [
            label [ attribute "for" "x_train" ] [ text "Training Features" ]
            input [
                attribute "id" "x_train"
                attribute "type" "file"
                onInput (fun e -> SetTrainingFeaturesFile (unbox e?target?value)) 
            ]
        ]
        model |> sprintf "%A" |> text
    ]
Run Code Online (Sandbox Code Playgroud)
  • 有没有一种简单的方法直接从F#捕获文件内容?
  • 完成此任务所需的最小互操作代码量是多少?

vil*_*asv 8

我找不到一种不写纯JavaScript的方法,主要是因为我无法FileReader从Fable 导入/实例化  .如果有人可以做到,那么解决方案可能会有所改善.

读取文件是异步的.这意味着视图应生成延迟模型更新.由于这只能在模型更新功能中完成,因此我必须在其中转发JavaScript文件句柄.

纯JavaScript只是一个导出黑客

// file interops.js, can I get rid of this?
export var getReader = function() { return new FileReader(); }
Run Code Online (Sandbox Code Playgroud)

在视图中

// view code
input [
    attribute "id" "x_train"
    attribute "type" "file"
    onInput (fun e -> FromFile (SetField, e?target?files?(0)))
]
Run Code Online (Sandbox Code Playgroud)

因此,该消息实际上是"带有文件内容的延迟消息".这是动作和更新代码:

type Action =
    | SetField of string
    | FromFile of (string -> Action) * obj

let update model action =
    match action with
    | SetField content ->
        { model with Field = content}, []
    | FromFile (setAction, file) ->
        let delayedAction h =
            let getReader = importMember "../src/interops.js"
            let reader = getReader()
            reader?onload <- (fun () ->  h <| setAction !!reader?result)
            reader?readAsText file |> ignore
        model, delayedAction |> toActionList
Run Code Online (Sandbox Code Playgroud)

FromFile是一个复杂的动作,因为我想用它来设置多个字段.如果你只需要一个,你可以只做一个of obj.


Max*_*gel 5

在最新版本的《神鬼寓言》中,我们现在可以访问Browser.Dom.FileReader并避免使用互操作。

可以这样写:

input 
    [ 
        Class "input"
        Type "file"
        OnInput (fun ev -> 
            let file = ev.target?files?(0)

            let reader = Browser.Dom.FileReader.Create()

            reader.onload <- fun evt ->
                dispatch (SaveFileContent evt.target?result)

            reader.onerror <- fun evt ->
                dispatch ErrorReadingFile

            reader.readAsText(file)
        ) 
    ]
Run Code Online (Sandbox Code Playgroud)

现场演示