@awes-io/ui 2.142.3 → 2.144.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/assets/css/components/_index.css +7 -1
- package/assets/css/components/action-card.css +1 -0
- package/assets/css/components/action-icon.css +2 -2
- package/assets/css/components/alert.css +28 -22
- package/assets/css/components/animation.css +52 -32
- package/assets/css/components/badge.css +1 -0
- package/assets/css/components/banner-text.css +15 -4
- package/assets/css/components/card.css +0 -1
- package/assets/css/components/content-placeholder.css +104 -0
- package/assets/css/components/dropdown.css +20 -7
- package/assets/css/components/empty-container.css +69 -1
- package/assets/css/components/filter-chosen.css +6 -0
- package/assets/css/components/filter-date-range.css +17 -1
- package/assets/css/components/filter-month.css +23 -17
- package/assets/css/components/filter-select.css +11 -0
- package/assets/css/components/icon-menu-item.css +12 -7
- package/assets/css/components/layout.css +1 -32
- package/assets/css/components/mobile-menu-nav.css +8 -4
- package/assets/css/components/modal.css +1 -1
- package/assets/css/components/number.css +12 -0
- package/assets/css/components/page-aside.css +54 -0
- package/assets/css/components/text-field.css +4 -0
- package/assets/js/css.js +1 -1
- package/assets/js/icons/mono.js +59 -91
- package/assets/js/icons/multicolor.js +1 -31
- package/components/1_atoms/AwActionIcon.vue +11 -2
- package/components/1_atoms/AwContentPlaceholder.vue +60 -0
- package/components/1_atoms/AwFlow.vue +37 -49
- package/components/1_atoms/AwGrid.vue +11 -3
- package/components/1_atoms/AwIcon/AwIcon.vue +5 -3
- package/components/1_atoms/AwIcon/AwIconSystemMono.vue +3 -2
- package/components/1_atoms/AwInput.vue +2 -2
- package/components/1_atoms/AwLabel.vue +1 -1
- package/components/1_atoms/AwList.vue +3 -1
- package/components/1_atoms/AwRadio.vue +1 -1
- package/components/1_atoms/AwSlider.vue +15 -1
- package/components/1_atoms/AwTag.vue +6 -1
- package/components/2_molecules/AwAlert.vue +63 -42
- package/components/2_molecules/AwBadge.vue +1 -1
- package/components/2_molecules/AwBannerText.vue +8 -2
- package/components/2_molecules/AwButton.vue +1 -1
- package/components/2_molecules/AwDescriptionInput.vue +19 -1
- package/components/2_molecules/AwEmptyContainer.vue +74 -72
- package/components/2_molecules/AwNumber.vue +180 -0
- package/components/2_molecules/AwSelect.vue +11 -4
- package/components/3_organisms/AwBottomBar.vue +22 -4
- package/components/3_organisms/AwFilterChosen.vue +73 -0
- package/components/3_organisms/AwFilterDateRange.vue +177 -0
- package/components/3_organisms/AwFilterMonth.vue +37 -40
- package/components/3_organisms/AwFilterSelect.vue +368 -0
- package/components/3_organisms/AwMultiBlockBuilder.vue +1 -1
- package/components/3_organisms/AwSubnav.vue +11 -1
- package/components/3_organisms/AwTable/AwTableBuilder.vue +20 -60
- package/components/3_organisms/AwTable/_AwTableCellDropdown.vue +6 -1
- package/components/3_organisms/AwTable/_AwTableRow.vue +2 -1
- package/components/4_pages/AwPage.vue +1 -0
- package/components/4_pages/AwPageAside.vue +108 -0
- package/components/5_layouts/AwLayoutCenter.vue +3 -8
- package/components/5_layouts/_AwMenuItemIcon.vue +9 -2
- package/components/5_layouts/_AwMobileMenuItem.vue +5 -3
- package/components/5_layouts/_AwUserMenu.vue +1 -1
- package/components/_config.js +26 -1
- package/docs/_template.md +80 -0
- package/docs/components/atoms/aw-accordion-fold.md +129 -0
- package/docs/components/atoms/aw-action-card-body.md +99 -0
- package/docs/components/atoms/aw-action-card.md +130 -0
- package/docs/components/atoms/aw-action-icon.md +126 -0
- package/docs/components/atoms/aw-avatar.md +106 -0
- package/docs/components/atoms/aw-card.md +137 -0
- package/docs/components/atoms/aw-checkbox.md +288 -0
- package/docs/components/atoms/aw-content-placeholder.md +147 -0
- package/docs/components/atoms/aw-description.md +83 -0
- package/docs/components/atoms/aw-dock.md +90 -0
- package/docs/components/atoms/aw-dropdown-button.md +94 -0
- package/docs/components/atoms/aw-dropdown.md +178 -0
- package/docs/components/atoms/aw-file.md +73 -0
- package/docs/components/atoms/aw-flow.md +140 -0
- package/docs/components/atoms/aw-grid.md +109 -0
- package/docs/components/atoms/aw-headline.md +71 -0
- package/docs/components/atoms/aw-icon-system-color.md +122 -0
- package/docs/components/atoms/aw-icon-system-mono.md +206 -0
- package/docs/components/atoms/aw-icon.md +235 -0
- package/docs/components/atoms/aw-info.md +123 -0
- package/docs/components/atoms/aw-input.md +212 -0
- package/docs/components/atoms/aw-label.md +136 -0
- package/docs/components/atoms/aw-link.md +151 -0
- package/docs/components/atoms/aw-list.md +152 -0
- package/docs/components/atoms/aw-progress.md +119 -0
- package/docs/components/atoms/aw-radio.md +182 -0
- package/docs/components/atoms/aw-refresh-wrapper.md +81 -0
- package/docs/components/atoms/aw-select-native.md +234 -0
- package/docs/components/atoms/aw-slider.md +189 -0
- package/docs/components/atoms/aw-sub-headline.md +73 -0
- package/docs/components/atoms/aw-switcher.md +192 -0
- package/docs/components/atoms/aw-tag.md +144 -0
- package/docs/components/atoms/aw-title.md +70 -0
- package/docs/components/atoms/aw-toggler.md +90 -0
- package/docs/components/layouts/aw-layout-center.md +168 -0
- package/docs/components/layouts/aw-layout-error.md +153 -0
- package/docs/components/layouts/aw-layout-provider.md +238 -0
- package/docs/components/layouts/aw-layout.md +88 -0
- package/docs/components/molecules/aw-action-button.md +138 -0
- package/docs/components/molecules/aw-alert.md +191 -0
- package/docs/components/molecules/aw-badge.md +129 -0
- package/docs/components/molecules/aw-banner-text.md +156 -0
- package/docs/components/molecules/aw-button-nav.md +111 -0
- package/docs/components/molecules/aw-button.md +193 -0
- package/docs/components/molecules/aw-description-input.md +124 -0
- package/docs/components/molecules/aw-empty-container.md +235 -0
- package/docs/components/molecules/aw-island.md +506 -0
- package/docs/components/molecules/aw-number.md +138 -0
- package/docs/components/molecules/aw-select-object.md +401 -0
- package/docs/components/molecules/aw-select.md +215 -0
- package/docs/components/molecules/aw-tab-nav.md +108 -0
- package/docs/components/molecules/aw-tel.md +129 -0
- package/docs/components/molecules/aw-textarea.md +83 -0
- package/docs/components/molecules/aw-userpic.md +115 -0
- package/docs/components/organisms/aw-address-block.md +64 -0
- package/docs/components/organisms/aw-address.md +132 -0
- package/docs/components/organisms/aw-birthday-picker.md +73 -0
- package/docs/components/organisms/aw-bottom-bar.md +66 -0
- package/docs/components/organisms/aw-calendar-days.md +115 -0
- package/docs/components/organisms/aw-calendar-nav.md +98 -0
- package/docs/components/organisms/aw-calendar-view.md +98 -0
- package/docs/components/organisms/aw-calendar.md +166 -0
- package/docs/components/organisms/aw-chart.md +154 -0
- package/docs/components/organisms/aw-chip-select.md +164 -0
- package/docs/components/organisms/aw-chip.md +126 -0
- package/docs/components/organisms/aw-code-snippet.md +94 -0
- package/docs/components/organisms/aw-code.md +132 -0
- package/docs/components/organisms/aw-context-menu.md +117 -0
- package/docs/components/organisms/aw-cropper.md +151 -0
- package/docs/components/organisms/aw-date.md +161 -0
- package/docs/components/organisms/aw-display-date.md +33 -0
- package/docs/components/organisms/aw-download-link.md +46 -0
- package/docs/components/organisms/aw-fetch-data.md +161 -0
- package/docs/components/organisms/aw-filter-chosen.md +226 -0
- package/docs/components/organisms/aw-filter-date-range.md +205 -0
- package/docs/components/organisms/aw-filter-month.md +43 -0
- package/docs/components/organisms/aw-filter-select.md +239 -0
- package/docs/components/organisms/aw-form.md +174 -0
- package/docs/components/organisms/aw-gmap-marker.md +86 -0
- package/docs/components/organisms/aw-gmap.md +90 -0
- package/docs/components/organisms/aw-image-upload.md +56 -0
- package/docs/components/organisms/aw-island-avatar.md +87 -0
- package/docs/components/organisms/aw-markdown-editor.md +104 -0
- package/docs/components/organisms/aw-modal-buttons.md +57 -0
- package/docs/components/organisms/aw-modal.md +246 -0
- package/docs/components/organisms/aw-model-edit.md +74 -0
- package/docs/components/organisms/aw-money.md +53 -0
- package/docs/components/organisms/aw-multi-block-builder.md +165 -0
- package/docs/components/organisms/aw-pagination.md +121 -0
- package/docs/components/organisms/aw-password.md +103 -0
- package/docs/components/organisms/aw-preview-card.md +45 -0
- package/docs/components/organisms/aw-search.md +116 -0
- package/docs/components/organisms/aw-subnav.md +122 -0
- package/docs/components/organisms/aw-table-builder.md +165 -0
- package/docs/components/organisms/aw-table-col.md +123 -0
- package/docs/components/organisms/aw-table-head.md +92 -0
- package/docs/components/organisms/aw-table-row.md +91 -0
- package/docs/components/organisms/aw-table.md +172 -0
- package/docs/components/organisms/aw-tags.md +54 -0
- package/docs/components/organisms/aw-toggle-show-aside.md +43 -0
- package/docs/components/organisms/aw-uploader-files.md +125 -0
- package/docs/components/organisms/aw-uploader.md +163 -0
- package/docs/components/organisms/aw-user-menu.md +87 -0
- package/docs/components/pages/aw-page-aside.md +296 -0
- package/docs/components/pages/aw-page-menu-buttons.md +172 -0
- package/docs/components/pages/aw-page-modal.md +198 -0
- package/docs/components/pages/aw-page-single.md +300 -0
- package/docs/components/pages/aw-page.md +194 -0
- package/docs/configuration.md +493 -0
- package/docs/cookbook/advanced-patterns.md +1388 -0
- package/docs/cookbook/common-patterns.md +965 -0
- package/docs/cookbook/index.md +786 -0
- package/docs/getting-started.md +596 -0
- package/docs/guides/best-practices.md +1106 -0
- package/docs/guides/data-fetching.md +852 -0
- package/docs/guides/error-handling.md +1172 -0
- package/docs/guides/forms-guide.md +1329 -0
- package/docs/guides/mobile-subnavigation.md +359 -0
- package/docs/guides/page-patterns/aside-pages.md +1418 -0
- package/docs/guides/page-patterns/dashboard-pages.md +990 -0
- package/docs/guides/page-patterns/detail-pages.md +1556 -0
- package/docs/guides/page-patterns/list-pages.md +1242 -0
- package/docs/index.md +263 -1
- package/docs/integrations.md +870 -0
- package/docs/reference/colors.md +232 -0
- package/docs/reference/icons.md +163 -0
- package/docs/reference/menu.md +462 -0
- package/docs/reference/plugins.md +970 -0
- package/docs/reference/troubleshooting.md +964 -0
- package/nuxt/awes.config.js +9 -8
- package/nuxt/index.js +2 -2
- package/nuxt/pages/more.vue +1 -1
- package/package.json +5 -3
- package/readme.md +171 -1
- package/store/awesIo.js +11 -0
- package/CHANGELOG.md +0 -4520
- package/docs/aw-accordion-fold.md +0 -46
- package/docs/aw-address.md +0 -44
- package/docs/aw-avatar.md +0 -51
- package/docs/aw-badge.md +0 -32
- package/docs/aw-button-nav.md +0 -44
- package/docs/aw-button.md +0 -50
- package/docs/aw-calendar-days.md +0 -46
- package/docs/aw-calendar-nav.md +0 -25
- package/docs/aw-calendar-view.md +0 -12
- package/docs/aw-calendar.md +0 -59
- package/docs/aw-card.md +0 -48
- package/docs/aw-chart.md +0 -51
- package/docs/aw-checkbox.md +0 -56
- package/docs/aw-chip-select.md +0 -46
- package/docs/aw-chip.md +0 -53
- package/docs/aw-code-snippet.md +0 -18
- package/docs/aw-code.md +0 -56
- package/docs/aw-content-wrapper.md +0 -40
- package/docs/aw-context-menu.md +0 -31
- package/docs/aw-cropper.md +0 -60
- package/docs/aw-dashboard-card.md +0 -37
- package/docs/aw-dashboard-donut.md +0 -30
- package/docs/aw-dashboard-line.md +0 -20
- package/docs/aw-dashboard-progress.md +0 -33
- package/docs/aw-dashboard-section.md +0 -32
- package/docs/aw-dashboard-speed.md +0 -30
- package/docs/aw-date.md +0 -52
- package/docs/aw-dropdown-button.md +0 -31
- package/docs/aw-dropdown.md +0 -69
- package/docs/aw-fetch-data.md +0 -45
- package/docs/aw-form.md +0 -52
- package/docs/aw-grid.md +0 -48
- package/docs/aw-icon.md +0 -50
- package/docs/aw-info.md +0 -53
- package/docs/aw-input.md +0 -55
- package/docs/aw-layout-default.md +0 -30
- package/docs/aw-layout-frame-center.md +0 -29
- package/docs/aw-layout-simple.md +0 -49
- package/docs/aw-link.md +0 -54
- package/docs/aw-markdown-editor.md +0 -51
- package/docs/aw-modal.md +0 -63
- package/docs/aw-multi-block-builder.md +0 -66
- package/docs/aw-page.md +0 -36
- package/docs/aw-pagination.md +0 -54
- package/docs/aw-password.md +0 -48
- package/docs/aw-radio.md +0 -54
- package/docs/aw-search.md +0 -49
- package/docs/aw-select.md +0 -93
- package/docs/aw-slider.md +0 -40
- package/docs/aw-svg-image.md +0 -19
- package/docs/aw-switcher.md +0 -51
- package/docs/aw-tab-nav.md +0 -55
- package/docs/aw-table-builder.md +0 -58
- package/docs/aw-table-col.md +0 -33
- package/docs/aw-table-head.md +0 -28
- package/docs/aw-table-row.md +0 -33
- package/docs/aw-table.md +0 -59
- package/docs/aw-tel.md +0 -47
- package/docs/aw-textarea.md +0 -47
- package/docs/aw-toggler.md +0 -41
- package/docs/aw-uploader-files.md +0 -20
- package/docs/aw-uploader.md +0 -60
- package/docs/aw-user-menu.md +0 -34
- package/docs/aw-userpic.md +0 -34
- /package/components/{3_organisms → 2_molecules}/AwTel.vue +0 -0
|
@@ -0,0 +1,1329 @@
|
|
|
1
|
+
---
|
|
2
|
+
metaTitle: Forms Integration Guide | AwesCode UI
|
|
3
|
+
meta:
|
|
4
|
+
- name: description
|
|
5
|
+
content: Complete guide to building forms with AwesCode UI components - validation, error handling, and common patterns.
|
|
6
|
+
title: Forms Integration Guide
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Forms Integration Guide
|
|
10
|
+
|
|
11
|
+
Complete guide to building forms with AwesCode UI components.
|
|
12
|
+
|
|
13
|
+
## Table of Contents
|
|
14
|
+
|
|
15
|
+
- [Model-Based Forms (Recommended)](#model-based-forms-recommended)
|
|
16
|
+
- [Basic Form Structure](#basic-form-structure)
|
|
17
|
+
- [Form Inputs](#form-inputs)
|
|
18
|
+
- [Validation & Errors](#validation--errors)
|
|
19
|
+
- [File Uploads](#file-uploads)
|
|
20
|
+
- [Complex Forms](#complex-forms)
|
|
21
|
+
- [Modal Forms](#modal-forms)
|
|
22
|
+
- [Multi-Step Forms](#multi-step-forms)
|
|
23
|
+
- [Best Practices](#best-practices)
|
|
24
|
+
|
|
25
|
+
## Model-Based Forms (Recommended)
|
|
26
|
+
|
|
27
|
+
For CRUD operations and data editing, use `AwModelEdit` with Vue-MC models instead of raw `AwForm`. This provides automatic change detection, validation, error handling, and state management.
|
|
28
|
+
|
|
29
|
+
### Why Use AwModelEdit?
|
|
30
|
+
|
|
31
|
+
**AwModelEdit** wraps your form fields and provides:
|
|
32
|
+
- Automatic change detection with unsaved changes warning
|
|
33
|
+
- Save/Cancel buttons that appear when data changes
|
|
34
|
+
- Keyboard shortcuts (Ctrl+Enter to save, Escape to cancel)
|
|
35
|
+
- Automatic error scrolling to first invalid field
|
|
36
|
+
- Sticky action panel that follows scroll
|
|
37
|
+
- Integration with Vue-MC model lifecycle
|
|
38
|
+
|
|
39
|
+
**Use AwModelEdit when:**
|
|
40
|
+
- Editing database records (users, posts, settings, etc.)
|
|
41
|
+
- Need change detection and confirmation dialogs
|
|
42
|
+
- Working with complex nested data structures
|
|
43
|
+
- Need automatic state management
|
|
44
|
+
- Server-side validation with field-level errors
|
|
45
|
+
|
|
46
|
+
**Use AwForm when:**
|
|
47
|
+
- One-off operations (login, contact forms, search)
|
|
48
|
+
- Simple data submission without persistent state
|
|
49
|
+
- File uploads to specific endpoints
|
|
50
|
+
- Custom form handling logic needed
|
|
51
|
+
|
|
52
|
+
### Simple Edit Form
|
|
53
|
+
|
|
54
|
+
```markup
|
|
55
|
+
<template>
|
|
56
|
+
<AwPage :title="title">
|
|
57
|
+
<AwContentPlaceholder v-if="user.fetching" type="form" :lines="4" />
|
|
58
|
+
|
|
59
|
+
<AwModelEdit v-else :model="user">
|
|
60
|
+
<AwGrid>
|
|
61
|
+
<AwCard title="Profile Information">
|
|
62
|
+
<AwInput
|
|
63
|
+
v-model="user.email"
|
|
64
|
+
:error="user.errors.email"
|
|
65
|
+
label="Email"
|
|
66
|
+
/>
|
|
67
|
+
|
|
68
|
+
<AwInput
|
|
69
|
+
v-model="user.first_name"
|
|
70
|
+
:error="user.errors.first_name"
|
|
71
|
+
label="First Name"
|
|
72
|
+
/>
|
|
73
|
+
|
|
74
|
+
<AwInput
|
|
75
|
+
v-model="user.last_name"
|
|
76
|
+
:error="user.errors.last_name"
|
|
77
|
+
label="Last Name"
|
|
78
|
+
/>
|
|
79
|
+
</AwCard>
|
|
80
|
+
</AwGrid>
|
|
81
|
+
</AwModelEdit>
|
|
82
|
+
</AwPage>
|
|
83
|
+
</template>
|
|
84
|
+
|
|
85
|
+
<script>
|
|
86
|
+
import User from '@/models/User'
|
|
87
|
+
|
|
88
|
+
export default {
|
|
89
|
+
data() {
|
|
90
|
+
return {
|
|
91
|
+
user: new User({ id: this.$route.params.id })
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
|
|
95
|
+
computed: {
|
|
96
|
+
title() {
|
|
97
|
+
return this.user.isNew() ? 'Create User' : `Edit ${this.user.first_name}`
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
|
|
101
|
+
fetch() {
|
|
102
|
+
// Load existing user data
|
|
103
|
+
return this.user.isNew()
|
|
104
|
+
? Promise.resolve()
|
|
105
|
+
: this.user.fetch()
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
</script>
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Defining Vue-MC Models
|
|
112
|
+
|
|
113
|
+
```javascript
|
|
114
|
+
// models/User.js
|
|
115
|
+
import { BaseModel } from '@awes-io/vue-mc'
|
|
116
|
+
|
|
117
|
+
export default class User extends BaseModel {
|
|
118
|
+
defaults() {
|
|
119
|
+
return {
|
|
120
|
+
id: null,
|
|
121
|
+
email: '',
|
|
122
|
+
first_name: '',
|
|
123
|
+
last_name: '',
|
|
124
|
+
status: 'active',
|
|
125
|
+
role: {
|
|
126
|
+
id: null,
|
|
127
|
+
name: ''
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
routes() {
|
|
133
|
+
return {
|
|
134
|
+
fetch: '/api/users/{id}',
|
|
135
|
+
save: '/api/users', // POST for new
|
|
136
|
+
update: '/api/users/{id}', // PUT/PATCH for existing
|
|
137
|
+
delete: '/api/users/{id}' // DELETE
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
validation() {
|
|
142
|
+
return {
|
|
143
|
+
email: 'required|email',
|
|
144
|
+
first_name: 'required|min:2',
|
|
145
|
+
last_name: 'required|min:2'
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Computed properties
|
|
150
|
+
get full_name() {
|
|
151
|
+
return `${this.first_name} ${this.last_name}`.trim()
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Nested Data Structures
|
|
157
|
+
|
|
158
|
+
```markup
|
|
159
|
+
<template>
|
|
160
|
+
<AwModelEdit :model="company">
|
|
161
|
+
<AwCard title="Company Details">
|
|
162
|
+
<AwInput
|
|
163
|
+
v-model="company.name"
|
|
164
|
+
:error="company.errors.name"
|
|
165
|
+
label="Company Name"
|
|
166
|
+
/>
|
|
167
|
+
|
|
168
|
+
<AwInput
|
|
169
|
+
v-model="company.tax_id"
|
|
170
|
+
:error="company.errors.tax_id"
|
|
171
|
+
label="Tax ID"
|
|
172
|
+
/>
|
|
173
|
+
</AwCard>
|
|
174
|
+
|
|
175
|
+
<AwCard title="Primary Contact">
|
|
176
|
+
<AwInput
|
|
177
|
+
v-model="company.contact.name"
|
|
178
|
+
:error="company.errors['contact.name']"
|
|
179
|
+
label="Contact Name"
|
|
180
|
+
/>
|
|
181
|
+
|
|
182
|
+
<AwInput
|
|
183
|
+
v-model="company.contact.email"
|
|
184
|
+
:error="company.errors['contact.email']"
|
|
185
|
+
label="Contact Email"
|
|
186
|
+
type="email"
|
|
187
|
+
/>
|
|
188
|
+
|
|
189
|
+
<AwTel
|
|
190
|
+
v-model="company.contact.phone"
|
|
191
|
+
:error="company.errors['contact.phone']"
|
|
192
|
+
label="Phone"
|
|
193
|
+
/>
|
|
194
|
+
</AwCard>
|
|
195
|
+
|
|
196
|
+
<AwCard title="Address">
|
|
197
|
+
<AwAddress
|
|
198
|
+
v-model="company.address"
|
|
199
|
+
:error="company.errors.address"
|
|
200
|
+
:with-google-maps="true"
|
|
201
|
+
/>
|
|
202
|
+
</AwCard>
|
|
203
|
+
</AwModelEdit>
|
|
204
|
+
</template>
|
|
205
|
+
|
|
206
|
+
<script>
|
|
207
|
+
import Company from '@/models/Company'
|
|
208
|
+
|
|
209
|
+
export default {
|
|
210
|
+
data() {
|
|
211
|
+
return {
|
|
212
|
+
company: new Company({ id: this.$route.params.id })
|
|
213
|
+
}
|
|
214
|
+
},
|
|
215
|
+
|
|
216
|
+
fetch() {
|
|
217
|
+
return this.company.isNew() ? Promise.resolve() : this.company.fetch()
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
</script>
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### Custom Save Actions
|
|
224
|
+
|
|
225
|
+
```markup
|
|
226
|
+
<template>
|
|
227
|
+
<AwModelEdit
|
|
228
|
+
:model="post"
|
|
229
|
+
@saved="onSaved"
|
|
230
|
+
>
|
|
231
|
+
<AwInput v-model="post.title" :error="post.errors.title" label="Title" />
|
|
232
|
+
<AwTextarea v-model="post.content" :error="post.errors.content" label="Content" />
|
|
233
|
+
|
|
234
|
+
<template #after-buttons>
|
|
235
|
+
<!-- Additional action buttons -->
|
|
236
|
+
<AwButton @click="publishPost" theme="outline" color="success">
|
|
237
|
+
Publish
|
|
238
|
+
</AwButton>
|
|
239
|
+
|
|
240
|
+
<AwButton @click="deletePost" theme="outline" color="error">
|
|
241
|
+
Delete
|
|
242
|
+
</AwButton>
|
|
243
|
+
</template>
|
|
244
|
+
</AwModelEdit>
|
|
245
|
+
</template>
|
|
246
|
+
|
|
247
|
+
<script>
|
|
248
|
+
export default {
|
|
249
|
+
data() {
|
|
250
|
+
return {
|
|
251
|
+
post: new Post({ id: this.$route.params.id })
|
|
252
|
+
}
|
|
253
|
+
},
|
|
254
|
+
|
|
255
|
+
methods: {
|
|
256
|
+
onSaved(post) {
|
|
257
|
+
this.$notify({ title: 'Post saved successfully!' })
|
|
258
|
+
// Custom redirect
|
|
259
|
+
if (post.isNew()) {
|
|
260
|
+
this.$router.push(`/posts/${post.id}/edit`)
|
|
261
|
+
}
|
|
262
|
+
},
|
|
263
|
+
|
|
264
|
+
async publishPost() {
|
|
265
|
+
try {
|
|
266
|
+
await this.post.save({ status: 'published' })
|
|
267
|
+
this.$notify({ title: 'Post published!' })
|
|
268
|
+
} catch (error) {
|
|
269
|
+
this.$notify({
|
|
270
|
+
type: 'error',
|
|
271
|
+
title: 'Failed to publish post'
|
|
272
|
+
})
|
|
273
|
+
}
|
|
274
|
+
},
|
|
275
|
+
|
|
276
|
+
async deletePost() {
|
|
277
|
+
if (confirm('Are you sure you want to delete this post?')) {
|
|
278
|
+
await this.post.delete()
|
|
279
|
+
this.$router.push('/posts')
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
</script>
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
### Conditional Fields
|
|
288
|
+
|
|
289
|
+
```markup
|
|
290
|
+
<template>
|
|
291
|
+
<AwModelEdit :model="user">
|
|
292
|
+
<AwCard title="Account">
|
|
293
|
+
<AwInput v-model="user.email" :error="user.errors.email" label="Email" />
|
|
294
|
+
|
|
295
|
+
<!-- Show password field only for new users -->
|
|
296
|
+
<template v-if="user.isNew()">
|
|
297
|
+
<AwPassword
|
|
298
|
+
v-model="user.password"
|
|
299
|
+
:error="user.errors.password"
|
|
300
|
+
label="Password"
|
|
301
|
+
required
|
|
302
|
+
/>
|
|
303
|
+
|
|
304
|
+
<AwPassword
|
|
305
|
+
v-model="user.password_confirmation"
|
|
306
|
+
:error="user.errors.password_confirmation"
|
|
307
|
+
label="Confirm Password"
|
|
308
|
+
required
|
|
309
|
+
/>
|
|
310
|
+
</template>
|
|
311
|
+
|
|
312
|
+
<!-- Show reset button for existing users -->
|
|
313
|
+
<template v-else>
|
|
314
|
+
<AwButton @click="sendPasswordReset" theme="outline">
|
|
315
|
+
Send Password Reset Email
|
|
316
|
+
</AwButton>
|
|
317
|
+
</template>
|
|
318
|
+
</AwCard>
|
|
319
|
+
|
|
320
|
+
<AwCard title="Role & Status">
|
|
321
|
+
<!-- Show different options based on user permissions -->
|
|
322
|
+
<AwSelect
|
|
323
|
+
v-if="$can('manage-roles')"
|
|
324
|
+
v-model="user.role_id"
|
|
325
|
+
:error="user.errors.role_id"
|
|
326
|
+
:options="roles"
|
|
327
|
+
label="Role"
|
|
328
|
+
/>
|
|
329
|
+
|
|
330
|
+
<AwSwitcher
|
|
331
|
+
v-model="user.is_active"
|
|
332
|
+
:error="user.errors.is_active"
|
|
333
|
+
label="Active Status"
|
|
334
|
+
/>
|
|
335
|
+
</AwCard>
|
|
336
|
+
</AwModelEdit>
|
|
337
|
+
</template>
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
### Relationship Management
|
|
341
|
+
|
|
342
|
+
```markup
|
|
343
|
+
<template>
|
|
344
|
+
<AwModelEdit :model="role">
|
|
345
|
+
<AwCard title="Role Information">
|
|
346
|
+
<AwInput
|
|
347
|
+
v-model="role.name"
|
|
348
|
+
:error="role.errors.name"
|
|
349
|
+
label="Role Name"
|
|
350
|
+
/>
|
|
351
|
+
|
|
352
|
+
<AwTextarea
|
|
353
|
+
v-model="role.description"
|
|
354
|
+
:error="role.errors.description"
|
|
355
|
+
label="Description"
|
|
356
|
+
/>
|
|
357
|
+
</AwCard>
|
|
358
|
+
|
|
359
|
+
<AwCard title="Permissions">
|
|
360
|
+
<!-- Many-to-many relationship with checkboxes -->
|
|
361
|
+
<AwCheckbox
|
|
362
|
+
v-for="permission in permissions.models"
|
|
363
|
+
:key="permission.id"
|
|
364
|
+
v-model="role.permission_ids"
|
|
365
|
+
:value="permission.id"
|
|
366
|
+
:label="permission.name"
|
|
367
|
+
>
|
|
368
|
+
{{ permission.name }}
|
|
369
|
+
<small class="text-muted">{{ permission.description }}</small>
|
|
370
|
+
</AwCheckbox>
|
|
371
|
+
</AwCard>
|
|
372
|
+
</AwModelEdit>
|
|
373
|
+
</template>
|
|
374
|
+
|
|
375
|
+
<script>
|
|
376
|
+
import Role from '@/models/Role'
|
|
377
|
+
import Permissions from '@/collections/Permissions'
|
|
378
|
+
|
|
379
|
+
export default {
|
|
380
|
+
data() {
|
|
381
|
+
return {
|
|
382
|
+
role: new Role({ id: this.$route.params.id }),
|
|
383
|
+
permissions: new Permissions()
|
|
384
|
+
}
|
|
385
|
+
},
|
|
386
|
+
|
|
387
|
+
async fetch() {
|
|
388
|
+
// Load permissions first, then role
|
|
389
|
+
await this.permissions.fetch()
|
|
390
|
+
|
|
391
|
+
if (!this.role.isNew()) {
|
|
392
|
+
await this.role.fetch()
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
</script>
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
### Advanced Configuration
|
|
400
|
+
|
|
401
|
+
```markup
|
|
402
|
+
<template>
|
|
403
|
+
<AwModelEdit
|
|
404
|
+
:model="settings"
|
|
405
|
+
:saveText="$t('Save Changes')"
|
|
406
|
+
:cancelText="$t('Reset')"
|
|
407
|
+
:isNotify="true"
|
|
408
|
+
:notifyText="$t('Settings updated successfully')"
|
|
409
|
+
:isRedirect="false"
|
|
410
|
+
:saveMethod="customSave"
|
|
411
|
+
:alwaysVisible="true"
|
|
412
|
+
saveErrorPath="response.data.message"
|
|
413
|
+
@saved="onSettingsSaved"
|
|
414
|
+
@error="onError"
|
|
415
|
+
>
|
|
416
|
+
<!-- Form fields -->
|
|
417
|
+
</AwModelEdit>
|
|
418
|
+
</template>
|
|
419
|
+
|
|
420
|
+
<script>
|
|
421
|
+
export default {
|
|
422
|
+
data() {
|
|
423
|
+
return {
|
|
424
|
+
settings: new Settings({ id: 1 })
|
|
425
|
+
}
|
|
426
|
+
},
|
|
427
|
+
|
|
428
|
+
methods: {
|
|
429
|
+
async customSave() {
|
|
430
|
+
// Custom save logic
|
|
431
|
+
return this.settings.save({
|
|
432
|
+
validate: true,
|
|
433
|
+
additional_data: this.getAdditionalData()
|
|
434
|
+
})
|
|
435
|
+
},
|
|
436
|
+
|
|
437
|
+
onSettingsSaved(settings) {
|
|
438
|
+
// Reload app config
|
|
439
|
+
this.$store.dispatch('loadSettings')
|
|
440
|
+
},
|
|
441
|
+
|
|
442
|
+
onError(error) {
|
|
443
|
+
console.error('Save failed:', error)
|
|
444
|
+
this.$notify({
|
|
445
|
+
type: 'error',
|
|
446
|
+
title: 'Error',
|
|
447
|
+
message: error.response?.data?.message || 'Failed to save settings'
|
|
448
|
+
})
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
</script>
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
### Modal Forms with Models
|
|
456
|
+
|
|
457
|
+
```markup
|
|
458
|
+
<template>
|
|
459
|
+
<div>
|
|
460
|
+
<AwButton @click="openModal">Create User</AwButton>
|
|
461
|
+
|
|
462
|
+
<AwModal :show="showModal" @close="closeModal">
|
|
463
|
+
<template #title>
|
|
464
|
+
{{ user.isNew() ? 'Create User' : 'Edit User' }}
|
|
465
|
+
</template>
|
|
466
|
+
|
|
467
|
+
<AwModelEdit
|
|
468
|
+
:model="user"
|
|
469
|
+
:isRedirect="false"
|
|
470
|
+
@saved="onUserSaved"
|
|
471
|
+
>
|
|
472
|
+
<AwInput v-model="user.email" :error="user.errors.email" label="Email" />
|
|
473
|
+
<AwInput v-model="user.first_name" :error="user.errors.first_name" label="First Name" />
|
|
474
|
+
<AwInput v-model="user.last_name" :error="user.errors.last_name" label="Last Name" />
|
|
475
|
+
</AwModelEdit>
|
|
476
|
+
</AwModal>
|
|
477
|
+
</div>
|
|
478
|
+
</template>
|
|
479
|
+
|
|
480
|
+
<script>
|
|
481
|
+
import User from '@/models/User'
|
|
482
|
+
|
|
483
|
+
export default {
|
|
484
|
+
data() {
|
|
485
|
+
return {
|
|
486
|
+
showModal: false,
|
|
487
|
+
user: null
|
|
488
|
+
}
|
|
489
|
+
},
|
|
490
|
+
|
|
491
|
+
methods: {
|
|
492
|
+
openModal(userId = null) {
|
|
493
|
+
this.user = new User(userId ? { id: userId } : {})
|
|
494
|
+
|
|
495
|
+
if (userId) {
|
|
496
|
+
this.user.fetch().then(() => {
|
|
497
|
+
this.showModal = true
|
|
498
|
+
})
|
|
499
|
+
} else {
|
|
500
|
+
this.showModal = true
|
|
501
|
+
}
|
|
502
|
+
},
|
|
503
|
+
|
|
504
|
+
closeModal() {
|
|
505
|
+
this.showModal = false
|
|
506
|
+
this.user = null
|
|
507
|
+
},
|
|
508
|
+
|
|
509
|
+
onUserSaved(user) {
|
|
510
|
+
this.$notify({ title: 'User saved successfully!' })
|
|
511
|
+
this.closeModal()
|
|
512
|
+
// Refresh list or take other action
|
|
513
|
+
this.$emit('user-saved', user)
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
</script>
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
## Basic Form Structure
|
|
521
|
+
|
|
522
|
+
> **Note:** For CRUD operations and data editing, use [AwModelEdit](#model-based-forms-recommended) instead. `AwForm` is best for one-off operations like login, search, and contact forms where you need raw HTTP form submission.
|
|
523
|
+
|
|
524
|
+
### Simple Login Form
|
|
525
|
+
|
|
526
|
+
```markup
|
|
527
|
+
<template>
|
|
528
|
+
<AwForm
|
|
529
|
+
url="/api/login"
|
|
530
|
+
method="post"
|
|
531
|
+
@sended="onSuccess"
|
|
532
|
+
@error="onError"
|
|
533
|
+
>
|
|
534
|
+
<AwInput
|
|
535
|
+
name="email"
|
|
536
|
+
label="Email"
|
|
537
|
+
type="email"
|
|
538
|
+
required
|
|
539
|
+
/>
|
|
540
|
+
|
|
541
|
+
<AwPassword
|
|
542
|
+
name="password"
|
|
543
|
+
label="Password"
|
|
544
|
+
required
|
|
545
|
+
/>
|
|
546
|
+
|
|
547
|
+
<AwButton type="submit" :loading="isLoading">
|
|
548
|
+
Sign In
|
|
549
|
+
</AwButton>
|
|
550
|
+
</AwForm>
|
|
551
|
+
</template>
|
|
552
|
+
|
|
553
|
+
<script>
|
|
554
|
+
export default {
|
|
555
|
+
data() {
|
|
556
|
+
return {
|
|
557
|
+
isLoading: false
|
|
558
|
+
}
|
|
559
|
+
},
|
|
560
|
+
|
|
561
|
+
methods: {
|
|
562
|
+
onSuccess(response) {
|
|
563
|
+
this.$router.push('/dashboard')
|
|
564
|
+
},
|
|
565
|
+
|
|
566
|
+
onError(error) {
|
|
567
|
+
console.error('Login failed:', error)
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
</script>
|
|
572
|
+
```
|
|
573
|
+
|
|
574
|
+
### Registration Form
|
|
575
|
+
|
|
576
|
+
```markup
|
|
577
|
+
<template>
|
|
578
|
+
<AwForm url="/api/register" method="post" @sended="onRegistered">
|
|
579
|
+
<AwInput name="name" label="Full Name" required />
|
|
580
|
+
|
|
581
|
+
<AwInput name="email" label="Email" type="email" required />
|
|
582
|
+
|
|
583
|
+
<AwPassword name="password" label="Password" required />
|
|
584
|
+
|
|
585
|
+
<AwPassword name="password_confirmation" label="Confirm Password" required />
|
|
586
|
+
|
|
587
|
+
<AwCheckbox name="terms" required>
|
|
588
|
+
I agree to the Terms of Service
|
|
589
|
+
</AwCheckbox>
|
|
590
|
+
|
|
591
|
+
<AwButton type="submit" size="lg">
|
|
592
|
+
Create Account
|
|
593
|
+
</AwButton>
|
|
594
|
+
</AwForm>
|
|
595
|
+
</template>
|
|
596
|
+
```
|
|
597
|
+
|
|
598
|
+
## Form Inputs
|
|
599
|
+
|
|
600
|
+
### Text Inputs
|
|
601
|
+
|
|
602
|
+
```markup
|
|
603
|
+
<AwForm url="/api/profile" method="patch">
|
|
604
|
+
<!-- Basic text input -->
|
|
605
|
+
<AwInput name="first_name" label="First Name" />
|
|
606
|
+
|
|
607
|
+
<!-- With placeholder -->
|
|
608
|
+
<AwInput
|
|
609
|
+
name="company"
|
|
610
|
+
label="Company"
|
|
611
|
+
placeholder="Acme Inc."
|
|
612
|
+
/>
|
|
613
|
+
|
|
614
|
+
<!-- With description -->
|
|
615
|
+
<AwDescriptionInput
|
|
616
|
+
name="username"
|
|
617
|
+
label="Username"
|
|
618
|
+
description="This will be your public identifier"
|
|
619
|
+
/>
|
|
620
|
+
|
|
621
|
+
<!-- Textarea for long text -->
|
|
622
|
+
<AwTextarea
|
|
623
|
+
name="bio"
|
|
624
|
+
label="Biography"
|
|
625
|
+
rows="4"
|
|
626
|
+
/>
|
|
627
|
+
</AwForm>
|
|
628
|
+
```
|
|
629
|
+
|
|
630
|
+
### Select & Dropdowns
|
|
631
|
+
|
|
632
|
+
```markup
|
|
633
|
+
<AwForm url="/api/preferences" method="post">
|
|
634
|
+
<!-- Simple select -->
|
|
635
|
+
<AwSelect
|
|
636
|
+
name="country"
|
|
637
|
+
label="Country"
|
|
638
|
+
:options="['USA', 'Canada', 'UK', 'Germany']"
|
|
639
|
+
/>
|
|
640
|
+
|
|
641
|
+
<!-- Select with objects -->
|
|
642
|
+
<AwSelectObject
|
|
643
|
+
name="timezone"
|
|
644
|
+
label="Timezone"
|
|
645
|
+
:options="timezones"
|
|
646
|
+
option-value="id"
|
|
647
|
+
option-label="name"
|
|
648
|
+
/>
|
|
649
|
+
|
|
650
|
+
<!-- Native select (for better mobile UX) -->
|
|
651
|
+
<AwSelectNative
|
|
652
|
+
name="language"
|
|
653
|
+
label="Language"
|
|
654
|
+
:options="[
|
|
655
|
+
{ value: 'en', text: 'English' },
|
|
656
|
+
{ value: 'es', text: 'Spanish' },
|
|
657
|
+
{ value: 'fr', text: 'French' }
|
|
658
|
+
]"
|
|
659
|
+
/>
|
|
660
|
+
</AwForm>
|
|
661
|
+
```
|
|
662
|
+
|
|
663
|
+
### Date & Time Inputs
|
|
664
|
+
|
|
665
|
+
```markup
|
|
666
|
+
<AwForm url="/api/events" method="post">
|
|
667
|
+
<!-- Date picker -->
|
|
668
|
+
<AwDate
|
|
669
|
+
name="event_date"
|
|
670
|
+
label="Event Date"
|
|
671
|
+
:min="new Date()"
|
|
672
|
+
/>
|
|
673
|
+
|
|
674
|
+
<!-- Birthday picker -->
|
|
675
|
+
<AwBirthdayPicker
|
|
676
|
+
name="birthday"
|
|
677
|
+
label="Date of Birth"
|
|
678
|
+
/>
|
|
679
|
+
|
|
680
|
+
<!-- Calendar view -->
|
|
681
|
+
<AwCalendar
|
|
682
|
+
v-model="selectedDate"
|
|
683
|
+
name="appointment"
|
|
684
|
+
/>
|
|
685
|
+
</AwForm>
|
|
686
|
+
```
|
|
687
|
+
|
|
688
|
+
### Checkboxes & Radios
|
|
689
|
+
|
|
690
|
+
```markup
|
|
691
|
+
<AwForm url="/api/settings" method="patch">
|
|
692
|
+
<!-- Single checkbox -->
|
|
693
|
+
<AwCheckbox name="notifications">
|
|
694
|
+
Enable email notifications
|
|
695
|
+
</AwCheckbox>
|
|
696
|
+
|
|
697
|
+
<!-- Radio buttons -->
|
|
698
|
+
<div>
|
|
699
|
+
<label>Subscription Plan</label>
|
|
700
|
+
<AwRadio name="plan" value="free">Free</AwRadio>
|
|
701
|
+
<AwRadio name="plan" value="pro">Pro</AwRadio>
|
|
702
|
+
<AwRadio name="plan" value="enterprise">Enterprise</AwRadio>
|
|
703
|
+
</div>
|
|
704
|
+
|
|
705
|
+
<!-- Toggle switcher -->
|
|
706
|
+
<AwSwitcher name="dark_mode" label="Dark Mode" />
|
|
707
|
+
</AwForm>
|
|
708
|
+
```
|
|
709
|
+
|
|
710
|
+
### Specialized Inputs
|
|
711
|
+
|
|
712
|
+
```markup
|
|
713
|
+
<AwForm url="/api/profile" method="patch">
|
|
714
|
+
<!-- Telephone input -->
|
|
715
|
+
<AwTel name="phone" label="Phone Number" />
|
|
716
|
+
|
|
717
|
+
<!-- Money input -->
|
|
718
|
+
<AwMoney name="budget" label="Budget" currency="USD" />
|
|
719
|
+
|
|
720
|
+
<!-- Code input -->
|
|
721
|
+
<AwCode name="verification_code" label="Verification Code" />
|
|
722
|
+
|
|
723
|
+
<!-- Slider -->
|
|
724
|
+
<AwSlider name="volume" label="Volume" :min="0" :max="100" />
|
|
725
|
+
|
|
726
|
+
<!-- Chip select -->
|
|
727
|
+
<AwChipSelect
|
|
728
|
+
name="skills"
|
|
729
|
+
label="Skills"
|
|
730
|
+
:options="['Vue.js', 'React', 'Angular', 'Node.js']"
|
|
731
|
+
/>
|
|
732
|
+
</AwForm>
|
|
733
|
+
```
|
|
734
|
+
|
|
735
|
+
## Validation & Errors
|
|
736
|
+
|
|
737
|
+
### HTML5 Validation
|
|
738
|
+
|
|
739
|
+
```markup
|
|
740
|
+
<AwForm url="/api/submit" method="post">
|
|
741
|
+
<!-- Required field -->
|
|
742
|
+
<AwInput name="email" label="Email" required />
|
|
743
|
+
|
|
744
|
+
<!-- Email validation -->
|
|
745
|
+
<AwInput name="email" label="Email" type="email" required />
|
|
746
|
+
|
|
747
|
+
<!-- Pattern validation -->
|
|
748
|
+
<AwInput
|
|
749
|
+
name="username"
|
|
750
|
+
label="Username"
|
|
751
|
+
pattern="[a-zA-Z0-9_]+"
|
|
752
|
+
title="Only letters, numbers, and underscores"
|
|
753
|
+
/>
|
|
754
|
+
|
|
755
|
+
<!-- Min/max length -->
|
|
756
|
+
<AwInput
|
|
757
|
+
name="password"
|
|
758
|
+
label="Password"
|
|
759
|
+
type="password"
|
|
760
|
+
minlength="8"
|
|
761
|
+
maxlength="100"
|
|
762
|
+
/>
|
|
763
|
+
</AwForm>
|
|
764
|
+
```
|
|
765
|
+
|
|
766
|
+
### Server-Side Error Handling
|
|
767
|
+
|
|
768
|
+
```markup
|
|
769
|
+
<template>
|
|
770
|
+
<AwForm
|
|
771
|
+
ref="form"
|
|
772
|
+
url="/api/users"
|
|
773
|
+
method="post"
|
|
774
|
+
@error="handleErrors"
|
|
775
|
+
>
|
|
776
|
+
<AwInput name="email" label="Email" />
|
|
777
|
+
<AwInput name="username" label="Username" />
|
|
778
|
+
<AwButton type="submit">Submit</AwButton>
|
|
779
|
+
</AwForm>
|
|
780
|
+
</template>
|
|
781
|
+
|
|
782
|
+
<script>
|
|
783
|
+
export default {
|
|
784
|
+
methods: {
|
|
785
|
+
handleErrors(error) {
|
|
786
|
+
// AwForm automatically sets field errors via setCustomValidity
|
|
787
|
+
// The errors are displayed on the respective input fields
|
|
788
|
+
|
|
789
|
+
// Optionally handle specific error codes
|
|
790
|
+
if (error.response?.status === 422) {
|
|
791
|
+
console.log('Validation failed:', error.response.data.errors)
|
|
792
|
+
}
|
|
793
|
+
},
|
|
794
|
+
|
|
795
|
+
// Programmatically set errors
|
|
796
|
+
setCustomErrors() {
|
|
797
|
+
this.$refs.form.setErrors({
|
|
798
|
+
email: 'Email is already taken',
|
|
799
|
+
username: 'Username must be unique'
|
|
800
|
+
})
|
|
801
|
+
},
|
|
802
|
+
|
|
803
|
+
// Clear all errors
|
|
804
|
+
clearErrors() {
|
|
805
|
+
this.$refs.form.resetErrors()
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
</script>
|
|
810
|
+
```
|
|
811
|
+
|
|
812
|
+
### Custom Validation
|
|
813
|
+
|
|
814
|
+
```markup
|
|
815
|
+
<template>
|
|
816
|
+
<AwForm url="/api/submit" @submit.prevent="validateAndSubmit">
|
|
817
|
+
<AwInput
|
|
818
|
+
ref="password"
|
|
819
|
+
v-model="password"
|
|
820
|
+
name="password"
|
|
821
|
+
label="Password"
|
|
822
|
+
type="password"
|
|
823
|
+
/>
|
|
824
|
+
|
|
825
|
+
<AwInput
|
|
826
|
+
ref="passwordConfirm"
|
|
827
|
+
v-model="passwordConfirm"
|
|
828
|
+
name="password_confirmation"
|
|
829
|
+
label="Confirm Password"
|
|
830
|
+
type="password"
|
|
831
|
+
/>
|
|
832
|
+
|
|
833
|
+
<AwButton type="submit">Submit</AwButton>
|
|
834
|
+
</AwForm>
|
|
835
|
+
</template>
|
|
836
|
+
|
|
837
|
+
<script>
|
|
838
|
+
export default {
|
|
839
|
+
data() {
|
|
840
|
+
return {
|
|
841
|
+
password: '',
|
|
842
|
+
passwordConfirm: ''
|
|
843
|
+
}
|
|
844
|
+
},
|
|
845
|
+
|
|
846
|
+
methods: {
|
|
847
|
+
validateAndSubmit(event) {
|
|
848
|
+
// Clear previous errors
|
|
849
|
+
this.$refs.password.$el.querySelector('input').setCustomValidity('')
|
|
850
|
+
this.$refs.passwordConfirm.$el.querySelector('input').setCustomValidity('')
|
|
851
|
+
|
|
852
|
+
// Custom validation
|
|
853
|
+
if (this.password !== this.passwordConfirm) {
|
|
854
|
+
this.$refs.passwordConfirm.$el
|
|
855
|
+
.querySelector('input')
|
|
856
|
+
.setCustomValidity('Passwords do not match')
|
|
857
|
+
return
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
// Submit if valid
|
|
861
|
+
event.target.submit()
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
</script>
|
|
866
|
+
```
|
|
867
|
+
|
|
868
|
+
## File Uploads
|
|
869
|
+
|
|
870
|
+
### Single File Upload
|
|
871
|
+
|
|
872
|
+
```markup
|
|
873
|
+
<AwForm url="/api/avatar" method="post" enctype="multipart/form-data">
|
|
874
|
+
<AwUploader
|
|
875
|
+
name="avatar"
|
|
876
|
+
label="Profile Picture"
|
|
877
|
+
accept="image/*"
|
|
878
|
+
:max-size="5242880"
|
|
879
|
+
/>
|
|
880
|
+
|
|
881
|
+
<AwButton type="submit">Upload</AwButton>
|
|
882
|
+
</AwForm>
|
|
883
|
+
```
|
|
884
|
+
|
|
885
|
+
### Multiple Files Upload
|
|
886
|
+
|
|
887
|
+
```markup
|
|
888
|
+
<AwForm url="/api/documents" method="post">
|
|
889
|
+
<AwUploaderFiles
|
|
890
|
+
name="documents"
|
|
891
|
+
label="Documents"
|
|
892
|
+
multiple
|
|
893
|
+
:max-files="5"
|
|
894
|
+
accept=".pdf,.doc,.docx"
|
|
895
|
+
/>
|
|
896
|
+
|
|
897
|
+
<AwButton type="submit">Upload Documents</AwButton>
|
|
898
|
+
</AwForm>
|
|
899
|
+
```
|
|
900
|
+
|
|
901
|
+
### Image Upload with Cropper
|
|
902
|
+
|
|
903
|
+
```markup
|
|
904
|
+
<template>
|
|
905
|
+
<AwForm url="/api/profile-image" method="post">
|
|
906
|
+
<AwCropper
|
|
907
|
+
v-model="croppedImage"
|
|
908
|
+
name="profile_image"
|
|
909
|
+
label="Profile Image"
|
|
910
|
+
:aspect-ratio="1"
|
|
911
|
+
:max-size="2097152"
|
|
912
|
+
/>
|
|
913
|
+
|
|
914
|
+
<AwButton type="submit" :disabled="!croppedImage">
|
|
915
|
+
Save Image
|
|
916
|
+
</AwButton>
|
|
917
|
+
</AwForm>
|
|
918
|
+
</template>
|
|
919
|
+
```
|
|
920
|
+
|
|
921
|
+
## Complex Forms
|
|
922
|
+
|
|
923
|
+
### Form with Nested Data
|
|
924
|
+
|
|
925
|
+
```markup
|
|
926
|
+
<template>
|
|
927
|
+
<AwForm url="/api/companies" method="post" @sended="onSuccess">
|
|
928
|
+
<!-- Company details -->
|
|
929
|
+
<AwInput name="company[name]" label="Company Name" />
|
|
930
|
+
<AwInput name="company[tax_id]" label="Tax ID" />
|
|
931
|
+
|
|
932
|
+
<!-- Address -->
|
|
933
|
+
<AwAddress
|
|
934
|
+
name="company[address]"
|
|
935
|
+
label="Company Address"
|
|
936
|
+
:with-google-maps="true"
|
|
937
|
+
/>
|
|
938
|
+
|
|
939
|
+
<!-- Contact person -->
|
|
940
|
+
<AwInput name="contact[name]" label="Contact Name" />
|
|
941
|
+
<AwInput name="contact[email]" label="Contact Email" type="email" />
|
|
942
|
+
<AwTel name="contact[phone]" label="Contact Phone" />
|
|
943
|
+
|
|
944
|
+
<AwButton type="submit">Create Company</AwButton>
|
|
945
|
+
</AwForm>
|
|
946
|
+
</template>
|
|
947
|
+
```
|
|
948
|
+
|
|
949
|
+
### Dynamic Form Fields
|
|
950
|
+
|
|
951
|
+
```markup
|
|
952
|
+
<template>
|
|
953
|
+
<AwForm url="/api/projects" method="post">
|
|
954
|
+
<AwInput name="project_name" label="Project Name" />
|
|
955
|
+
|
|
956
|
+
<!-- Dynamic team members -->
|
|
957
|
+
<div v-for="(member, index) in members" :key="index">
|
|
958
|
+
<h4>Team Member {{ index + 1 }}</h4>
|
|
959
|
+
<AwInput :name="`members[${index}][name]`" label="Name" />
|
|
960
|
+
<AwInput :name="`members[${index}][email]`" label="Email" type="email" />
|
|
961
|
+
<AwButton @click="removeMember(index)" theme="outline" color="error">
|
|
962
|
+
Remove
|
|
963
|
+
</AwButton>
|
|
964
|
+
</div>
|
|
965
|
+
|
|
966
|
+
<AwButton @click="addMember" theme="outline">
|
|
967
|
+
Add Team Member
|
|
968
|
+
</AwButton>
|
|
969
|
+
|
|
970
|
+
<AwButton type="submit">Create Project</AwButton>
|
|
971
|
+
</AwForm>
|
|
972
|
+
</template>
|
|
973
|
+
|
|
974
|
+
<script>
|
|
975
|
+
export default {
|
|
976
|
+
data() {
|
|
977
|
+
return {
|
|
978
|
+
members: [{ name: '', email: '' }]
|
|
979
|
+
}
|
|
980
|
+
},
|
|
981
|
+
|
|
982
|
+
methods: {
|
|
983
|
+
addMember() {
|
|
984
|
+
this.members.push({ name: '', email: '' })
|
|
985
|
+
},
|
|
986
|
+
|
|
987
|
+
removeMember(index) {
|
|
988
|
+
this.members.splice(index, 1)
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
</script>
|
|
993
|
+
```
|
|
994
|
+
|
|
995
|
+
## Modal Forms
|
|
996
|
+
|
|
997
|
+
### Simple Modal Form
|
|
998
|
+
|
|
999
|
+
```markup
|
|
1000
|
+
<template>
|
|
1001
|
+
<AwModal :show="showModal" @close="showModal = false">
|
|
1002
|
+
<template #title>Create New User</template>
|
|
1003
|
+
|
|
1004
|
+
<AwForm url="/api/users" method="post" @sended="onUserCreated">
|
|
1005
|
+
<AwInput name="name" label="Name" required />
|
|
1006
|
+
<AwInput name="email" label="Email" type="email" required />
|
|
1007
|
+
<AwSelect name="role" label="Role" :options="roles" />
|
|
1008
|
+
|
|
1009
|
+
<template #buttons>
|
|
1010
|
+
<AwButton type="submit">Create User</AwButton>
|
|
1011
|
+
<AwButton @click="showModal = false" color="mono">
|
|
1012
|
+
Cancel
|
|
1013
|
+
</AwButton>
|
|
1014
|
+
</template>
|
|
1015
|
+
</AwForm>
|
|
1016
|
+
</AwModal>
|
|
1017
|
+
</template>
|
|
1018
|
+
|
|
1019
|
+
<script>
|
|
1020
|
+
export default {
|
|
1021
|
+
data() {
|
|
1022
|
+
return {
|
|
1023
|
+
showModal: false,
|
|
1024
|
+
roles: ['Admin', 'Editor', 'Viewer']
|
|
1025
|
+
}
|
|
1026
|
+
},
|
|
1027
|
+
|
|
1028
|
+
methods: {
|
|
1029
|
+
onUserCreated(response) {
|
|
1030
|
+
this.showModal = false
|
|
1031
|
+
this.$notify({ title: 'User created successfully!' })
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
</script>
|
|
1036
|
+
```
|
|
1037
|
+
|
|
1038
|
+
## Multi-Step Forms
|
|
1039
|
+
|
|
1040
|
+
### Multi-Step Registration
|
|
1041
|
+
|
|
1042
|
+
```markup
|
|
1043
|
+
<template>
|
|
1044
|
+
<div>
|
|
1045
|
+
<AwProgress :value="(currentStep / totalSteps) * 100" />
|
|
1046
|
+
|
|
1047
|
+
<AwForm
|
|
1048
|
+
ref="form"
|
|
1049
|
+
url="/api/register"
|
|
1050
|
+
method="post"
|
|
1051
|
+
@submit.prevent="handleStep"
|
|
1052
|
+
>
|
|
1053
|
+
<!-- Step 1: Basic Info -->
|
|
1054
|
+
<div v-show="currentStep === 1">
|
|
1055
|
+
<h2>Step 1: Basic Information</h2>
|
|
1056
|
+
<AwInput v-model="formData.name" name="name" label="Full Name" required />
|
|
1057
|
+
<AwInput v-model="formData.email" name="email" label="Email" type="email" required />
|
|
1058
|
+
<AwPassword v-model="formData.password" name="password" label="Password" required />
|
|
1059
|
+
</div>
|
|
1060
|
+
|
|
1061
|
+
<!-- Step 2: Profile -->
|
|
1062
|
+
<div v-show="currentStep === 2">
|
|
1063
|
+
<h2>Step 2: Profile Details</h2>
|
|
1064
|
+
<AwBirthdayPicker v-model="formData.birthday" name="birthday" label="Birthday" />
|
|
1065
|
+
<AwTel v-model="formData.phone" name="phone" label="Phone" />
|
|
1066
|
+
<AwTextarea v-model="formData.bio" name="bio" label="Bio" />
|
|
1067
|
+
</div>
|
|
1068
|
+
|
|
1069
|
+
<!-- Step 3: Preferences -->
|
|
1070
|
+
<div v-show="currentStep === 3">
|
|
1071
|
+
<h2>Step 3: Preferences</h2>
|
|
1072
|
+
<AwSelect v-model="formData.timezone" name="timezone" label="Timezone" :options="timezones" />
|
|
1073
|
+
<AwCheckbox v-model="formData.newsletter" name="newsletter">
|
|
1074
|
+
Subscribe to newsletter
|
|
1075
|
+
</AwCheckbox>
|
|
1076
|
+
</div>
|
|
1077
|
+
|
|
1078
|
+
<!-- Navigation -->
|
|
1079
|
+
<AwFlow justify="between">
|
|
1080
|
+
<AwButton
|
|
1081
|
+
v-if="currentStep > 1"
|
|
1082
|
+
@click="currentStep--"
|
|
1083
|
+
theme="outline"
|
|
1084
|
+
>
|
|
1085
|
+
Previous
|
|
1086
|
+
</AwButton>
|
|
1087
|
+
|
|
1088
|
+
<AwButton v-if="currentStep < totalSteps" type="button" @click="nextStep">
|
|
1089
|
+
Next
|
|
1090
|
+
</AwButton>
|
|
1091
|
+
|
|
1092
|
+
<AwButton v-else type="submit">
|
|
1093
|
+
Complete Registration
|
|
1094
|
+
</AwButton>
|
|
1095
|
+
</AwFlow>
|
|
1096
|
+
</AwForm>
|
|
1097
|
+
</div>
|
|
1098
|
+
</template>
|
|
1099
|
+
|
|
1100
|
+
<script>
|
|
1101
|
+
export default {
|
|
1102
|
+
data() {
|
|
1103
|
+
return {
|
|
1104
|
+
currentStep: 1,
|
|
1105
|
+
totalSteps: 3,
|
|
1106
|
+
formData: {
|
|
1107
|
+
name: '',
|
|
1108
|
+
email: '',
|
|
1109
|
+
password: '',
|
|
1110
|
+
birthday: null,
|
|
1111
|
+
phone: '',
|
|
1112
|
+
bio: '',
|
|
1113
|
+
timezone: '',
|
|
1114
|
+
newsletter: false
|
|
1115
|
+
},
|
|
1116
|
+
timezones: ['UTC', 'EST', 'PST', 'GMT']
|
|
1117
|
+
}
|
|
1118
|
+
},
|
|
1119
|
+
|
|
1120
|
+
methods: {
|
|
1121
|
+
nextStep() {
|
|
1122
|
+
// Validate current step before proceeding
|
|
1123
|
+
if (this.$refs.form.$el.checkValidity()) {
|
|
1124
|
+
this.currentStep++
|
|
1125
|
+
} else {
|
|
1126
|
+
this.$refs.form.$el.reportValidity()
|
|
1127
|
+
}
|
|
1128
|
+
},
|
|
1129
|
+
|
|
1130
|
+
handleStep(event) {
|
|
1131
|
+
// Final submission
|
|
1132
|
+
event.target.submit()
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1136
|
+
</script>
|
|
1137
|
+
```
|
|
1138
|
+
|
|
1139
|
+
## Best Practices
|
|
1140
|
+
|
|
1141
|
+
### 1. Choose the Right Form Component
|
|
1142
|
+
|
|
1143
|
+
```markup
|
|
1144
|
+
<!-- Good: Use AwModelEdit for CRUD operations -->
|
|
1145
|
+
<AwModelEdit :model="user">
|
|
1146
|
+
<AwInput v-model="user.email" :error="user.errors.email" label="Email" />
|
|
1147
|
+
</AwModelEdit>
|
|
1148
|
+
|
|
1149
|
+
<!-- Good: Use AwForm for one-off operations -->
|
|
1150
|
+
<AwForm url="/api/login" method="post">
|
|
1151
|
+
<AwInput name="email" label="Email" />
|
|
1152
|
+
<AwButton type="submit">Login</AwButton>
|
|
1153
|
+
</AwForm>
|
|
1154
|
+
|
|
1155
|
+
<!-- Bad: Using AwForm for editing records (no change detection) -->
|
|
1156
|
+
<AwForm url="/api/users/1" method="patch">
|
|
1157
|
+
<AwInput name="email" label="Email" />
|
|
1158
|
+
</AwForm>
|
|
1159
|
+
```
|
|
1160
|
+
|
|
1161
|
+
### 2. Always Use Labels
|
|
1162
|
+
|
|
1163
|
+
```markup
|
|
1164
|
+
<!-- Good -->
|
|
1165
|
+
<AwInput name="email" label="Email" />
|
|
1166
|
+
|
|
1167
|
+
<!-- Bad -->
|
|
1168
|
+
<AwInput name="email" placeholder="Email" />
|
|
1169
|
+
```
|
|
1170
|
+
|
|
1171
|
+
### 3. Provide Clear Feedback
|
|
1172
|
+
|
|
1173
|
+
```markup
|
|
1174
|
+
<AwForm url="/api/save" @sended="onSuccess" @error="onError">
|
|
1175
|
+
<AwInput name="title" label="Title" />
|
|
1176
|
+
<AwButton type="submit" :loading="isSubmitting">
|
|
1177
|
+
{{ isSubmitting ? 'Saving...' : 'Save' }}
|
|
1178
|
+
</AwButton>
|
|
1179
|
+
</AwForm>
|
|
1180
|
+
```
|
|
1181
|
+
|
|
1182
|
+
### 4. Handle Loading States
|
|
1183
|
+
|
|
1184
|
+
For form data loading, use `AwContentPlaceholder`:
|
|
1185
|
+
|
|
1186
|
+
```markup
|
|
1187
|
+
<template>
|
|
1188
|
+
<AwContentPlaceholder v-if="loading" type="form" :lines="4" />
|
|
1189
|
+
|
|
1190
|
+
<AwForm v-else ref="form" url="/api/submit" @submit="onSubmit">
|
|
1191
|
+
<AwInput name="data" label="Data" />
|
|
1192
|
+
<AwButton type="submit">Submit</AwButton>
|
|
1193
|
+
</AwForm>
|
|
1194
|
+
</template>
|
|
1195
|
+
|
|
1196
|
+
<script>
|
|
1197
|
+
export default {
|
|
1198
|
+
data() {
|
|
1199
|
+
return {
|
|
1200
|
+
loading: true
|
|
1201
|
+
}
|
|
1202
|
+
},
|
|
1203
|
+
async mounted() {
|
|
1204
|
+
await this.loadFormData()
|
|
1205
|
+
this.loading = false
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1208
|
+
</script>
|
|
1209
|
+
```
|
|
1210
|
+
|
|
1211
|
+
For complex forms with multiple sections:
|
|
1212
|
+
|
|
1213
|
+
```markup
|
|
1214
|
+
<template>
|
|
1215
|
+
<AwGrid v-if="loading" :col="{ lg: 3 }">
|
|
1216
|
+
<div span="{ lg: 2 }">
|
|
1217
|
+
<AwContentPlaceholder type="form" :lines="8" />
|
|
1218
|
+
</div>
|
|
1219
|
+
<div>
|
|
1220
|
+
<AwContentPlaceholder type="form" :lines="4" />
|
|
1221
|
+
</div>
|
|
1222
|
+
</AwGrid>
|
|
1223
|
+
|
|
1224
|
+
<AwForm v-else url="/api/submit">
|
|
1225
|
+
<!-- Form content -->
|
|
1226
|
+
</AwForm>
|
|
1227
|
+
</template>
|
|
1228
|
+
```
|
|
1229
|
+
|
|
1230
|
+
### 5. Use Appropriate Input Types
|
|
1231
|
+
|
|
1232
|
+
```markup
|
|
1233
|
+
<!-- Email validation -->
|
|
1234
|
+
<AwInput name="email" label="Email" type="email" />
|
|
1235
|
+
|
|
1236
|
+
<!-- Number input -->
|
|
1237
|
+
<AwInput name="age" label="Age" type="number" :min="0" :max="120" />
|
|
1238
|
+
|
|
1239
|
+
<!-- URL input -->
|
|
1240
|
+
<AwInput name="website" label="Website" type="url" />
|
|
1241
|
+
```
|
|
1242
|
+
|
|
1243
|
+
### 6. Group Related Fields
|
|
1244
|
+
|
|
1245
|
+
```markup
|
|
1246
|
+
<AwForm url="/api/users" method="post">
|
|
1247
|
+
<AwCard title="Personal Information">
|
|
1248
|
+
<AwInput name="first_name" label="First Name" />
|
|
1249
|
+
<AwInput name="last_name" label="Last Name" />
|
|
1250
|
+
<AwBirthdayPicker name="birthday" label="Birthday" />
|
|
1251
|
+
</AwCard>
|
|
1252
|
+
|
|
1253
|
+
<AwCard title="Contact Information">
|
|
1254
|
+
<AwInput name="email" label="Email" type="email" />
|
|
1255
|
+
<AwTel name="phone" label="Phone" />
|
|
1256
|
+
</AwCard>
|
|
1257
|
+
|
|
1258
|
+
<AwButton type="submit">Save</AwButton>
|
|
1259
|
+
</AwForm>
|
|
1260
|
+
```
|
|
1261
|
+
|
|
1262
|
+
### 7. Provide Help Text
|
|
1263
|
+
|
|
1264
|
+
```markup
|
|
1265
|
+
<AwDescriptionInput
|
|
1266
|
+
name="api_key"
|
|
1267
|
+
label="API Key"
|
|
1268
|
+
description="You can find your API key in the developer settings"
|
|
1269
|
+
type="password"
|
|
1270
|
+
/>
|
|
1271
|
+
```
|
|
1272
|
+
|
|
1273
|
+
### 8. Use Method Override for PUT/PATCH
|
|
1274
|
+
|
|
1275
|
+
```markup
|
|
1276
|
+
<!-- For Laravel/REST APIs that don't support PUT/PATCH natively -->
|
|
1277
|
+
<AwForm url="/api/users/1" method="patch">
|
|
1278
|
+
<AwInput name="name" label="Name" />
|
|
1279
|
+
<AwButton type="submit">Update</AwButton>
|
|
1280
|
+
</AwForm>
|
|
1281
|
+
```
|
|
1282
|
+
|
|
1283
|
+
## Common Patterns
|
|
1284
|
+
|
|
1285
|
+
### Search Form
|
|
1286
|
+
|
|
1287
|
+
```markup
|
|
1288
|
+
<AwForm url="/api/search" method="get">
|
|
1289
|
+
<AwSearch
|
|
1290
|
+
name="q"
|
|
1291
|
+
placeholder="Search..."
|
|
1292
|
+
@input="debounceSearch"
|
|
1293
|
+
/>
|
|
1294
|
+
</AwForm>
|
|
1295
|
+
```
|
|
1296
|
+
|
|
1297
|
+
### Filter Form
|
|
1298
|
+
|
|
1299
|
+
```markup
|
|
1300
|
+
<AwForm url="/api/products" method="get">
|
|
1301
|
+
<AwSelect name="category" label="Category" :options="categories" />
|
|
1302
|
+
<AwSlider name="price_min" label="Min Price" :min="0" :max="1000" />
|
|
1303
|
+
<AwSlider name="price_max" label="Max Price" :min="0" :max="1000" />
|
|
1304
|
+
<AwButton type="submit">Apply Filters</AwButton>
|
|
1305
|
+
<AwButton type="reset" theme="outline">Reset</AwButton>
|
|
1306
|
+
</AwForm>
|
|
1307
|
+
```
|
|
1308
|
+
|
|
1309
|
+
### Inline Edit Form
|
|
1310
|
+
|
|
1311
|
+
```markup
|
|
1312
|
+
<AwForm url="/api/tasks/1" method="patch" @sended="onSaved">
|
|
1313
|
+
<AwInput
|
|
1314
|
+
v-model="taskName"
|
|
1315
|
+
name="name"
|
|
1316
|
+
@blur="$refs.form.$el.submit()"
|
|
1317
|
+
/>
|
|
1318
|
+
</AwForm>
|
|
1319
|
+
```
|
|
1320
|
+
|
|
1321
|
+
---
|
|
1322
|
+
|
|
1323
|
+
For more examples, see individual component documentation:
|
|
1324
|
+
- [AwModelEdit](../components/organisms/aw-model-edit.md) - Model-based forms (recommended)
|
|
1325
|
+
- [AwForm](../components/organisms/aw-form.md) - Raw form submission
|
|
1326
|
+
- [AwInput](../components/atoms/aw-input.md) - Text inputs
|
|
1327
|
+
- [AwSelect](../components/molecules/aw-select.md) - Select dropdowns
|
|
1328
|
+
- [AwUploader](../components/organisms/aw-uploader.md) - File uploads
|
|
1329
|
+
- [Vue-MC Models Guide](../../vue-mc/docs/models.md) - Model definitions
|