使用Fable获取文件输入内容

时间:2017-01-01 21:19:18

标签: javascript html5 f# fable-f#

我已经看过simple ways使用HTML5文件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
    ]
  • 是否有一种直接从F#中捕获文件内容的简单方法?
  • 完成此操作所需的最小互操作代码量是多少?

2 个答案:

答案 0 :(得分:8)

  

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

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

纯JavaScript只是一个导出黑客

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

在视图中

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

因此该消息实际上是“带文件内容的延迟消息”。这是动作和更新代码:

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

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

答案 1 :(得分:4)

在最新版本的寓言中,我们现在可以访问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)
        ) 
    ]

Live demo