View difference between Paste ID: cp8kw3JQ and sxaMRnFP
SHOW: | | - or go back to the newest paste.
1
namespace Validation_Scratchpad
2
3
open System
4
open IntelliFactory.WebSharper
5
open IntelliFactory.WebSharper.UI.Next
6
open IntelliFactory.WebSharper.UI.Next.Html
7
8
[<JavaScript>]
9
module Client =
10
11
    // Model-y Stuff Here
12
    type EMailAddress = EMail of string
13
    type TelephoneNumber = TN of string
14
15
    let showPhone (TN s) = s
16
    let showEMail (EMail e) = e
17
18
    type Person =
19
        {
20
            PersonName : string
21
            PersonEMailAddress : EMailAddress
22
            PersonTelephoneNumber : TelephoneNumber
23
        }
24
25
    let mkPerson name num email =
26
        {
27
            PersonName = name
28
            PersonEMailAddress = email
29
            PersonTelephoneNumber = num
30
        }
31
32
    // Define Result sum type
33
    type ErrorMsg = string
34
    type Result<'a> = | Success of 'a | Failure of ErrorMsg
35
36
    // Helpers
37
    let txt = Doc.TextNode
38
    let (==>) attrId attrVal = Attr.Create attrId attrVal
39
40
    // Validation: takes num var, produces Result<TelephoneNumber>
41
    let validateNum vNum =
42
        View.FromVar vNum
43
        |> View.Map (fun num ->
44
            if String.forall Char.IsDigit num && num.Length > 0 then
45
                TN num |> Success
46
            else
47
                Failure "Not a valid telephone number"
48
        )
49
50
    // Same for email
51
    let validateEmail vEmail =
52
        View.FromVar vEmail
53
        |> View.Map (fun (email : string) ->
54
            if email.Contains("@") then
55
                EMail email |> Success
56
            else
57
                Failure "Not a valid email address"
58
        )
59
60
    // Displays nothing if success, err if failure
61
    let DisplayFailure = function
62
        | Success _ -> ""
63
        | Failure err -> err + ", "
64
65
66
    // View.Do and let! translate to View.Bind, so this updates whenever
67
    // any of the fields change.
68
    // We take a View<string> for name, and View<Result<TelephoneNumber>> and
69
    // View<Result<EmailAddress>> for the validated fields
70
    // NOTE: This won't compile in W# in the public UI.Next just yet (we forgot a JS tag)
71
    // but will do on next release
72
    let PersonView nameView telView emailView =
73
        View.Do {
74
            let! name = nameView
75
            let! tel = telView
76
            let! email = emailView
77
            match (tel, email) with
78
                // If successfully validated for both, we can construct a View<Success<Person>>
79
                | (Success t, Success e) ->
80
                    return mkPerson name t e |> Success
81
                | _ ->
82
                    // If not, we concat the errors to get a failure
83
                    // This is the bit I'm not happy about -- would be much nicer to make this more
84
                    // general
85
                    return
86
                        DisplayFailure tel + DisplayFailure email
87
                        |> Failure
88
        }
89
90
91
    // Person -> Doc
92
    let showPerson p =
93
        Div0 [
94
            P0 [txt <| "Name: " + p.PersonName]
95
            P0 [txt <| "Phone Number: " + (showPhone p.PersonTelephoneNumber)]
96
            P0 [txt <| "EMail Address: " + (showEMail p.PersonEMailAddress)]
97
        ]
98
99
    // Result<Person> -> Doc
100
    let ShowResult personView =
101
        personView
102
        |> View.Map (fun personRes ->
103
            match personRes with
104
                | Success p -> showPerson p
105
                | Failure errs -> txt errs
106
        )
107
108
    // Form and main document
109
    let myForm =
110
        // Create variables
111
        let rvName = Var.Create ""
112
        let rvTel = Var.Create ""
113
        let rvEmail = Var.Create ""
114
115
        Div0 [
116
            Div0 [
117
                // Create form controls
118
                Div0 [
119
                    Html.Label ["for" ==> "nameBox"] [txt "Name:"]
120
                    Doc.Input ["id" ==> "nameBox"] rvName
121
                ]
122
123
                Div0 [
124
                    Html.Label ["for" ==> "telBox"] [txt "Telephone Number:"]
125
                    Doc.Input ["id" ==> "telBox"] rvTel
126
                ]
127
128
                Div0 [
129
                    Html.Label ["for" ==> "emailBox"] [txt "Email:"]
130
                    Doc.Input ["id" ==> "emailBox"] rvEmail
131
                ]
132
            ]
133
134
            Div0 [
135
                txt "Result"
136
                Elements.Br [][]
137
                // validateNum and validateEmail perform validation on the names and emails,
138
                // producing View<Result<TelephoneNumber>> and View<Result<EMailAddress>>
139
                PersonView (View.FromVar rvName) (validateNum rvTel) (validateEmail rvEmail)
140
                |> ShowResult
141
                |> Doc.EmbedView
142
            ]
143
        ]
144
145
    let Main =
146
        JavaScript.Log("Running JavaScript Entry Point..")
147
        Doc.RunById "my-container" myForm