Search code examples
serializationf#local-storagewebsharper

What local-storage tooling does WebSharper provide?


In looking at the documentation for WebSharper's local storage, the SetItem item is string * string -> unit (and GetItem is string -> string).

This means that I'll need to convert anything I want to store into strings and do the reverse to retrieve them. Or, to put it in another way, I'll need to serialize and de-serialize them. Is there a way to use the behind-the-scenes conversion that WebSharper already does for RPC calls, or am I stuck with using a server-side library like FsPicker?


Solution

  • Not built in yet, I have been using this helper module to make local storage usable the same way as a ref cell:

    open IntelliFactory.WebSharper
    
    // Helper for handling localstorage, making a stored value work like a ref cell.
    [<JavaScript; AutoOpen>]
    module LocalStorage =
        open IntelliFactory.WebSharper.Html5
    
        let localStorage = Window.Self.LocalStorage
    
        type IValue<'T> = 
            abstract Value: 'T with get, set
    
        let [<Inline>] ( ! ) (x: IValue<_>) = x.Value
        let [<Inline>] ( := ) (x: IValue<_>) v = x.Value <- v
    
        // Redefining Ref to use IValue
        type Ref<'T> (value: 'T) =
            let mutable v = value 
            interface IValue<'T> with
                member this.Value
                    with get() = v
                    and set value = v <- value
    
        let [<Inline>] ref v = Ref  v
        let incr i = i := !i + 1
        let decr i = i := !i - 1
    
        type IStorageItem<'T> =
            inherit IValue<'T>
            abstract Save: unit -> unit
            abstract Delete: unit -> unit
    
        type JSONStorageItem<'T>(key, defaultVal) = 
            let mutable value = None
    
            let getValue() =
                match value with
                | Some v -> v
                | _ ->
                    let v =
                        match localStorage.GetItem key with
                        | null -> defaultVal
                        | s -> 
                            Json.Parse s :?> _
                    value <- Some v
                    v
    
            interface IStorageItem<'T> with
                member this.Value
                    with get() = getValue()
                    and  set v =
                        try localStorage.SetItem(key, Json.Stringify v)  
                            value <- Some v 
                        with _ -> JavaScript.Alert "Saving data to storage failed."
    
                member this.Save() = 
                    try localStorage.SetItem(key, Json.Stringify (getValue()))  
                    with _ -> JavaScript.Alert "Saving data to storage failed."
    
                member this.Delete() =
                    localStorage.RemoveItem key
                    value <- None
    
        let [<Inline>] getJSONStorage key defaultVal = JSONStorageItem<_>(key, defaultVal) :> IStorageItem<_>
    

    However this can currently only stringify/parse straight data objects: record, list, array, tuple and union types are ok, but no prototypes are restored.