Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
    Shmew
    @Shmew
    Does a record type with one of the values being an option have that value be null when it's cast to a pojo or remove the property entirely?
    Florian Verdonck
    @nojaf
    Would think null, if the option is None. Try out the online REPL to be sure, you can easily see the compiled js there
    Shmew
    @Shmew
    Oh I didn't know that existed, very awesome. Thanks
    Thiago Temple
    @thitemple
    Does anyone have a good suggestions for working with forms with Elmish?
    Shmew
    @Shmew
    @thitemple I know https://github.com/MangelMaxime/Thoth has form builder libraries but I haven't used them
    Florian Verdonck
    @nojaf
    @thitemple I'm experimenting with Formik if you are interested, https://jaredpalmer.com/formik/
    Thiago Temple
    @thitemple
    @nojaf do you have the bindings for that somewhere?
    Florian Verdonck
    @nojaf
    I have some in my own project
    Yup:
    #load "./Common.fsx"
    
    open System.Text.RegularExpressions
    open Fable.Core
    open Fable.Core.JS
    open Fable.Core.JsInterop
    
    type SchemaDescription =
        { ``type``: string
          label: string
          meta: obj
          tests: obj array
          fields: obj }
    
    type ValidateOptions =
        { strict: bool option
          abortEarly: bool option
          stripUnknown: bool option
          recursive: bool option
          context: obj option }
    
    type ValidationError =
        { name: string
          message: string
          value: obj option }
    
    type [<AllowNullLiteral>] Schema<'T> =
        abstract clone: unit -> Schema<'T>
        abstract label: label: string -> Schema<'T>
        abstract meta: metadata: obj option -> Schema<'T>
        abstract meta: unit -> obj option
        abstract describe: unit -> SchemaDescription
        abstract concat: schema: Schema<'T> -> Schema<'T>
        abstract validate: value: obj option * ?options: ValidateOptions -> Promise<'T>
        abstract validateSync: value: obj option * ?options: ValidateOptions -> 'T
        abstract validateAt: path: string * value: 'T * ?options: ValidateOptions -> Promise<'T>
        abstract validateSyncAt: path: string * value: 'T * ?options: ValidateOptions -> 'T
        abstract isValid: value: obj option * ?options: obj -> Promise<bool>
        abstract isValidSync: value: obj option * ?options: obj -> bool
        abstract cast: value: obj option * ?options: obj -> 'T
        abstract isType: value: obj option -> bool
        abstract strict: isStrict: bool -> Schema<'T>
        abstract strip: strip: bool -> Schema<'T>
        abstract withMutation: fn: (Schema<'T> -> unit) -> unit
        abstract ``default``: value: obj option -> Schema<'T>
        abstract ``default``: unit -> 'T
        abstract typeError: ?message: string -> Schema<'T>
        //abstract oneOf: arrayOfValues: Array<U2<'T, Ref>> * ?message: string -> Schema<'T>
        abstract notOneOf: arrayOfValues: ResizeArray<obj option> * ?message: string -> Schema<'T>
        //abstract ``when``: keys: U2<string, ResizeArray<obj option>> * builder: WhenOptions<Schema<'T>> -> Schema<'T>
        abstract test: name: string * message: string * test: (TestContext -> obj -> U3<bool, ValidationError, Promise<U2<bool, ValidationError>>>) * ?callbackStyleAsync: bool -> Schema<'T>
        abstract test: name: string * message: string * test: ('T -> bool) -> Schema<'T>
        //abstract test: options: TestOptions -> Schema<'T>
        //abstract transform: fn: TransformFunction<Schema<'T>> -> Schema<'T>
    
    and TestContext =
        { path: string
          options: ValidateOptions
          parent: obj option
          schema: Schema<obj>
          resolve: (obj option -> obj option)
          createError: (string -> ValidationError) }
    
    type [<AllowNullLiteral>] MixedSchema<'T> =
        inherit Schema<'T>
        abstract nullable: ?isNullable: bool -> MixedSchema<'T>
        abstract required: ?message: string -> MixedSchema<'T>
        abstract notRequired: unit -> MixedSchema<'T option>
        abstract concat: schema: MixedSchema<'T> -> MixedSchema<'T>
        abstract concat: schema: MixedSchema<'U> -> MixedSchema<U2<'T, 'U>>
    
    type [<AllowNullLiteral>] StringSchema =
        inherit Schema<string>
        abstract length: limit: float * ?message: string -> StringSchema
        abstract min: limit: float * ?message: string -> StringSchema
        abstract max: limit: float * ?message: string -> StringSchema
        abstract matches: regex: Regex * ?messageOrOptions: string-> StringSchema
        abstract email: ?message: string -> StringSchema
        abstract url: ?message: string -> StringSchema
        abstract ensure: unit -> StringSchema
        abstract trim: ?message: string -> StringSchema
        abstract lowercase: ?message: string -> StringSchema
        abstract uppercase: ?message: string -> StringSchema
        abstract nullable: ?isNullable: bool -> StringSchema
        abstract required: ?message: string -> StringSchema
        abstract notRequired: unit -> StringSchema
    
    type [<AllowNullLiteral>] FloatNumberSchema =
        inherit Schema<float>
        abstract min: limit: float * ?message: string -> FloatNumberSchema
        abstract lessThan: limit: float * ?message: string -> FloatNumberSchema
        abstract moreThan: li
    Formik:
    #load "../../../.paket/load/netstandard2.0/client/client.group.fsx"
    #load "./Yup.fsx"
    
    open Fable.Core.JsInterop
    open Fable.React
    open Browser.Types
    
    type FormikProps<'t> =
        { values: 't
          errors: obj
          status: obj
          touched: bool
          handleBlur: string -> unit
          handleChange: string -> unit
          handleSubmit: Event -> unit
          isSubmitting: bool }
    
        member this.GetError name =
            let decoder =
                Thoth.Json.Decode.object (fun get -> get.Optional.Field name Thoth.Json.Decode.string)
            let result =
                Thoth.Json.Decode.fromValue "$" decoder this.errors
    
            match result with
            | Ok(Some err) -> Some err
            | Ok(None) -> None
            | Error err ->
                failwithf "Could not decode error message for field '%s', %A" name err
    
        member this.GetErrorsBy (decoder: Thoth.Json.Decoder<string list>) name =
            let result = Thoth.Json.Decode.fromValue "$" decoder this.errors
            match result with
            | Ok(err) -> err
            | Error err -> failwithf "Could not decode error message for field '%s', %A" name err
    
    type FormikActions =
        { setSubmitting: bool -> unit }
    
    let private Formik_ : ReactElementType = import "Formik" "formik"
    
    let Formik<'t> (onSubmit: (System.Action<'t,obj>)) (render: (FormikProps<'t> -> ReactElement)) (validationSchema: Yup.Schema<'t>) (initialValues: 't) =
        let props =
            createObj [ "initialValues" ==> initialValues
                        "onSubmit" ==> onSubmit
                        "render" ==> render
                        "validationSchema" ==> validationSchema ]
        ReactBindings.React.createElement(Formik_, props, [])
    
    type FieldRenderOptions<'t> =
        { onChange: Event -> unit
          onBlur: Event -> unit
          name: string
          value: 't }
    
    type FormInField =
        { errors: Map<string,string> }
    
    type FieldProps<'t, 's> =
        { field: FieldRenderOptions<'t>
          form: FormikProps<'s> }
    let private Field_ : ReactElementType = import "Field" "formik"
    let Field<'t,'s> (name: string) (render: FieldProps<'t,'s> -> ReactElement) =
        let props =
            createObj [ "name" ==> name
                        "render" ==> render ]
        ReactBindings.React.createElement(Field_, props, [])
    All very much WIP
    Thiago Temple
    @thitemple
    @nojaf thanks for that, I'll give it a try tomorrow
    Utkarsh Kukreti
    @utkarshkukreti
    Is it intentional that array indexing is not bounds checked at runtime? The following compiles to x[100] with no index check:
    let x = [| 10 |]
    let y = x.[100]
    In the native F# repl I get: System.IndexOutOfRangeException: Index was outside the bounds of the array.
    Ilja Nosik
    @inosik
    That seems to be the default JS behavior. Try Array.tryItem, it checks if the index is in the range and returns 'a option
    kerams
    @kerams
    Any idea how to get rid of this? Started getting it after updating to Fable 3.
    Fable.Elmish.3.0.5/cmd.fs(144,31): (144,42) warning FABLE: Async.Start will behave as StartImmediate - Inline call from ../../src/Client/Client.fs(80,4)
    let getItemDetailCmd itemId =
        Cmd.OfAsync.either Server.api.getItemDetail itemId O2 Error
    Shmew
    @Shmew
    it's actually because of an elmish update
    Utkarsh Kukreti
    @utkarshkukreti
    @inosik yes. I'm just surprised how easy it is to run into runtime errors in Fable. In OCaml/BuckleScript array indexing is bounds check by default (and there's also a way to get option)
    Shmew
    @Shmew
    do Cmd.OfAsyncImmediate
    @kerams
    kerams
    @kerams
    Beautiful, thanks.
    Shmew
    @Shmew
    np
    JBotto
    @jbotto94
    Hello, does anyone know of a simple example which illustrates how to use Fable to compile NUnit tests?
    Ilja Nosik
    @inosik
    @jbotto94 There used to be a plugin for Fable 1 which did that, but Fable doesn't support plugins anymore. I think you'd be better off using a JS test library. Take a look at Fable itself, the test suite uses Expecto on .NET and Mocha on Node. Or Fable.Mocha, which looks nice.
    JBotto
    @jbotto94
    @inosik Thank you for your answer. I will have a look
    Stefan Cullmann
    @SCullman

    I am trying to upgrade a project to fable3 (and all other new packages).
    However, the files within the .fable folder are outdated, which causes errors on compilation like

    ERROR in ./.fable/Fable.Elmish.2.0.3/cmd.fs
    Module Error (from ./node_modules/fable-loader/index.js):
    #####/.fable/Fable.Elmish.2.0.3/cmd.fs(98,48): (98,55) error FSHARP: The type 'Promise' is not defined in 'Fable.Import.JS'. (code 39)

    Entries within paket.lock look fine:

    GROUP Client
    STORAGE: NONE
    RESTRICTION: == netstandard2.0
    NUGET
      remote: https://www.nuget.org/api/v2
       ...
        Fable.Elmish (3.0.5)
          Fable.Core (>= 3.0)
          FSharp.Core (>= 4.6.2)...
    Florian Verdonck
    @nojaf
    Promise is now part of Fable.Core.JS
    And some helpers are found in https://www.nuget.org/packages/Fable.Promise/
    Stefan Cullmann
    @SCullman
    I know. But it also should use Fable.Elmish 3.0.5 instead of 2.0.3.
    Stefan Cullmann
    @SCullman
    After deleting a lot of folder (.obj, .folder), clearing up the nuget cache, etc ... it was still not working.
    Then I removed the paket group Build for fake, and suddenly all correct fable files appeared in .fable. Afterwards I rolled back to the former paket.dependency and both fable and fake work again.
    kerams
    @kerams
    Delete .fable. It will be recreated
    Kevin Lanthier
    @klanthier

    Question for the community that work close with react

    I have this react component, that has sub components inside of itself, say for example, when you call the react component banner, it generates this for himself :

    <div>
        <InsideComponent dismiss={}>
    </div>

    I'm trying to use the pattern with DU types using fable jsinterop to convert my Capitalized props to lower case using (keyValueList CaseRules.LowerFirst props), but it only does so for the first level of props passed to the function, not the subsequent ones.
    I was wondering if there is some technique out there that would allow to convert all of the keyvalues inside a DU type (including child elements of that type) to lowercase, not just the top level props.

    Example of my use case:

    type BannerAction = 
        | Dismiss of (unit -> unit)
    
    type BannerProps =
        | Action of BannerAction
    
    let inline banner (props : BannerProps list) (elems : ReactElement list) : ReactElement =
        ofImport "Banner" "MyBannerComponent" (keyValueList CaseRules.LowerFirst props) elems   // This is where id need something like keyValueListOfAllProps

    Final result right now makes it that it create some sort of object in javascript like that :

    {
        action: {
            Dismiss: function   // <--- need this one uncapitalized as well
       }
    }
    Maxime Mangel
    @MangelMaxime
    Hello @klanthier you need to create an "helper" in order to call keyValueList against Action args something similar to:
    static member Style (css: Props.CSSProp list) : MapProps = unbox ("style", keyValueList CaseRules.LowerFirst css)
    Kevin Lanthier
    @klanthier
    @MangelMaxime So there's no way to loop through all the childs props and do it in one go ? I assume I need to handle each of those cases seperately ?
    Maxime Mangel
    @MangelMaxime

    @klanthier Yes there ways to do it using dynamic programming, but it would be less performs because you would try to iterate over properties that don't need to be iterated on. For example, if one of the props is just a string, etc.

    It's better IHMO to call keyValueList only where it's needed to will keep your binding code clean and "optimize" it

    Kevin Lanthier
    @klanthier

    @MangelMaxime how do you proceed in that case ?
    Say I have :

    type BannerProps =
        | Action of BannerAction
        | Text of String
        | OtherProp of String
        | SomeBool of Bool

    How would you apply a top level lowercasing first, and then handle the BannerAction guy seperately ?

    Maxime Mangel
    @MangelMaxime

    @klanthier You can do it like that:

    open Fable.Core
    open Fable.Core.JsInterop
    
    type BannerAction =
        | Dismiss of bool
    
    type BannerProps =
        | Text of string
        | OtherProp of string
        | SomeBool of bool
    
    let Action (actions : BannerAction list) =
        unbox ("action", keyValueList CaseRules.LowerFirst actions)
    
    let inline banner (props : BannerProps list) =
        (keyValueList CaseRules.LowerFirst props)
    
    let value =
        banner 
            [
                Text "Maxime"
                OtherProp "Mangel"
                SomeBool true
                Action
                    [
                        Dismiss false
                    ]
            ]

    or personally I prefer this way:

    open Fable.Core
    open Fable.Core.JsInterop
    
    [<RequireQualifiedAccess>]
    type BannerAction =
        | Dismiss of bool
    
    [<RequireQualifiedAccess>]
    type BannerProps =
        | Text of string
        | OtherProp of string
        | SomeBool of bool
        static member Action (actions : BannerAction list) =
            unbox ("action", keyValueList CaseRules.LowerFirst actions)
    
    let inline banner (props : BannerProps list) =
        (keyValueList CaseRules.LowerFirst props)
    
    let value =
        banner 
            [
                BannerProps.Text "Maxime"
                BannerProps.OtherProp "Mangel"
                BannerProps.SomeBool true
                BannerProps.Action
                    [
                        BannerAction.Dismiss false
                    ]
            ]
    This gives you:
    {
      "text": "Maxime",
      "otherProp": "Mangel",
      "someBool": true,
      "action": {
        "dismiss": false
      }
    }
    Kevin Lanthier
    @klanthier
    @MangelMaxime Thanks a lot, I think this is a really good approach and will definitely make use of !
    Aleksander Spro
    @projecteon
    @MangelMaxime Nice, might incorporate that too
    Anyone have any ideas why my app page reloads on hot reload? Or ideas how to debug it. I have one page that does this. Others are ok.
    using fable/elmish btw
    Maxime Mangel
    @MangelMaxime
    @projecteon Perhaps, you activated the live reload, in your webpack config if the hot reload failed (had an exception during execution)
    Shmew
    @Shmew
    does fable support System.Uri?
    Ilja Nosik
    @inosik
    Yes, but some properties are not supported
    Aleksander Spro
    @projecteon
    @MangelMaxime Could you redirect me on what to look at for that? I'm semi into webpack but I havent look at the api that much since 2.0 and relied on "template works" :)
    Maxime Mangel
    @MangelMaxime

    @projecteon It's just something I read in the past. So I don't have a specific page for that.

    Another, thing that come in minds is that perhaps you have a code in your app page that ask for a reload or url change. You could try make the logs persistant between page reload in your browser (their is a checkbox for that in theory). And activate the Program.withConsoleTrace to see if something is triggered.

    Aleksander Spro
    @projecteon
    Im already using withConsolTrace in debug env. Ill have a look the other things, thank you @MangelMaxime
    Aleksander Spro
    @projecteon

    I found the issue. It tries to hot reload vendor-js from the wrong url. It adds the current sub path to the root ..
    My location on hotreload

    http://localhost:8080/somesubpath/somesubsubpath

    Tries to reload from

    http://localhost:8080/somesubpath/vendors.js
    Aleksander Spro
    @projecteon
    Found it:
    webpack output needs the publicPath property set