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 |