odac 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.editorconfig +21 -0
- package/.github/workflows/auto-pr-description.yml +49 -0
- package/.github/workflows/release.yml +32 -0
- package/.github/workflows/test-coverage.yml +58 -0
- package/.husky/pre-commit +2 -0
- package/.kiro/steering/code-style.md +56 -0
- package/.kiro/steering/product.md +20 -0
- package/.kiro/steering/structure.md +77 -0
- package/.kiro/steering/tech.md +87 -0
- package/.prettierrc +10 -0
- package/.releaserc.js +134 -0
- package/AGENTS.md +84 -0
- package/CHANGELOG.md +181 -0
- package/CODE_OF_CONDUCT.md +83 -0
- package/CONTRIBUTING.md +63 -0
- package/LICENSE +661 -0
- package/README.md +57 -0
- package/SECURITY.md +26 -0
- package/bin/candy +10 -0
- package/bin/candypack +10 -0
- package/cli/index.js +3 -0
- package/cli/src/Cli.js +348 -0
- package/cli/src/Connector.js +93 -0
- package/cli/src/Monitor.js +416 -0
- package/core/Candy.js +87 -0
- package/core/Commands.js +239 -0
- package/core/Config.js +1094 -0
- package/core/Lang.js +52 -0
- package/core/Log.js +43 -0
- package/core/Process.js +26 -0
- package/docs/backend/01-overview/01-whats-in-the-candy-box.md +9 -0
- package/docs/backend/01-overview/02-super-handy-helper-functions.md +9 -0
- package/docs/backend/01-overview/03-development-server.md +79 -0
- package/docs/backend/02-structure/01-typical-project-layout.md +39 -0
- package/docs/backend/03-config/00-configuration-overview.md +214 -0
- package/docs/backend/03-config/01-database-connection.md +60 -0
- package/docs/backend/03-config/02-static-route-mapping-optional.md +20 -0
- package/docs/backend/03-config/03-request-timeout.md +11 -0
- package/docs/backend/03-config/04-environment-variables.md +227 -0
- package/docs/backend/03-config/05-early-hints.md +352 -0
- package/docs/backend/04-routing/01-basic-page-routes.md +28 -0
- package/docs/backend/04-routing/02-controller-less-view-routes.md +43 -0
- package/docs/backend/04-routing/03-api-and-data-routes.md +20 -0
- package/docs/backend/04-routing/04-authentication-aware-routes.md +48 -0
- package/docs/backend/04-routing/05-advanced-routing.md +14 -0
- package/docs/backend/04-routing/06-error-pages.md +101 -0
- package/docs/backend/04-routing/07-cron-jobs.md +149 -0
- package/docs/backend/05-controllers/01-how-to-build-a-controller.md +17 -0
- package/docs/backend/05-controllers/02-your-trusty-candy-assistant.md +20 -0
- package/docs/backend/05-controllers/03-controller-classes.md +93 -0
- package/docs/backend/05-forms/01-custom-forms.md +395 -0
- package/docs/backend/05-forms/02-automatic-database-insert.md +297 -0
- package/docs/backend/06-request-and-response/01-the-request-object-what-is-the-user-asking-for.md +96 -0
- package/docs/backend/06-request-and-response/02-sending-a-response-replying-to-the-user.md +40 -0
- package/docs/backend/07-views/01-the-view-directory.md +73 -0
- package/docs/backend/07-views/02-rendering-a-view.md +179 -0
- package/docs/backend/07-views/03-template-syntax.md +181 -0
- package/docs/backend/07-views/03-variables.md +328 -0
- package/docs/backend/07-views/04-request-data.md +231 -0
- package/docs/backend/07-views/05-conditionals.md +290 -0
- package/docs/backend/07-views/06-loops.md +353 -0
- package/docs/backend/07-views/07-translations.md +358 -0
- package/docs/backend/07-views/08-backend-javascript.md +398 -0
- package/docs/backend/07-views/09-comments.md +297 -0
- package/docs/backend/08-database/01-database-connection.md +99 -0
- package/docs/backend/08-database/02-using-mysql.md +322 -0
- package/docs/backend/09-validation/01-the-validator-service.md +424 -0
- package/docs/backend/10-authentication/01-user-logins-with-authjs.md +53 -0
- package/docs/backend/10-authentication/02-foiling-villains-with-csrf-protection.md +55 -0
- package/docs/backend/10-authentication/03-register.md +134 -0
- package/docs/backend/10-authentication/04-candy-register-forms.md +676 -0
- package/docs/backend/10-authentication/05-session-management.md +159 -0
- package/docs/backend/10-authentication/06-candy-login-forms.md +596 -0
- package/docs/backend/11-mail/01-the-mail-service.md +42 -0
- package/docs/backend/12-streaming/01-streaming-overview.md +300 -0
- package/docs/backend/13-utilities/01-candy-var.md +504 -0
- package/docs/frontend/01-overview/01-introduction.md +146 -0
- package/docs/frontend/02-ajax-navigation/01-quick-start.md +608 -0
- package/docs/frontend/02-ajax-navigation/02-configuration.md +370 -0
- package/docs/frontend/02-ajax-navigation/03-advanced-usage.md +519 -0
- package/docs/frontend/03-forms/01-form-handling.md +420 -0
- package/docs/frontend/04-api-requests/01-get-post.md +443 -0
- package/docs/frontend/05-streaming/01-client-streaming.md +163 -0
- package/docs/index.json +452 -0
- package/docs/server/01-installation/01-quick-install.md +19 -0
- package/docs/server/01-installation/02-manual-installation-via-npm.md +9 -0
- package/docs/server/02-get-started/01-core-concepts.md +7 -0
- package/docs/server/02-get-started/02-basic-commands.md +57 -0
- package/docs/server/02-get-started/03-cli-reference.md +276 -0
- package/docs/server/02-get-started/04-cli-quick-reference.md +102 -0
- package/docs/server/03-service/01-start-a-new-service.md +57 -0
- package/docs/server/03-service/02-delete-a-service.md +48 -0
- package/docs/server/04-web/01-create-a-website.md +36 -0
- package/docs/server/04-web/02-list-websites.md +9 -0
- package/docs/server/04-web/03-delete-a-website.md +29 -0
- package/docs/server/05-subdomain/01-create-a-subdomain.md +32 -0
- package/docs/server/05-subdomain/02-list-subdomains.md +33 -0
- package/docs/server/05-subdomain/03-delete-a-subdomain.md +41 -0
- package/docs/server/06-ssl/01-renew-an-ssl-certificate.md +34 -0
- package/docs/server/07-mail/01-create-a-mail-account.md +23 -0
- package/docs/server/07-mail/02-delete-a-mail-account.md +20 -0
- package/docs/server/07-mail/03-list-mail-accounts.md +20 -0
- package/docs/server/07-mail/04-change-account-password.md +23 -0
- package/eslint.config.mjs +120 -0
- package/framework/index.js +4 -0
- package/framework/src/Auth.js +309 -0
- package/framework/src/Candy.js +81 -0
- package/framework/src/Config.js +79 -0
- package/framework/src/Env.js +60 -0
- package/framework/src/Lang.js +57 -0
- package/framework/src/Mail.js +83 -0
- package/framework/src/Mysql.js +575 -0
- package/framework/src/Request.js +301 -0
- package/framework/src/Route/Cron.js +128 -0
- package/framework/src/Route/Internal.js +439 -0
- package/framework/src/Route.js +455 -0
- package/framework/src/Server.js +15 -0
- package/framework/src/Stream.js +163 -0
- package/framework/src/Token.js +37 -0
- package/framework/src/Validator.js +271 -0
- package/framework/src/Var.js +211 -0
- package/framework/src/View/EarlyHints.js +190 -0
- package/framework/src/View/Form.js +600 -0
- package/framework/src/View.js +513 -0
- package/framework/web/candy.js +838 -0
- package/jest.config.js +22 -0
- package/locale/de-DE.json +80 -0
- package/locale/en-US.json +79 -0
- package/locale/es-ES.json +80 -0
- package/locale/fr-FR.json +80 -0
- package/locale/pt-BR.json +80 -0
- package/locale/ru-RU.json +80 -0
- package/locale/tr-TR.json +85 -0
- package/locale/zh-CN.json +80 -0
- package/package.json +86 -0
- package/server/index.js +5 -0
- package/server/src/Api.js +88 -0
- package/server/src/DNS.js +940 -0
- package/server/src/Hub.js +535 -0
- package/server/src/Mail.js +571 -0
- package/server/src/SSL.js +180 -0
- package/server/src/Server.js +27 -0
- package/server/src/Service.js +248 -0
- package/server/src/Subdomain.js +64 -0
- package/server/src/Web/Firewall.js +170 -0
- package/server/src/Web/Proxy.js +134 -0
- package/server/src/Web.js +451 -0
- package/server/src/mail/imap.js +1091 -0
- package/server/src/mail/server.js +32 -0
- package/server/src/mail/smtp.js +786 -0
- package/test/cli/Cli.test.js +36 -0
- package/test/core/Candy.test.js +234 -0
- package/test/core/Commands.test.js +538 -0
- package/test/core/Config.test.js +1435 -0
- package/test/core/Lang.test.js +250 -0
- package/test/core/Process.test.js +156 -0
- package/test/framework/Route.test.js +239 -0
- package/test/framework/View/EarlyHints.test.js +282 -0
- package/test/scripts/check-coverage.js +132 -0
- package/test/server/Api.test.js +647 -0
- package/test/server/Client.test.js +338 -0
- package/test/server/DNS.test.js +2050 -0
- package/test/server/DNS.test.js.bak +2084 -0
- package/test/server/Log.test.js +73 -0
- package/test/server/Mail.account.test_.js +460 -0
- package/test/server/Mail.init.test_.js +411 -0
- package/test/server/Mail.test_.js +1340 -0
- package/test/server/SSL.test_.js +1491 -0
- package/test/server/Server.test.js +765 -0
- package/test/server/Service.test_.js +1127 -0
- package/test/server/Subdomain.test.js +440 -0
- package/test/server/Web/Firewall.test.js +175 -0
- package/test/server/Web.test_.js +1562 -0
- package/test/server/__mocks__/acme-client.js +17 -0
- package/test/server/__mocks__/bcrypt.js +50 -0
- package/test/server/__mocks__/child_process.js +389 -0
- package/test/server/__mocks__/crypto.js +432 -0
- package/test/server/__mocks__/fs.js +450 -0
- package/test/server/__mocks__/globalCandy.js +227 -0
- package/test/server/__mocks__/http-proxy.js +105 -0
- package/test/server/__mocks__/http.js +575 -0
- package/test/server/__mocks__/https.js +272 -0
- package/test/server/__mocks__/index.js +249 -0
- package/test/server/__mocks__/mail/server.js +100 -0
- package/test/server/__mocks__/mail/smtp.js +31 -0
- package/test/server/__mocks__/mailparser.js +81 -0
- package/test/server/__mocks__/net.js +369 -0
- package/test/server/__mocks__/node-forge.js +328 -0
- package/test/server/__mocks__/os.js +320 -0
- package/test/server/__mocks__/path.js +291 -0
- package/test/server/__mocks__/selfsigned.js +8 -0
- package/test/server/__mocks__/server/src/mail/server.js +100 -0
- package/test/server/__mocks__/server/src/mail/smtp.js +31 -0
- package/test/server/__mocks__/smtp-server.js +106 -0
- package/test/server/__mocks__/sqlite3.js +394 -0
- package/test/server/__mocks__/testFactories.js +299 -0
- package/test/server/__mocks__/testHelpers.js +363 -0
- package/test/server/__mocks__/tls.js +229 -0
- package/watchdog/index.js +3 -0
- package/watchdog/src/Watchdog.js +156 -0
- package/web/config.json +5 -0
- package/web/controller/page/about.js +27 -0
- package/web/controller/page/index.js +34 -0
- package/web/package.json +18 -0
- package/web/public/assets/css/style.css +1835 -0
- package/web/public/assets/js/app.js +96 -0
- package/web/route/www.js +19 -0
- package/web/skeleton/main.html +22 -0
- package/web/view/content/about.html +65 -0
- package/web/view/content/home.html +205 -0
- package/web/view/footer/main.html +11 -0
- package/web/view/head/main.html +5 -0
- package/web/view/header/main.html +14 -0
|
@@ -0,0 +1,420 @@
|
|
|
1
|
+
# Form Handling with candy.js
|
|
2
|
+
|
|
3
|
+
Learn how to handle forms with automatic AJAX submission, CSRF protection, and validation in CandyPack.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
### Basic Form
|
|
8
|
+
|
|
9
|
+
```html
|
|
10
|
+
<form id="contact-form" action="/api/contact" method="POST">
|
|
11
|
+
<input name="email" type="email" required>
|
|
12
|
+
<button type="submit">Submit</button>
|
|
13
|
+
</form>
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
```javascript
|
|
17
|
+
Candy.form('#contact-form', function(data) {
|
|
18
|
+
if (data.result.success) {
|
|
19
|
+
alert('Form submitted successfully!')
|
|
20
|
+
}
|
|
21
|
+
})
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
That's it! candy.js handles:
|
|
25
|
+
- ✅ AJAX submission
|
|
26
|
+
- ✅ CSRF token (automatic)
|
|
27
|
+
- ✅ Validation errors (auto-generated)
|
|
28
|
+
- ✅ Success messages (auto-generated)
|
|
29
|
+
- ✅ Loading states
|
|
30
|
+
|
|
31
|
+
**Note:** Error and success message elements are automatically created if not present in your HTML. You can optionally add them for custom styling or positioning.
|
|
32
|
+
|
|
33
|
+
## Form Configuration
|
|
34
|
+
|
|
35
|
+
### Basic Usage
|
|
36
|
+
|
|
37
|
+
```javascript
|
|
38
|
+
Candy.form('#my-form', function(data) {
|
|
39
|
+
console.log('Response:', data)
|
|
40
|
+
})
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### With Options
|
|
44
|
+
|
|
45
|
+
```javascript
|
|
46
|
+
Candy.form({
|
|
47
|
+
form: '#my-form',
|
|
48
|
+
messages: true, // Show error/success messages
|
|
49
|
+
loading: function(percent) {
|
|
50
|
+
console.log('Upload progress:', percent + '%')
|
|
51
|
+
}
|
|
52
|
+
}, function(data) {
|
|
53
|
+
if (data.result.success) {
|
|
54
|
+
console.log('Success!')
|
|
55
|
+
}
|
|
56
|
+
})
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Redirect After Submit
|
|
60
|
+
|
|
61
|
+
```javascript
|
|
62
|
+
Candy.form('#my-form', '/success-page')
|
|
63
|
+
// Redirects to /success-page on success
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Error Handling
|
|
67
|
+
|
|
68
|
+
### Automatic Error Display
|
|
69
|
+
|
|
70
|
+
By default, errors are automatically displayed next to the input fields when validation fails. The system creates error elements automatically.
|
|
71
|
+
|
|
72
|
+
### Custom Error Placement (Optional)
|
|
73
|
+
|
|
74
|
+
If you want to control where errors appear, add error elements manually:
|
|
75
|
+
|
|
76
|
+
```html
|
|
77
|
+
<input name="email" type="email">
|
|
78
|
+
<span candy-form-error="email"></span>
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
**If not present:** The system automatically creates `<span candy-form-error="email">` after the input field.
|
|
82
|
+
|
|
83
|
+
**If present:** The system uses your existing element and updates its content.
|
|
84
|
+
|
|
85
|
+
### Custom Error Display
|
|
86
|
+
|
|
87
|
+
```javascript
|
|
88
|
+
Candy.form('#my-form', function(data) {
|
|
89
|
+
if (!data.result.success) {
|
|
90
|
+
// Custom error handling
|
|
91
|
+
Object.entries(data.errors).forEach(([field, message]) => {
|
|
92
|
+
console.log(`${field}: ${message}`)
|
|
93
|
+
})
|
|
94
|
+
}
|
|
95
|
+
})
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Styling Errors
|
|
99
|
+
|
|
100
|
+
```css
|
|
101
|
+
/* Error message */
|
|
102
|
+
[candy-form-error] {
|
|
103
|
+
color: #ef4444;
|
|
104
|
+
font-size: 0.875rem;
|
|
105
|
+
margin-top: 0.25rem;
|
|
106
|
+
display: none;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/* Invalid input */
|
|
110
|
+
input._candy_error {
|
|
111
|
+
border-color: #ef4444;
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Success Messages
|
|
116
|
+
|
|
117
|
+
### Automatic Success Display
|
|
118
|
+
|
|
119
|
+
Success messages are automatically displayed at the end of the form when submission succeeds.
|
|
120
|
+
|
|
121
|
+
### Custom Success Placement (Optional)
|
|
122
|
+
|
|
123
|
+
If you want to control where success messages appear, add a success element manually:
|
|
124
|
+
|
|
125
|
+
```html
|
|
126
|
+
<form id="my-form" action="/api/submit" method="POST">
|
|
127
|
+
<!-- form fields -->
|
|
128
|
+
<button type="submit">Submit</button>
|
|
129
|
+
<div candy-form-success></div>
|
|
130
|
+
</form>
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
**If not present:** The system automatically creates `<span candy-form-success>` at the end of the form.
|
|
134
|
+
|
|
135
|
+
**If present:** The system uses your existing element and updates its content.
|
|
136
|
+
|
|
137
|
+
### Custom Success Message
|
|
138
|
+
|
|
139
|
+
```javascript
|
|
140
|
+
Candy.form('#my-form', function(data) {
|
|
141
|
+
if (data.result.success) {
|
|
142
|
+
document.querySelector('#custom-message').innerHTML =
|
|
143
|
+
'Thank you! Your form has been submitted.'
|
|
144
|
+
}
|
|
145
|
+
})
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## File Uploads
|
|
149
|
+
|
|
150
|
+
### Basic File Upload
|
|
151
|
+
|
|
152
|
+
```html
|
|
153
|
+
<form id="upload-form" action="/api/upload" method="POST">
|
|
154
|
+
<input name="file" type="file" required>
|
|
155
|
+
<button type="submit">Upload</button>
|
|
156
|
+
</form>
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
```javascript
|
|
160
|
+
Candy.form('#upload-form', function(data) {
|
|
161
|
+
if (data.result.success) {
|
|
162
|
+
console.log('File uploaded:', data.result.filename)
|
|
163
|
+
}
|
|
164
|
+
})
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Upload Progress
|
|
168
|
+
|
|
169
|
+
```javascript
|
|
170
|
+
Candy.form({
|
|
171
|
+
form: '#upload-form',
|
|
172
|
+
loading: function(percent) {
|
|
173
|
+
document.querySelector('#progress').style.width = percent + '%'
|
|
174
|
+
document.querySelector('#progress-text').textContent = percent + '%'
|
|
175
|
+
}
|
|
176
|
+
}, function(data) {
|
|
177
|
+
console.log('Upload complete!')
|
|
178
|
+
})
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### Multiple Files
|
|
182
|
+
|
|
183
|
+
```html
|
|
184
|
+
<input name="files[]" type="file" multiple>
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## Advanced Features
|
|
188
|
+
|
|
189
|
+
### Disable Messages
|
|
190
|
+
|
|
191
|
+
```javascript
|
|
192
|
+
Candy.form({
|
|
193
|
+
form: '#my-form',
|
|
194
|
+
messages: false // Don't show automatic messages
|
|
195
|
+
}, function(data) {
|
|
196
|
+
// Handle messages manually
|
|
197
|
+
})
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Disable Specific Messages
|
|
201
|
+
|
|
202
|
+
```javascript
|
|
203
|
+
Candy.form({
|
|
204
|
+
form: '#my-form',
|
|
205
|
+
messages: ['error'] // Only show errors, not success
|
|
206
|
+
}, function(data) {
|
|
207
|
+
// Custom success handling
|
|
208
|
+
})
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### Form Reset
|
|
212
|
+
|
|
213
|
+
```javascript
|
|
214
|
+
Candy.form('#my-form', function(data) {
|
|
215
|
+
if (data.result.success) {
|
|
216
|
+
// Reset the form
|
|
217
|
+
document.querySelector('#my-form').reset()
|
|
218
|
+
}
|
|
219
|
+
})
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### Conditional Submission
|
|
223
|
+
|
|
224
|
+
```javascript
|
|
225
|
+
document.querySelector('#my-form').addEventListener('submit', function(e) {
|
|
226
|
+
if (!confirm('Are you sure?')) {
|
|
227
|
+
e.preventDefault()
|
|
228
|
+
e.stopPropagation()
|
|
229
|
+
}
|
|
230
|
+
})
|
|
231
|
+
|
|
232
|
+
Candy.form('#my-form', function(data) {
|
|
233
|
+
console.log('Submitted!')
|
|
234
|
+
})
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
## Server-Side Setup
|
|
238
|
+
|
|
239
|
+
### Controller Example
|
|
240
|
+
|
|
241
|
+
```javascript
|
|
242
|
+
// controller/post/contact.js
|
|
243
|
+
module.exports = async function(Candy) {
|
|
244
|
+
const email = await Candy.Request.request('email')
|
|
245
|
+
const message = await Candy.Request.request('message')
|
|
246
|
+
|
|
247
|
+
// Validation
|
|
248
|
+
const errors = {}
|
|
249
|
+
if (!email) errors.email = 'Email is required'
|
|
250
|
+
if (!message) errors.message = 'Message is required'
|
|
251
|
+
|
|
252
|
+
if (Object.keys(errors).length > 0) {
|
|
253
|
+
return {
|
|
254
|
+
result: {success: false},
|
|
255
|
+
errors: errors
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// Process form
|
|
260
|
+
// ... send email, save to database, etc.
|
|
261
|
+
|
|
262
|
+
return {
|
|
263
|
+
result: {
|
|
264
|
+
success: true,
|
|
265
|
+
message: 'Thank you for your message!'
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
### Route Setup
|
|
272
|
+
|
|
273
|
+
```javascript
|
|
274
|
+
// route/www.js
|
|
275
|
+
Candy.Route.post('/api/contact', 'contact')
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
## Validation
|
|
279
|
+
|
|
280
|
+
### Client-Side Validation
|
|
281
|
+
|
|
282
|
+
Use HTML5 validation:
|
|
283
|
+
|
|
284
|
+
```html
|
|
285
|
+
<input name="email" type="email" required>
|
|
286
|
+
<input name="age" type="number" min="18" max="100">
|
|
287
|
+
<input name="website" type="url">
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
### Server-Side Validation
|
|
291
|
+
|
|
292
|
+
Always validate on the server:
|
|
293
|
+
|
|
294
|
+
```javascript
|
|
295
|
+
module.exports = async function(Candy) {
|
|
296
|
+
const email = await Candy.Request.request('email')
|
|
297
|
+
|
|
298
|
+
const errors = {}
|
|
299
|
+
|
|
300
|
+
// Required field
|
|
301
|
+
if (!email) {
|
|
302
|
+
errors.email = 'Email is required'
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// Email format
|
|
306
|
+
else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
|
|
307
|
+
errors.email = 'Invalid email format'
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// Check if exists
|
|
311
|
+
else if (await emailExists(email)) {
|
|
312
|
+
errors.email = 'Email already registered'
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
if (Object.keys(errors).length > 0) {
|
|
316
|
+
return {result: {success: false}, errors}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// Process...
|
|
320
|
+
}
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
## Common Patterns
|
|
324
|
+
|
|
325
|
+
### Contact Form
|
|
326
|
+
|
|
327
|
+
```html
|
|
328
|
+
<form id="contact-form" action="/api/contact" method="POST">
|
|
329
|
+
<input name="name" type="text" required>
|
|
330
|
+
<input name="email" type="email" required>
|
|
331
|
+
<textarea name="message" required></textarea>
|
|
332
|
+
<button type="submit">Send Message</button>
|
|
333
|
+
</form>
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
**Note:** Error and success elements are auto-generated. Add them manually only if you need custom positioning or styling.
|
|
337
|
+
|
|
338
|
+
```javascript
|
|
339
|
+
Candy.form('#contact-form', function(data) {
|
|
340
|
+
if (data.result.success) {
|
|
341
|
+
document.querySelector('#contact-form').reset()
|
|
342
|
+
}
|
|
343
|
+
})
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
### Login Form
|
|
347
|
+
|
|
348
|
+
```html
|
|
349
|
+
<form id="login-form" action="/api/login" method="POST">
|
|
350
|
+
<input name="email" type="email" required>
|
|
351
|
+
<input name="password" type="password" required>
|
|
352
|
+
<button type="submit">Login</button>
|
|
353
|
+
</form>
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
```javascript
|
|
357
|
+
Candy.form('#login-form', function(data) {
|
|
358
|
+
if (data.result.success) {
|
|
359
|
+
// Redirect to dashboard
|
|
360
|
+
window.location.href = '/dashboard'
|
|
361
|
+
}
|
|
362
|
+
})
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
### Registration Form
|
|
366
|
+
|
|
367
|
+
```html
|
|
368
|
+
<form id="register-form" action="/api/register" method="POST">
|
|
369
|
+
<input name="name" type="text" required>
|
|
370
|
+
<input name="email" type="email" required>
|
|
371
|
+
<input name="password" type="password" required minlength="8">
|
|
372
|
+
<input name="password_confirm" type="password" required>
|
|
373
|
+
<button type="submit">Register</button>
|
|
374
|
+
</form>
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
**Tip:** For better UX, you can add custom error elements for specific positioning:
|
|
378
|
+
|
|
379
|
+
```html
|
|
380
|
+
<div class="form-group">
|
|
381
|
+
<input name="email" type="email" required>
|
|
382
|
+
<span candy-form-error="email" class="error-message"></span>
|
|
383
|
+
</div>
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
## Best Practices
|
|
387
|
+
|
|
388
|
+
1. **Always Validate Server-Side**: Never trust client-side validation alone
|
|
389
|
+
2. **Show Clear Errors**: Display errors next to the relevant fields
|
|
390
|
+
3. **Provide Feedback**: Show loading states during submission
|
|
391
|
+
4. **Reset on Success**: Clear the form after successful submission
|
|
392
|
+
5. **Handle Errors Gracefully**: Provide helpful error messages
|
|
393
|
+
6. **Use HTTPS**: Always use HTTPS for forms with sensitive data
|
|
394
|
+
|
|
395
|
+
## Troubleshooting
|
|
396
|
+
|
|
397
|
+
### Form Not Submitting
|
|
398
|
+
|
|
399
|
+
- Check that `Candy.form()` is called after DOM is ready
|
|
400
|
+
- Verify the form selector is correct
|
|
401
|
+
- Check browser console for errors
|
|
402
|
+
|
|
403
|
+
### Errors Not Displaying
|
|
404
|
+
|
|
405
|
+
- Errors are automatically created - no manual elements needed
|
|
406
|
+
- Check that server returns errors in correct format: `{result: {success: false}, errors: {fieldName: 'message'}}`
|
|
407
|
+
- Verify `messages` option is not set to `false`
|
|
408
|
+
- If using custom error elements, ensure `candy-form-error` attributes match field names exactly
|
|
409
|
+
|
|
410
|
+
### CSRF Token Errors
|
|
411
|
+
|
|
412
|
+
- CSRF tokens are handled automatically
|
|
413
|
+
- If you get token errors, check server configuration
|
|
414
|
+
- Ensure cookies are enabled
|
|
415
|
+
|
|
416
|
+
## Next Steps
|
|
417
|
+
|
|
418
|
+
- Learn about [Validation](02-validation.md)
|
|
419
|
+
- Explore [File Uploads](03-file-uploads.md)
|
|
420
|
+
- Check [API Requests](../04-api-requests/01-get-post.md)
|