使用 Fable 获取文件输入内容
Getting file input content with Fable
我看到 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# 捕获文件内容的简单方法?
- 完成此操作所需的最少互操作寓言代码量是多少?
I couldn't find a way to not write plain JavaScript mainly because I couldn't import/instantiate FileReader
from Fable. If someone can do it, then the solution can probably improve.
读取文件是异步的。这意味着视图应该生成延迟的模型更新。由于这只能在模型更新功能中完成,我不得不在里面转发一个 JavaScript 文件句柄。
普通的 JavaScript 只是一个导出 hack
// 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)))
]
所以消息实际上是 "Delayed Message with File Content"。这是操作和更新代码:
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
。
在最新版本的寓言中,我们现在可以访问 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)
)
]
这是我对 Maxime 的回答的看法,使用 Fable.Elmish.React v3.0.1。我不熟悉?运算符,但我可以使用 :?> 来转换某些类型。
input [
Class "input"
Type "file"
OnInput (fun ev ->
let file = (ev.target :?> Browser.Types.HTMLInputElement).files.Item(0)
let reader = Browser.Dom.FileReader.Create()
reader.onload <- fun evt ->
(*
Negotiate/assume the onload target is a FileReader
Result is a string containg file contents:
https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readAsText
*)
dispatch (Set (string (evt.target :?> Browser.Types.FileReader).result))
reader.onerror <- fun evt ->
dispatch (Set "Error")
reader.readAsText(file))]
我看到 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# 捕获文件内容的简单方法?
- 完成此操作所需的最少互操作寓言代码量是多少?
I couldn't find a way to not write plain JavaScript mainly because I couldn't import/instantiate
FileReader
from Fable. If someone can do it, then the solution can probably improve.
读取文件是异步的。这意味着视图应该生成延迟的模型更新。由于这只能在模型更新功能中完成,我不得不在里面转发一个 JavaScript 文件句柄。
普通的 JavaScript 只是一个导出 hack
// 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)))
]
所以消息实际上是 "Delayed Message with File Content"。这是操作和更新代码:
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
。
在最新版本的寓言中,我们现在可以访问 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)
)
]
这是我对 Maxime 的回答的看法,使用 Fable.Elmish.React v3.0.1。我不熟悉?运算符,但我可以使用 :?> 来转换某些类型。
input [
Class "input"
Type "file"
OnInput (fun ev ->
let file = (ev.target :?> Browser.Types.HTMLInputElement).files.Item(0)
let reader = Browser.Dom.FileReader.Create()
reader.onload <- fun evt ->
(*
Negotiate/assume the onload target is a FileReader
Result is a string containg file contents:
https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readAsText
*)
dispatch (Set (string (evt.target :?> Browser.Types.FileReader).result))
reader.onerror <- fun evt ->
dispatch (Set "Error")
reader.readAsText(file))]