@awes-io/ui 2.142.0 → 2.143.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.
Files changed (239) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/assets/css/components/_index.css +7 -1
  3. package/assets/css/components/animation.css +38 -32
  4. package/assets/css/components/content-placeholder.css +103 -0
  5. package/assets/css/components/empty-container.css +69 -1
  6. package/assets/css/components/filter-chosen.css +6 -0
  7. package/assets/css/components/filter-date-range.css +17 -1
  8. package/assets/css/components/filter-month.css +23 -17
  9. package/assets/css/components/filter-select.css +11 -0
  10. package/assets/css/components/layout.css +1 -32
  11. package/assets/css/components/modal.css +1 -1
  12. package/assets/css/components/number.css +12 -0
  13. package/assets/css/components/page-aside.css +54 -0
  14. package/assets/js/css.js +1 -1
  15. package/assets/js/icons/mono.js +59 -91
  16. package/assets/js/icons/multicolor.js +1 -31
  17. package/components/1_atoms/AwContentPlaceholder.vue +60 -0
  18. package/components/1_atoms/AwFlow.vue +21 -48
  19. package/components/1_atoms/AwLabel.vue +1 -1
  20. package/components/2_molecules/AwButton.vue +1 -1
  21. package/components/2_molecules/AwEmptyContainer.vue +74 -72
  22. package/components/2_molecules/AwNumber.vue +180 -0
  23. package/components/2_molecules/AwSelect.vue +11 -4
  24. package/components/3_organisms/AwFilterChosen.vue +73 -0
  25. package/components/3_organisms/AwFilterDateRange.vue +177 -0
  26. package/components/3_organisms/AwFilterMonth.vue +37 -40
  27. package/components/3_organisms/AwFilterSelect.vue +368 -0
  28. package/components/3_organisms/AwImageUpload.vue +1 -1
  29. package/components/3_organisms/AwMarkdownEditor.vue +0 -0
  30. package/components/3_organisms/AwMultiBlockBuilder.vue +1 -1
  31. package/components/3_organisms/AwTable/AwTableBuilder.vue +12 -60
  32. package/components/4_pages/AwPageAside.vue +108 -0
  33. package/components/5_layouts/AwLayoutCenter.vue +3 -8
  34. package/components/5_layouts/_AwUserMenu.vue +1 -1
  35. package/dist/css/aw-icons.css +26 -0
  36. package/dist/fonts/aw-icons.svg +18 -0
  37. package/dist/fonts/aw-icons.ttf +0 -0
  38. package/dist/fonts/aw-icons.woff +0 -0
  39. package/dist/fonts/aw-icons.woff2 +0 -0
  40. package/docs/_template.md +80 -0
  41. package/docs/components/atoms/aw-accordion-fold.md +91 -0
  42. package/docs/components/atoms/aw-action-card-body.md +67 -0
  43. package/docs/components/atoms/aw-action-card.md +94 -0
  44. package/docs/components/atoms/aw-action-icon.md +88 -0
  45. package/docs/components/atoms/aw-avatar.md +106 -0
  46. package/docs/components/atoms/aw-card.md +112 -0
  47. package/docs/components/atoms/aw-checkbox.md +112 -0
  48. package/docs/components/atoms/aw-content-placeholder.md +116 -0
  49. package/docs/components/atoms/aw-description.md +83 -0
  50. package/docs/components/atoms/aw-dock.md +84 -0
  51. package/docs/components/atoms/aw-dropdown-button.md +94 -0
  52. package/docs/components/atoms/aw-dropdown.md +128 -0
  53. package/docs/components/atoms/aw-file.md +73 -0
  54. package/docs/components/atoms/aw-flow.md +92 -0
  55. package/docs/components/atoms/aw-grid.md +91 -0
  56. package/docs/components/atoms/aw-headline.md +71 -0
  57. package/docs/components/atoms/aw-icon-system-color.md +121 -0
  58. package/docs/components/atoms/aw-icon-system-mono.md +205 -0
  59. package/docs/components/atoms/aw-icon.md +235 -0
  60. package/docs/components/atoms/aw-info.md +85 -0
  61. package/docs/components/atoms/aw-input.md +120 -0
  62. package/docs/components/atoms/aw-label.md +83 -0
  63. package/docs/components/atoms/aw-link.md +99 -0
  64. package/docs/components/atoms/aw-list.md +88 -0
  65. package/docs/components/atoms/aw-progress.md +70 -0
  66. package/docs/components/atoms/aw-radio.md +109 -0
  67. package/docs/components/atoms/aw-refresh-wrapper.md +81 -0
  68. package/docs/components/atoms/aw-select-native.md +106 -0
  69. package/docs/components/atoms/aw-slider.md +82 -0
  70. package/docs/components/atoms/aw-sub-headline.md +73 -0
  71. package/docs/components/atoms/aw-switcher.md +115 -0
  72. package/docs/components/atoms/aw-tag.md +80 -0
  73. package/docs/components/atoms/aw-title.md +70 -0
  74. package/docs/components/atoms/aw-toggler.md +69 -0
  75. package/docs/components/layouts/aw-layout-center.md +168 -0
  76. package/docs/components/layouts/aw-layout-error.md +153 -0
  77. package/docs/components/layouts/aw-layout-provider.md +238 -0
  78. package/docs/components/layouts/aw-layout.md +88 -0
  79. package/docs/components/molecules/aw-action-button.md +91 -0
  80. package/docs/components/molecules/aw-alert.md +96 -0
  81. package/docs/components/molecules/aw-badge.md +108 -0
  82. package/docs/components/molecules/aw-banner-text.md +90 -0
  83. package/docs/components/molecules/aw-button-nav.md +46 -0
  84. package/docs/components/molecules/aw-button.md +123 -0
  85. package/docs/components/molecules/aw-description-input.md +67 -0
  86. package/docs/components/molecules/aw-empty-container.md +86 -0
  87. package/docs/components/molecules/aw-island.md +234 -0
  88. package/docs/components/molecules/aw-number.md +138 -0
  89. package/docs/components/molecules/aw-select-object.md +401 -0
  90. package/docs/components/molecules/aw-select.md +215 -0
  91. package/docs/components/molecules/aw-tab-nav.md +108 -0
  92. package/docs/components/molecules/aw-tel.md +129 -0
  93. package/docs/components/molecules/aw-textarea.md +83 -0
  94. package/docs/components/molecules/aw-userpic.md +115 -0
  95. package/docs/components/organisms/aw-address-block.md +64 -0
  96. package/docs/components/organisms/aw-address.md +132 -0
  97. package/docs/components/organisms/aw-birthday-picker.md +73 -0
  98. package/docs/components/organisms/aw-bottom-bar.md +66 -0
  99. package/docs/components/organisms/aw-calendar-days.md +115 -0
  100. package/docs/components/organisms/aw-calendar-nav.md +98 -0
  101. package/docs/components/organisms/aw-calendar-view.md +98 -0
  102. package/docs/components/organisms/aw-calendar.md +166 -0
  103. package/docs/components/organisms/aw-chart.md +154 -0
  104. package/docs/components/organisms/aw-chip-select.md +164 -0
  105. package/docs/components/organisms/aw-chip.md +126 -0
  106. package/docs/components/organisms/aw-code-snippet.md +94 -0
  107. package/docs/components/organisms/aw-code.md +132 -0
  108. package/docs/components/organisms/aw-context-menu.md +117 -0
  109. package/docs/components/organisms/aw-cropper.md +151 -0
  110. package/docs/components/organisms/aw-date.md +161 -0
  111. package/docs/components/organisms/aw-display-date.md +33 -0
  112. package/docs/components/organisms/aw-download-link.md +46 -0
  113. package/docs/components/organisms/aw-fetch-data.md +161 -0
  114. package/docs/components/organisms/aw-filter-chosen.md +226 -0
  115. package/docs/components/organisms/aw-filter-date-range.md +205 -0
  116. package/docs/components/organisms/aw-filter-month.md +43 -0
  117. package/docs/components/organisms/aw-filter-select.md +225 -0
  118. package/docs/components/organisms/aw-form.md +174 -0
  119. package/docs/components/organisms/aw-gmap-marker.md +86 -0
  120. package/docs/components/organisms/aw-gmap.md +90 -0
  121. package/docs/components/organisms/aw-image-upload.md +56 -0
  122. package/docs/components/organisms/aw-island-avatar.md +87 -0
  123. package/docs/components/organisms/aw-markdown-editor.md +104 -0
  124. package/docs/components/organisms/aw-modal-buttons.md +57 -0
  125. package/docs/components/organisms/aw-modal.md +246 -0
  126. package/docs/components/organisms/aw-model-edit.md +74 -0
  127. package/docs/components/organisms/aw-money.md +53 -0
  128. package/docs/components/organisms/aw-multi-block-builder.md +165 -0
  129. package/docs/components/organisms/aw-pagination.md +121 -0
  130. package/docs/components/organisms/aw-password.md +103 -0
  131. package/docs/components/organisms/aw-preview-card.md +45 -0
  132. package/docs/components/organisms/aw-search.md +116 -0
  133. package/docs/components/organisms/aw-subnav.md +122 -0
  134. package/docs/components/organisms/aw-table-builder.md +165 -0
  135. package/docs/components/organisms/aw-table-col.md +123 -0
  136. package/docs/components/organisms/aw-table-head.md +92 -0
  137. package/docs/components/organisms/aw-table-row.md +91 -0
  138. package/docs/components/organisms/aw-table.md +172 -0
  139. package/docs/components/organisms/aw-tags.md +54 -0
  140. package/docs/components/organisms/aw-toggle-show-aside.md +43 -0
  141. package/docs/components/organisms/aw-uploader-files.md +125 -0
  142. package/docs/components/organisms/aw-uploader.md +163 -0
  143. package/docs/components/organisms/aw-user-menu.md +87 -0
  144. package/docs/components/pages/aw-page-aside.md +296 -0
  145. package/docs/components/pages/aw-page-menu-buttons.md +172 -0
  146. package/docs/components/pages/aw-page-modal.md +198 -0
  147. package/docs/components/pages/aw-page-single.md +253 -0
  148. package/docs/components/pages/aw-page.md +194 -0
  149. package/docs/configuration.md +493 -0
  150. package/docs/cookbook/advanced-patterns.md +1388 -0
  151. package/docs/cookbook/common-patterns.md +965 -0
  152. package/docs/cookbook/index.md +786 -0
  153. package/docs/getting-started.md +596 -0
  154. package/docs/guides/best-practices.md +1106 -0
  155. package/docs/guides/data-fetching.md +852 -0
  156. package/docs/guides/error-handling.md +1172 -0
  157. package/docs/guides/forms-guide.md +1329 -0
  158. package/docs/guides/mobile-subnavigation.md +359 -0
  159. package/docs/guides/page-patterns/aside-pages.md +1418 -0
  160. package/docs/guides/page-patterns/dashboard-pages.md +990 -0
  161. package/docs/guides/page-patterns/detail-pages.md +1493 -0
  162. package/docs/guides/page-patterns/list-pages.md +1094 -0
  163. package/docs/index.md +263 -1
  164. package/docs/integrations.md +870 -0
  165. package/docs/reference/menu.md +462 -0
  166. package/docs/reference/plugins.md +970 -0
  167. package/docs/reference/troubleshooting.md +945 -0
  168. package/nuxt/awes.config.js +9 -8
  169. package/nuxt/icons.css +26 -0
  170. package/nuxt/index.js +2 -2
  171. package/nuxt/pages/more.vue +1 -1
  172. package/package.json +5 -3
  173. package/readme.md +171 -1
  174. package/docs/aw-accordion-fold.md +0 -46
  175. package/docs/aw-address.md +0 -44
  176. package/docs/aw-avatar.md +0 -51
  177. package/docs/aw-badge.md +0 -32
  178. package/docs/aw-button-nav.md +0 -44
  179. package/docs/aw-button.md +0 -50
  180. package/docs/aw-calendar-days.md +0 -46
  181. package/docs/aw-calendar-nav.md +0 -25
  182. package/docs/aw-calendar-view.md +0 -12
  183. package/docs/aw-calendar.md +0 -59
  184. package/docs/aw-card.md +0 -48
  185. package/docs/aw-chart.md +0 -51
  186. package/docs/aw-checkbox.md +0 -56
  187. package/docs/aw-chip-select.md +0 -46
  188. package/docs/aw-chip.md +0 -53
  189. package/docs/aw-code-snippet.md +0 -18
  190. package/docs/aw-code.md +0 -56
  191. package/docs/aw-content-wrapper.md +0 -40
  192. package/docs/aw-context-menu.md +0 -31
  193. package/docs/aw-cropper.md +0 -60
  194. package/docs/aw-dashboard-card.md +0 -37
  195. package/docs/aw-dashboard-donut.md +0 -30
  196. package/docs/aw-dashboard-line.md +0 -20
  197. package/docs/aw-dashboard-progress.md +0 -33
  198. package/docs/aw-dashboard-section.md +0 -32
  199. package/docs/aw-dashboard-speed.md +0 -30
  200. package/docs/aw-date.md +0 -52
  201. package/docs/aw-dropdown-button.md +0 -31
  202. package/docs/aw-dropdown.md +0 -69
  203. package/docs/aw-fetch-data.md +0 -45
  204. package/docs/aw-form.md +0 -52
  205. package/docs/aw-grid.md +0 -48
  206. package/docs/aw-icon.md +0 -50
  207. package/docs/aw-info.md +0 -53
  208. package/docs/aw-input.md +0 -55
  209. package/docs/aw-layout-default.md +0 -30
  210. package/docs/aw-layout-frame-center.md +0 -29
  211. package/docs/aw-layout-simple.md +0 -49
  212. package/docs/aw-link.md +0 -54
  213. package/docs/aw-markdown-editor.md +0 -51
  214. package/docs/aw-modal.md +0 -63
  215. package/docs/aw-multi-block-builder.md +0 -66
  216. package/docs/aw-page.md +0 -36
  217. package/docs/aw-pagination.md +0 -54
  218. package/docs/aw-password.md +0 -48
  219. package/docs/aw-radio.md +0 -54
  220. package/docs/aw-search.md +0 -49
  221. package/docs/aw-select.md +0 -93
  222. package/docs/aw-slider.md +0 -40
  223. package/docs/aw-svg-image.md +0 -19
  224. package/docs/aw-switcher.md +0 -51
  225. package/docs/aw-tab-nav.md +0 -55
  226. package/docs/aw-table-builder.md +0 -58
  227. package/docs/aw-table-col.md +0 -33
  228. package/docs/aw-table-head.md +0 -28
  229. package/docs/aw-table-row.md +0 -33
  230. package/docs/aw-table.md +0 -59
  231. package/docs/aw-tel.md +0 -47
  232. package/docs/aw-textarea.md +0 -47
  233. package/docs/aw-timeline-builder.md +0 -50
  234. package/docs/aw-toggler.md +0 -41
  235. package/docs/aw-uploader-files.md +0 -20
  236. package/docs/aw-uploader.md +0 -60
  237. package/docs/aw-user-menu.md +0 -34
  238. package/docs/aw-userpic.md +0 -34
  239. /package/components/{3_organisms → 2_molecules}/AwTel.vue +0 -0
@@ -0,0 +1,852 @@
1
+ # Data Fetching Guide
2
+
3
+ Complete guide to fetching data from your Laravel backend using vue-mc collections and models.
4
+
5
+ ## Overview
6
+
7
+ The AwesCode UI framework uses **vue-mc** for data management, which provides:
8
+ - **Collections** - For lists of items with pagination
9
+ - **Models** - For single resources
10
+ - **Automatic API communication** - Built-in axios integration
11
+ - **Validation** - Client and server-side validation
12
+ - **Lifecycle hooks** - Before/after fetch, save, delete
13
+
14
+ ## Collection Auto-Fetching with AwTableBuilder
15
+
16
+ ### The Simple Way
17
+
18
+ AwTableBuilder automatically fetches collection data - no manual fetching needed!
19
+
20
+ ```markup
21
+ <template>
22
+ <AwPage title="Customers">
23
+ <AwTableBuilder :collection="customers">
24
+ <AwTableCol field="name" title="Name" />
25
+ <AwTableCol field="email" title="Email" />
26
+ </AwTableBuilder>
27
+ </AwPage>
28
+ </template>
29
+
30
+ <script>
31
+ import Customers from '~/collections/Customers'
32
+
33
+ export default {
34
+ data() {
35
+ return {
36
+ customers: new Customers([], {
37
+ shop_uuid: this.$route.params.shop_uuid
38
+ })
39
+ }
40
+ }
41
+ // No fetch() or mounted() needed!
42
+ }
43
+ </script>
44
+ ```
45
+
46
+ **What happens:**
47
+ 1. ✅ AwTableBuilder mounts
48
+ 2. ✅ Automatically calls `customers.fetch()`
49
+ 3. ✅ Shows loading state
50
+ 4. ✅ Displays data when loaded
51
+ 5. ✅ Handles pagination automatically
52
+
53
+ ### ⚠️ Important: Don't Use v-if for Loading
54
+
55
+ ```markup
56
+ <!-- ❌ BAD - Prevents AwTableBuilder from mounting -->
57
+ <template>
58
+ <AwPage title="Customers">
59
+ <div v-if="loading">Loading...</div>
60
+ <AwTableBuilder v-else :collection="customers">
61
+ <!-- Never mounts if loading=true initially -->
62
+ </AwTableBuilder>
63
+ </AwPage>
64
+ </template>
65
+
66
+ <!-- ✅ GOOD - Let AwTableBuilder handle loading -->
67
+ <template>
68
+ <AwPage title="Customers">
69
+ <AwTableBuilder :collection="customers">
70
+ <!-- Mounts immediately, shows internal loading state -->
71
+ </AwTableBuilder>
72
+ </AwPage>
73
+ </template>
74
+ ```
75
+
76
+ ### With Search Parameters
77
+
78
+ AwTableBuilder watches for route query changes:
79
+
80
+ ```markup
81
+ <template>
82
+ <AwPage title="Customers">
83
+ <div class="flex justify-end mb-6">
84
+ <AwSearch class="w-full lg:w-auto" />
85
+ </div>
86
+
87
+ <AwTableBuilder
88
+ :collection="customers"
89
+ :watch-params="['search']"
90
+ >
91
+ <AwTableCol field="name" title="Name" />
92
+ </AwTableBuilder>
93
+ </AwPage>
94
+ </template>
95
+ ```
96
+
97
+ **How it works:**
98
+ 1. User types in AwSearch
99
+ 2. Updates `$route.query.search`
100
+ 3. AwTableBuilder detects change
101
+ 4. Automatically refetches collection
102
+
103
+ ### With Filter Options
104
+
105
+ Pass additional options to collection:
106
+
107
+ ```markup
108
+ <template>
109
+ <AwPage title="Orders">
110
+ <AwSelect
111
+ v-model="statusFilter"
112
+ :options="['all', 'pending', 'completed']"
113
+ label="Status"
114
+ />
115
+
116
+ <AwTableBuilder
117
+ :collection="orders"
118
+ :options="filterOptions"
119
+ >
120
+ <AwTableCol field="id" title="Order #" />
121
+ </AwTableBuilder>
122
+ </AwPage>
123
+ </template>
124
+
125
+ <script>
126
+ export default {
127
+ data() {
128
+ return {
129
+ statusFilter: 'all'
130
+ }
131
+ },
132
+
133
+ computed: {
134
+ filterOptions() {
135
+ return {
136
+ shop_uuid: this.$route.params.shop_uuid,
137
+ status: this.statusFilter !== 'all' ? this.statusFilter : undefined
138
+ }
139
+ }
140
+ },
141
+
142
+ watch: {
143
+ filterOptions: {
144
+ handler() {
145
+ this.orders.fetch()
146
+ },
147
+ deep: true
148
+ }
149
+ }
150
+ }
151
+ </script>
152
+ ```
153
+
154
+ ## Manual Collection Fetching
155
+
156
+ ### Basic Manual Fetch
157
+
158
+ For cases where you need manual control:
159
+
160
+ ```markup
161
+ <template>
162
+ <AwPage title="Analytics">
163
+ <AwContentPlaceholder v-if="loading" type="text" :lines="6" />
164
+
165
+ <div v-else>
166
+ <div v-for="item in analytics.models" :key="item.id">
167
+ {{ item.name }}
168
+ </div>
169
+ </div>
170
+ </AwPage>
171
+ </template>
172
+
173
+ <script>
174
+ import Analytics from '~/collections/Analytics'
175
+
176
+ export default {
177
+ data() {
178
+ return {
179
+ analytics: new Analytics([], {
180
+ shop_uuid: this.$route.params.shop_uuid
181
+ }),
182
+ loading: true
183
+ }
184
+ },
185
+
186
+ async mounted() {
187
+ await this.loadAnalytics()
188
+ },
189
+
190
+ methods: {
191
+ async loadAnalytics() {
192
+ this.loading = true
193
+ try {
194
+ await this.analytics.fetch()
195
+ } catch (error) {
196
+ this.$notify({
197
+ message: 'Failed to load analytics',
198
+ type: 'error'
199
+ })
200
+ } finally {
201
+ this.loading = false
202
+ }
203
+ }
204
+ }
205
+ }
206
+ </script>
207
+ ```
208
+
209
+ ### With Parameters
210
+
211
+ Pass query parameters to fetch:
212
+
213
+ ```javascript
214
+ async loadData() {
215
+ await this.collection.fetch({
216
+ params: {
217
+ start_date: this.dateRange.start,
218
+ end_date: this.dateRange.end,
219
+ category: this.selectedCategory
220
+ }
221
+ })
222
+ }
223
+ ```
224
+
225
+ ### Refetching After Changes
226
+
227
+ Refetch collection after mutations:
228
+
229
+ ```javascript
230
+ async deleteItem(item) {
231
+ const confirmed = await this.$confirm({
232
+ title: 'Delete Item',
233
+ message: 'Are you sure?'
234
+ })
235
+
236
+ if (!confirmed) return
237
+
238
+ try {
239
+ await this.$axios.delete(`/api/items/${item.id}`)
240
+ this.$notify({
241
+ message: 'Item deleted',
242
+ type: 'success'
243
+ })
244
+
245
+ // Refetch collection
246
+ await this.items.fetch()
247
+ } catch (error) {
248
+ this.$notify({
249
+ message: 'Failed to delete item',
250
+ type: 'error'
251
+ })
252
+ }
253
+ }
254
+ ```
255
+
256
+ ## Model Fetching
257
+
258
+ ### Fetch Existing Model
259
+
260
+ Load data for existing record:
261
+
262
+ ```markup
263
+ <script>
264
+ import Customer from '~/models/Customer'
265
+
266
+ export default {
267
+ data() {
268
+ return {
269
+ customer: new Customer(
270
+ { id: this.$route.params.id },
271
+ null,
272
+ { shop_uuid: this.$route.params.shop_uuid }
273
+ ),
274
+ loading: true
275
+ }
276
+ },
277
+
278
+ async mounted() {
279
+ if (!this.customer.isNew()) {
280
+ try {
281
+ await this.customer.fetch()
282
+ } catch (error) {
283
+ // Handle 404
284
+ if (error.response?.status === 404) {
285
+ this.$notify({
286
+ message: 'Customer not found',
287
+ type: 'error'
288
+ })
289
+ this.$router.push('/customers')
290
+ return
291
+ }
292
+
293
+ // Other errors
294
+ this.$notify({
295
+ message: 'Failed to load customer',
296
+ type: 'error'
297
+ })
298
+ } finally {
299
+ this.loading = false
300
+ }
301
+ } else {
302
+ this.loading = false
303
+ }
304
+ }
305
+ }
306
+ </script>
307
+ ```
308
+
309
+ ### Conditional Fetching
310
+
311
+ Only fetch if not creating new:
312
+
313
+ ```javascript
314
+ async mounted() {
315
+ const uuid = this.$route.params.uuid
316
+
317
+ if (uuid !== 'new') {
318
+ this.loading = true
319
+ try {
320
+ await this.model.fetch()
321
+ } catch (error) {
322
+ this.$notify({
323
+ message: 'Record not found',
324
+ type: 'error'
325
+ })
326
+ this.$router.push('/list')
327
+ } finally {
328
+ this.loading = false
329
+ }
330
+ }
331
+ }
332
+ ```
333
+
334
+ ## AwSelect Async Loading
335
+
336
+ ### Function Returns URL
337
+
338
+ For dropdowns with many options, use async loading:
339
+
340
+ ```markup
341
+ <template>
342
+ <AwSelect
343
+ v-model="product.category_id"
344
+ :options="loadCategories"
345
+ option-label="name"
346
+ track-by="id"
347
+ label="Category"
348
+ />
349
+ </template>
350
+
351
+ <script>
352
+ export default {
353
+ methods: {
354
+ // Return URL string for AwSelect to fetch from
355
+ loadCategories(search) {
356
+ const shopUuid = this.$route.params.shop_uuid
357
+ return `/api/shops/${shopUuid}/categories?search=${search}`
358
+ }
359
+ }
360
+ }
361
+ </script>
362
+ ```
363
+
364
+ **How it works:**
365
+ 1. ✅ Pass **function** to `:options` (not array)
366
+ 2. ✅ Function receives `search` parameter
367
+ 3. ✅ Returns URL string
368
+ 4. ✅ AwSelect makes GET request automatically
369
+ 5. ✅ Autocomplete behavior as user types
370
+
371
+ ### With Custom Label Formatting
372
+
373
+ ```markup
374
+ <AwSelect
375
+ v-model="campaign.template_key"
376
+ :options="loadTemplates"
377
+ :option-label="formatTemplateLabel"
378
+ track-by="template_key"
379
+ label="Template"
380
+ />
381
+
382
+ <script>
383
+ export default {
384
+ methods: {
385
+ loadTemplates(search) {
386
+ return `/api/templates?search=${search}`
387
+ },
388
+
389
+ formatTemplateLabel(template) {
390
+ return `${template.name} (${template.channel})`
391
+ }
392
+ }
393
+ }
394
+ </script>
395
+ ```
396
+
397
+ ## Pagination
398
+
399
+ ### Automatic with AwTableBuilder
400
+
401
+ AwTableBuilder handles pagination automatically:
402
+
403
+ ```markup
404
+ <AwTableBuilder :collection="customers">
405
+ <AwTableCol field="name" title="Name" />
406
+ </AwTableBuilder>
407
+ ```
408
+
409
+ Collection response should include pagination meta:
410
+
411
+ ```json
412
+ {
413
+ "data": [...],
414
+ "meta": {
415
+ "current_page": 1,
416
+ "last_page": 10,
417
+ "per_page": 15,
418
+ "total": 145
419
+ }
420
+ }
421
+ ```
422
+
423
+ ### Manual Pagination
424
+
425
+ Use AwPagination component:
426
+
427
+ ```markup
428
+ <template>
429
+ <div>
430
+ <div v-for="item in items.models" :key="item.id">
431
+ {{ item.name }}
432
+ </div>
433
+
434
+ <AwPagination
435
+ v-model="page"
436
+ :total-pages="totalPages"
437
+ @input="loadPage"
438
+ />
439
+ </div>
440
+ </template>
441
+
442
+ <script>
443
+ export default {
444
+ data() {
445
+ return {
446
+ page: 1,
447
+ totalPages: 1
448
+ }
449
+ },
450
+
451
+ methods: {
452
+ async loadPage(page) {
453
+ await this.items.fetch({
454
+ params: { page }
455
+ })
456
+
457
+ // Update total pages from response
458
+ this.totalPages = this.items.response?.meta?.last_page || 1
459
+ }
460
+ }
461
+ }
462
+ </script>
463
+ ```
464
+
465
+ ## Error Handling
466
+
467
+ ### Collection Fetch Errors
468
+
469
+ ```javascript
470
+ async loadData() {
471
+ try {
472
+ await this.collection.fetch()
473
+ } catch (error) {
474
+ console.error('Fetch failed:', error)
475
+
476
+ // Network error
477
+ if (!error.response) {
478
+ this.$notify({
479
+ message: 'Network error. Please check your connection.',
480
+ type: 'error'
481
+ })
482
+ return
483
+ }
484
+
485
+ // 404 - Not found
486
+ if (error.response.status === 404) {
487
+ this.$notify({
488
+ message: 'Resource not found',
489
+ type: 'error'
490
+ })
491
+ this.$router.push('/dashboard')
492
+ return
493
+ }
494
+
495
+ // 403 - Forbidden
496
+ if (error.response.status === 403) {
497
+ this.$notify({
498
+ message: 'You do not have permission to view this',
499
+ type: 'error'
500
+ })
501
+ return
502
+ }
503
+
504
+ // Generic error
505
+ this.$notify({
506
+ message: 'Failed to load data',
507
+ type: 'error'
508
+ })
509
+ }
510
+ }
511
+ ```
512
+
513
+ ### Model Fetch Errors
514
+
515
+ ```javascript
516
+ async mounted() {
517
+ if (!this.model.isNew()) {
518
+ try {
519
+ await this.model.fetch()
520
+ } catch (error) {
521
+ if (error.response?.status === 404) {
522
+ this.$notify({
523
+ message: 'Record not found',
524
+ type: 'error'
525
+ })
526
+ this.$router.push('/list')
527
+ } else {
528
+ this.$notify({
529
+ message: 'Failed to load record',
530
+ type: 'error'
531
+ })
532
+ }
533
+ }
534
+ }
535
+ }
536
+ ```
537
+
538
+ ## Caching
539
+
540
+ ### Simple Cache
541
+
542
+ Cache data to avoid unnecessary requests:
543
+
544
+ ```javascript
545
+ export default {
546
+ data() {
547
+ return {
548
+ cachedData: null
549
+ }
550
+ },
551
+
552
+ methods: {
553
+ async loadData() {
554
+ // Return cached data if available
555
+ if (this.cachedData) {
556
+ return this.cachedData
557
+ }
558
+
559
+ // Fetch and cache
560
+ const { data } = await this.$axios.get('/api/data')
561
+ this.cachedData = data
562
+ return data
563
+ }
564
+ }
565
+ }
566
+ ```
567
+
568
+ ### Vuex Store Cache
569
+
570
+ ```javascript
571
+ // store/customers.js
572
+ export const state = () => ({
573
+ customers: [],
574
+ loaded: false
575
+ })
576
+
577
+ export const actions = {
578
+ async fetch({ commit, state }) {
579
+ // Return cached if already loaded
580
+ if (state.loaded) {
581
+ return state.customers
582
+ }
583
+
584
+ const { data } = await this.$axios.get('/api/customers')
585
+ commit('SET_CUSTOMERS', data)
586
+ commit('SET_LOADED', true)
587
+ return data
588
+ }
589
+ }
590
+
591
+ export const mutations = {
592
+ SET_CUSTOMERS(state, customers) {
593
+ state.customers = customers
594
+ },
595
+ SET_LOADED(state, loaded) {
596
+ state.loaded = loaded
597
+ }
598
+ }
599
+ ```
600
+
601
+ ## Polling for Updates
602
+
603
+ ### Interval Polling
604
+
605
+ ```markup
606
+ <script>
607
+ export default {
608
+ data() {
609
+ return {
610
+ pollingInterval: null
611
+ }
612
+ },
613
+
614
+ mounted() {
615
+ // Initial fetch
616
+ this.loadData()
617
+
618
+ // Poll every 30 seconds
619
+ this.pollingInterval = setInterval(() => {
620
+ this.loadData()
621
+ }, 30000)
622
+ },
623
+
624
+ beforeDestroy() {
625
+ // Clean up interval
626
+ if (this.pollingInterval) {
627
+ clearInterval(this.pollingInterval)
628
+ }
629
+ },
630
+
631
+ methods: {
632
+ async loadData() {
633
+ await this.collection.fetch()
634
+ }
635
+ }
636
+ }
637
+ </script>
638
+ ```
639
+
640
+ ### Conditional Polling
641
+
642
+ Only poll when page is visible:
643
+
644
+ ```javascript
645
+ mounted() {
646
+ // Start polling
647
+ this.startPolling()
648
+
649
+ // Stop polling when page hidden
650
+ document.addEventListener('visibilitychange', this.handleVisibilityChange)
651
+ },
652
+
653
+ beforeDestroy() {
654
+ this.stopPolling()
655
+ document.removeEventListener('visibilitychange', this.handleVisibilityChange)
656
+ },
657
+
658
+ methods: {
659
+ startPolling() {
660
+ this.loadData()
661
+ this.pollingInterval = setInterval(() => {
662
+ if (!document.hidden) {
663
+ this.loadData()
664
+ }
665
+ }, 30000)
666
+ },
667
+
668
+ stopPolling() {
669
+ if (this.pollingInterval) {
670
+ clearInterval(this.pollingInterval)
671
+ }
672
+ },
673
+
674
+ handleVisibilityChange() {
675
+ if (document.hidden) {
676
+ this.stopPolling()
677
+ } else {
678
+ this.startPolling()
679
+ }
680
+ }
681
+ }
682
+ ```
683
+
684
+ ## Loading States
685
+
686
+ ### Collection Loading
687
+
688
+ Vue-mc collections provide `loading` state. Use `AwContentPlaceholder` for better UX:
689
+
690
+ ```markup
691
+ <template>
692
+ <div>
693
+ <AwContentPlaceholder v-if="customers.loading" type="text" :lines="8" />
694
+
695
+ <div v-else>
696
+ <div v-for="customer in customers.models" :key="customer.id">
697
+ {{ customer.name }}
698
+ </div>
699
+ </div>
700
+ </div>
701
+ </template>
702
+ ```
703
+
704
+ ### Model Loading
705
+
706
+ Models provide `fetching` state. Use form placeholder for form data. When using `AwCard`, place the placeholder inside the card to replace the content:
707
+
708
+ ```markup
709
+ <template>
710
+ <AwCard title="Customer Details">
711
+ <AwContentPlaceholder v-if="customer.fetching" type="form" :lines="6" />
712
+
713
+ <AwGrid v-else>
714
+ <!-- Customer data -->
715
+ </AwGrid>
716
+ </AwCard>
717
+ </template>
718
+ ```
719
+
720
+ ### Complex Content Loading
721
+
722
+ For pages with mixed content types, use multiple placeholders:
723
+
724
+ ```markup
725
+ <template>
726
+ <div v-if="loading">
727
+ <AwGrid :col="{ md: 2 }">
728
+ <AwContentPlaceholder type="image" />
729
+ <AwContentPlaceholder type="text" :lines="6" />
730
+ </AwGrid>
731
+ <AwFlow class="mt-4">
732
+ <AwContentPlaceholder type="avatar" />
733
+ <AwContentPlaceholder type="text" :lines="3" />
734
+ </AwFlow>
735
+ </div>
736
+
737
+ <div v-else>
738
+ <!-- Actual content -->
739
+ </div>
740
+ </template>
741
+ ```
742
+
743
+ ### Custom Loading Flag
744
+
745
+ For manual control:
746
+
747
+ ```markup
748
+ <template>
749
+ <AwContentPlaceholder v-if="loading" type="form" :lines="4" />
750
+
751
+ <AwForm v-else url="/api/submit">
752
+ <!-- Form fields -->
753
+ </AwForm>
754
+ </template>
755
+
756
+ <script>
757
+ export default {
758
+ data() {
759
+ return {
760
+ loading: false
761
+ }
762
+ },
763
+
764
+ methods: {
765
+ async loadData() {
766
+ this.loading = true
767
+ try {
768
+ await this.collection.fetch()
769
+ } finally {
770
+ this.loading = false
771
+ }
772
+ }
773
+ }
774
+ }
775
+ </script>
776
+ ```
777
+
778
+ ## Best Practices
779
+
780
+ ### 1. Use AwTableBuilder Auto-Fetch
781
+
782
+ ```markup
783
+ <!-- ✅ GOOD - Let AwTableBuilder fetch -->
784
+ <AwTableBuilder :collection="customers" />
785
+
786
+ <!-- ❌ BAD - Manual fetch not needed -->
787
+ <script>
788
+ async mounted() {
789
+ await this.customers.fetch() // Unnecessary!
790
+ }
791
+ </script>
792
+ ```
793
+
794
+ ### 2. Always Include shop_uuid
795
+
796
+ ```javascript
797
+ // ✅ GOOD
798
+ customers: new Customers([], {
799
+ shop_uuid: this.$route.params.shop_uuid
800
+ })
801
+
802
+ // ❌ BAD
803
+ customers: new Customers([])
804
+ ```
805
+
806
+ ### 3. Handle Errors
807
+
808
+ ```javascript
809
+ // ✅ GOOD
810
+ try {
811
+ await this.model.fetch()
812
+ } catch (error) {
813
+ this.$notify({
814
+ message: 'Failed to load',
815
+ type: 'error'
816
+ })
817
+ }
818
+
819
+ // ❌ BAD
820
+ await this.model.fetch() // No error handling
821
+ ```
822
+
823
+ ### 4. Check isNew() Before Fetching
824
+
825
+ ```javascript
826
+ // ✅ GOOD
827
+ if (!this.model.isNew()) {
828
+ await this.model.fetch()
829
+ }
830
+
831
+ // ❌ BAD
832
+ await this.model.fetch() // Fails if new model
833
+ ```
834
+
835
+ ### 5. Clean Up Intervals
836
+
837
+ ```javascript
838
+ // ✅ GOOD
839
+ beforeDestroy() {
840
+ clearInterval(this.pollingInterval)
841
+ }
842
+
843
+ // ❌ BAD
844
+ // No cleanup - memory leak
845
+ ```
846
+
847
+ ## See Also
848
+
849
+ - [Best Practices Guide](./best-practices.md) - Data management patterns
850
+ - [Error Handling Guide](./error-handling.md) - Error handling strategies
851
+ - [List Pages Guide](./page-patterns/list-pages.md) - List page patterns
852
+ - [Vue-MC Documentation](../../vue-mc/docs/) - Complete vue-mc API