df-ae-forms-package 1.0.0 → 1.0.2

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.
@@ -0,0 +1,783 @@
1
+ # DF AE Forms Package - Integration Guide for Ionic/Angular
2
+
3
+ This guide provides step-by-step instructions for integrating the `df-ae-forms-package` into your Ionic/Angular application.
4
+
5
+ ## Table of Contents
6
+
7
+ 1. [Prerequisites](#prerequisites)
8
+ 2. [Installation](#installation)
9
+ 3. [Basic Setup](#basic-setup)
10
+ 4. [React Bridge Setup](#react-bridge-setup)
11
+ 5. [Using the Component](#using-the-component)
12
+ 6. [Styling](#styling)
13
+ 7. [Form Data Handling](#form-data-handling)
14
+ 8. [Common Issues and Solutions](#common-issues-and-solutions)
15
+ 9. [Complete Example](#complete-example)
16
+
17
+ ## Prerequisites
18
+
19
+ - Angular 12+ application
20
+ - Ionic 6+ application
21
+ - Node.js 14+ and npm 6+
22
+
23
+ ## Installation
24
+
25
+ ### 1. Install the Package
26
+
27
+ ```bash
28
+ npm install df-ae-forms-package
29
+ ```
30
+
31
+ ### 2. Install Peer Dependencies
32
+
33
+ ```bash
34
+ npm install react react-dom lucide-react @dnd-kit/core @dnd-kit/sortable @dnd-kit/utilities
35
+ ```
36
+
37
+ ### 3. Install React Bridge for Angular
38
+
39
+ ```bash
40
+ npm install @angular-react/react
41
+ ```
42
+
43
+ ## Basic Setup
44
+
45
+ ### 1. Import Styles
46
+
47
+ In your `src/global.scss` or `src/styles.scss` file, import the package styles:
48
+
49
+ ```scss
50
+ // Import DF Forms Package styles
51
+ @import '~df-ae-forms-package/dist/index.css';
52
+ ```
53
+
54
+ **Important**: The CSS file contains all the design system variables and component styles. Make sure this import is at the top of your global styles file.
55
+
56
+ ### 2. Ensure CSS Variables are Available
57
+
58
+ The package uses CSS variables for theming. These are included in the CSS file, but you can override them in your application:
59
+
60
+ ```scss
61
+ :root {
62
+ // Override package variables if needed
63
+ --df-color-primary: #303992;
64
+ --df-color-secondary: #ff7032;
65
+ --df-color-error-primary: #f04248;
66
+ // ... other variables
67
+ }
68
+ ```
69
+
70
+ ## React Bridge Setup
71
+
72
+ Since this is a React component and you're using Angular, you need to set up a React bridge.
73
+
74
+ ### 1. Create a React Wrapper Component
75
+
76
+ Create a new file `src/app/components/react-form-wrapper.tsx`:
77
+
78
+ ```tsx
79
+ import React from 'react';
80
+ import { DfFormPreview, FormComponentType, DeviceType } from 'df-ae-forms-package';
81
+
82
+ interface ReactFormWrapperProps {
83
+ formComponents: FormComponentType[];
84
+ currentDevice?: DeviceType;
85
+ isPreviewMode?: boolean;
86
+ initialFormData?: FormComponentType[];
87
+ formTitle?: string;
88
+ formDescription?: string;
89
+ formTemplateId?: string;
90
+ onSubmit?: (formData: FormComponentType[]) => void;
91
+ onFormDataChange?: (formData: FormComponentType[]) => void;
92
+ }
93
+
94
+ export const ReactFormWrapper: React.FC<ReactFormWrapperProps> = (props) => {
95
+ return <DfFormPreview {...props} />;
96
+ };
97
+ ```
98
+
99
+ ### 2. Create Angular Component Wrapper
100
+
101
+ Create `src/app/components/form-preview.component.ts`:
102
+
103
+ ```typescript
104
+ import { Component, Input, Output, EventEmitter, OnInit, OnDestroy, ViewChild, ElementRef } from '@angular/core';
105
+ import { createRoot, Root } from 'react-dom/client';
106
+ import * as React from 'react';
107
+ import { ReactFormWrapper } from './react-form-wrapper';
108
+ import { FormComponentType, DeviceType } from 'df-ae-forms-package';
109
+
110
+ @Component({
111
+ selector: 'app-form-preview',
112
+ template: '<div #reactContainer></div>',
113
+ styles: [`
114
+ :host {
115
+ display: block;
116
+ width: 100%;
117
+ height: 100%;
118
+ }
119
+ `]
120
+ })
121
+ export class FormPreviewComponent implements OnInit, OnDestroy {
122
+ @ViewChild('reactContainer', { static: true }) containerRef!: ElementRef;
123
+
124
+ @Input() formComponents: FormComponentType[] = [];
125
+ @Input() currentDevice: DeviceType = 'desktop';
126
+ @Input() isPreviewMode: boolean = false;
127
+ @Input() initialFormData: FormComponentType[] = [];
128
+ @Input() formTitle?: string;
129
+ @Input() formDescription?: string;
130
+ @Input() formTemplateId?: string;
131
+
132
+ @Output() formSubmit = new EventEmitter<FormComponentType[]>();
133
+ @Output() formDataChange = new EventEmitter<FormComponentType[]>();
134
+
135
+ private root: Root | null = null;
136
+
137
+ ngOnInit() {
138
+ this.renderReactComponent();
139
+ }
140
+
141
+ ngOnDestroy() {
142
+ if (this.root) {
143
+ this.root.unmount();
144
+ }
145
+ }
146
+
147
+ private renderReactComponent() {
148
+ if (!this.root) {
149
+ this.root = createRoot(this.containerRef.nativeElement);
150
+ }
151
+
152
+ this.root.render(
153
+ React.createElement(ReactFormWrapper, {
154
+ formComponents: this.formComponents,
155
+ currentDevice: this.currentDevice,
156
+ isPreviewMode: this.isPreviewMode,
157
+ initialFormData: this.initialFormData,
158
+ formTitle: this.formTitle,
159
+ formDescription: this.formDescription,
160
+ formTemplateId: this.formTemplateId,
161
+ onSubmit: (formData: FormComponentType[]) => {
162
+ this.formSubmit.emit(formData);
163
+ },
164
+ onFormDataChange: (formData: FormComponentType[]) => {
165
+ this.formDataChange.emit(formData);
166
+ }
167
+ })
168
+ );
169
+ }
170
+
171
+ ngOnChanges() {
172
+ if (this.root) {
173
+ this.renderReactComponent();
174
+ }
175
+ }
176
+ }
177
+ ```
178
+
179
+ ### 3. Alternative: Using @angular-react/react
180
+
181
+ If you prefer using the `@angular-react/react` package:
182
+
183
+ ```typescript
184
+ import { Component, Input, Output, EventEmitter } from '@angular/core';
185
+ import { ReactComponent } from '@angular-react/react';
186
+ import { DfFormPreview, FormComponentType, DeviceType } from 'df-ae-forms-package';
187
+
188
+ @Component({
189
+ selector: 'app-form-preview',
190
+ template: `
191
+ <react-component
192
+ [component]="DfFormPreview"
193
+ [props]="formProps"
194
+ ></react-component>
195
+ `
196
+ })
197
+ export class FormPreviewComponent {
198
+ DfFormPreview = DfFormPreview;
199
+
200
+ @Input() formComponents: FormComponentType[] = [];
201
+ @Input() currentDevice: DeviceType = 'desktop';
202
+ @Input() isPreviewMode: boolean = false;
203
+ // ... other inputs
204
+
205
+ @Output() formSubmit = new EventEmitter<FormComponentType[]>();
206
+ @Output() formDataChange = new EventEmitter<FormComponentType[]>();
207
+
208
+ get formProps() {
209
+ return {
210
+ formComponents: this.formComponents,
211
+ currentDevice: this.currentDevice,
212
+ isPreviewMode: this.isPreviewMode,
213
+ onSubmit: (formData: FormComponentType[]) => this.formSubmit.emit(formData),
214
+ onFormDataChange: (formData: FormComponentType[]) => this.formDataChange.emit(formData)
215
+ };
216
+ }
217
+ }
218
+ ```
219
+
220
+ ## Using the Component
221
+
222
+ ### 1. In Your Angular Component
223
+
224
+ ```typescript
225
+ import { Component, OnInit } from '@angular/core';
226
+ import { FormComponentType } from 'df-ae-forms-package';
227
+ import { FormService } from './services/form.service'; // Your service
228
+
229
+ @Component({
230
+ selector: 'app-form-list',
231
+ template: `
232
+ <ion-content>
233
+ <ion-list>
234
+ <ion-item *ngFor="let form of forms" (click)="openForm(form)">
235
+ <ion-label>{{ form.title }}</ion-label>
236
+ </ion-item>
237
+ </ion-list>
238
+ </ion-content>
239
+ `
240
+ })
241
+ export class FormListPage implements OnInit {
242
+ forms: any[] = [];
243
+
244
+ constructor(private formService: FormService) {}
245
+
246
+ ngOnInit() {
247
+ this.loadForms();
248
+ }
249
+
250
+ loadForms() {
251
+ this.formService.getForms().subscribe(forms => {
252
+ this.forms = forms;
253
+ });
254
+ }
255
+
256
+ openForm(form: any) {
257
+ // Navigate to form preview page
258
+ this.router.navigate(['/form-preview', form.id]);
259
+ }
260
+ }
261
+ ```
262
+
263
+ ### 2. Form Preview Page
264
+
265
+ ```typescript
266
+ import { Component, OnInit } from '@angular/core';
267
+ import { ActivatedRoute } from '@angular/router';
268
+ import { FormComponentType } from 'df-ae-forms-package';
269
+ import { FormService } from './services/form.service';
270
+
271
+ @Component({
272
+ selector: 'app-form-preview',
273
+ template: `
274
+ <ion-header>
275
+ <ion-toolbar>
276
+ <ion-title>{{ formTitle }}</ion-title>
277
+ </ion-toolbar>
278
+ </ion-header>
279
+ <ion-content>
280
+ <app-form-preview
281
+ [formComponents]="formComponents"
282
+ [currentDevice]="currentDevice"
283
+ [isPreviewMode]="false"
284
+ [formTitle]="formTitle"
285
+ [formDescription]="formDescription"
286
+ [formTemplateId]="formTemplateId"
287
+ (formSubmit)="handleFormSubmit($event)"
288
+ (formDataChange)="handleFormDataChange($event)"
289
+ ></app-form-preview>
290
+ </ion-content>
291
+ `
292
+ })
293
+ export class FormPreviewPage implements OnInit {
294
+ formComponents: FormComponentType[] = [];
295
+ formTitle: string = '';
296
+ formDescription: string = '';
297
+ formTemplateId: string = '';
298
+ currentDevice: 'desktop' | 'tablet' | 'mobile' = 'desktop';
299
+
300
+ constructor(
301
+ private route: ActivatedRoute,
302
+ private formService: FormService
303
+ ) {}
304
+
305
+ ngOnInit() {
306
+ const formId = this.route.snapshot.paramMap.get('id');
307
+ if (formId) {
308
+ this.loadForm(formId);
309
+ }
310
+ }
311
+
312
+ loadForm(formId: string) {
313
+ this.formService.getFormById(formId).subscribe(form => {
314
+ // Assuming your API returns form data in the correct format
315
+ this.formComponents = form.components || [];
316
+ this.formTitle = form.title || '';
317
+ this.formDescription = form.description || '';
318
+ this.formTemplateId = form.id || '';
319
+ });
320
+ }
321
+
322
+ handleFormSubmit(formData: FormComponentType[]) {
323
+ // Handle form submission
324
+ this.formService.submitForm(this.formTemplateId, formData).subscribe(
325
+ response => {
326
+ console.log('Form submitted successfully', response);
327
+ // Show success message, navigate, etc.
328
+ },
329
+ error => {
330
+ console.error('Form submission failed', error);
331
+ // Show error message
332
+ }
333
+ );
334
+ }
335
+
336
+ handleFormDataChange(formData: FormComponentType[]) {
337
+ // Handle form data changes (for auto-save, etc.)
338
+ console.log('Form data changed', formData);
339
+ }
340
+ }
341
+ ```
342
+
343
+ ## Styling
344
+
345
+ ### 1. Ensure Styles are Loaded
346
+
347
+ Make sure the CSS is imported in your global styles:
348
+
349
+ ```scss
350
+ // src/global.scss
351
+ @import '~df-ae-forms-package/dist/index.css';
352
+ ```
353
+
354
+ ### 2. Override CSS Variables (Optional)
355
+
356
+ ```scss
357
+ :root {
358
+ --df-color-primary: #303992;
359
+ --df-color-secondary: #ff7032;
360
+ --df-color-error-primary: #f04248;
361
+ --df-color-text-dark: #000000;
362
+ --df-color-text-light: #8c8c8c;
363
+ --df-color-fb-container: #ffffff;
364
+ --df-color-fb-border: #e4e5ec;
365
+ --df-color-fb-bg: #f4f4f4;
366
+ }
367
+ ```
368
+
369
+ ### 3. Dark Mode Support
370
+
371
+ The package supports dark mode. Add the `dark` class to your root element:
372
+
373
+ ```typescript
374
+ // In your app.component.ts
375
+ export class AppComponent {
376
+ isDarkMode = false;
377
+
378
+ toggleDarkMode() {
379
+ this.isDarkMode = !this.isDarkMode;
380
+ document.body.classList.toggle('dark', this.isDarkMode);
381
+ }
382
+ }
383
+ ```
384
+
385
+ ## Form Data Handling
386
+
387
+ ### 1. Loading Form Data from API
388
+
389
+ ```typescript
390
+ // form.service.ts
391
+ import { Injectable } from '@angular/core';
392
+ import { HttpClient } from '@angular/common/http';
393
+ import { Observable } from 'rxjs';
394
+ import { FormComponentType } from 'df-ae-forms-package';
395
+
396
+ @Injectable({
397
+ providedIn: 'root'
398
+ })
399
+ export class FormService {
400
+ private apiUrl = 'https://your-api.com/api';
401
+
402
+ constructor(private http: HttpClient) {}
403
+
404
+ getForms(): Observable<any[]> {
405
+ return this.http.get<any[]>(`${this.apiUrl}/forms`);
406
+ }
407
+
408
+ getFormById(id: string): Observable<any> {
409
+ return this.http.get<any>(`${this.apiUrl}/forms/${id}`);
410
+ }
411
+
412
+ submitForm(formId: string, formData: FormComponentType[]): Observable<any> {
413
+ return this.http.post(`${this.apiUrl}/forms/${formId}/submit`, {
414
+ components: formData
415
+ });
416
+ }
417
+ }
418
+ ```
419
+
420
+ ### 2. Form Data Format
421
+
422
+ The form components expect data in this format:
423
+
424
+ ```typescript
425
+ const formComponents: FormComponentType[] = [
426
+ {
427
+ id: 'field-1',
428
+ name: 'text-input',
429
+ basic: {
430
+ label: 'Full Name',
431
+ placeholder: 'Enter your full name',
432
+ defaultValue: ''
433
+ },
434
+ validation: {
435
+ required: true,
436
+ minLength: 2,
437
+ maxLength: 50
438
+ },
439
+ styles: {
440
+ column: 12,
441
+ labelAlignment: 'top'
442
+ }
443
+ },
444
+ {
445
+ id: 'field-2',
446
+ name: 'email-input',
447
+ basic: {
448
+ label: 'Email Address',
449
+ placeholder: 'Enter your email',
450
+ defaultValue: ''
451
+ },
452
+ validation: {
453
+ required: true
454
+ }
455
+ }
456
+ ];
457
+ ```
458
+
459
+ ## Common Issues and Solutions
460
+
461
+ ### Issue 1: Styles Not Working
462
+
463
+ **Problem**: Form components are not styled correctly.
464
+
465
+ **Solutions**:
466
+ 1. Ensure CSS is imported: `@import '~df-ae-forms-package/dist/index.css';`
467
+ 2. Check that CSS variables are defined
468
+ 3. Verify the build includes the CSS file
469
+ 4. Clear browser cache and rebuild
470
+
471
+ ### Issue 2: Labels Not Showing
472
+
473
+ **Problem**: Form labels are not visible.
474
+
475
+ **Solutions**:
476
+ 1. Verify that `formComponents[].basic.label` is set for each component
477
+ 2. Check that `hideLabel` prop is not set to `true`
478
+ 3. Ensure CSS is properly loaded
479
+ 4. Check browser console for errors
480
+
481
+ ### Issue 3: Components Not Rendering
482
+
483
+ **Problem**: Form components are not appearing.
484
+
485
+ **Solutions**:
486
+ 1. Verify `formComponents` array is not empty
487
+ 2. Check that component IDs are unique
488
+ 3. Ensure conditional logic is not hiding components
489
+ 4. Check browser console for React errors
490
+ 5. Verify React bridge is properly set up
491
+
492
+ ### Issue 4: Validation Not Working
493
+
494
+ **Problem**: Form validation is not functioning.
495
+
496
+ **Solutions**:
497
+ 1. Ensure `isPreviewMode` is set to `false` for test mode
498
+ 2. Check that validation rules are properly defined
499
+ 3. Verify `onFormDataChange` callback is working
500
+ 4. Check that form submission handler is properly connected
501
+
502
+ ### Issue 5: React Bridge Issues
503
+
504
+ **Problem**: React components are not rendering in Angular.
505
+
506
+ **Solutions**:
507
+ 1. Verify `react` and `react-dom` are installed
508
+ 2. Check that React bridge is properly configured
509
+ 3. Ensure `createRoot` is used (React 18+)
510
+ 4. Check for version conflicts between React and Angular
511
+
512
+ ## Complete Example
513
+
514
+ Here's a complete working example:
515
+
516
+ ### 1. Module Setup
517
+
518
+ ```typescript
519
+ // app.module.ts
520
+ import { NgModule } from '@angular/core';
521
+ import { BrowserModule } from '@angular/platform-browser';
522
+ import { HttpClientModule } from '@angular/common/http';
523
+ import { AppRoutingModule } from './app-routing.module';
524
+ import { AppComponent } from './app.component';
525
+ import { FormListPage } from './pages/form-list/form-list.page';
526
+ import { FormPreviewPage } from './pages/form-preview/form-preview.page';
527
+ import { FormPreviewComponent } from './components/form-preview.component';
528
+
529
+ @NgModule({
530
+ declarations: [
531
+ AppComponent,
532
+ FormListPage,
533
+ FormPreviewPage,
534
+ FormPreviewComponent
535
+ ],
536
+ imports: [
537
+ BrowserModule,
538
+ AppRoutingModule,
539
+ HttpClientModule,
540
+ IonicModule.forRoot()
541
+ ],
542
+ providers: [],
543
+ bootstrap: [AppComponent]
544
+ })
545
+ export class AppModule {}
546
+ ```
547
+
548
+ ### 2. Service
549
+
550
+ ```typescript
551
+ // services/form.service.ts
552
+ import { Injectable } from '@angular/core';
553
+ import { HttpClient } from '@angular/common/http';
554
+ import { Observable } from 'rxjs';
555
+ import { map } from 'rxjs/operators';
556
+ import { FormComponentType } from 'df-ae-forms-package';
557
+
558
+ @Injectable({
559
+ providedIn: 'root'
560
+ })
561
+ export class FormService {
562
+ private apiUrl = 'https://your-api.com/api';
563
+
564
+ constructor(private http: HttpClient) {}
565
+
566
+ getForms(): Observable<any[]> {
567
+ return this.http.get<any[]>(`${this.apiUrl}/forms`);
568
+ }
569
+
570
+ getFormById(id: string): Observable<{
571
+ components: FormComponentType[];
572
+ title: string;
573
+ description: string;
574
+ id: string;
575
+ }> {
576
+ return this.http.get<any>(`${this.apiUrl}/forms/${id}`).pipe(
577
+ map(response => ({
578
+ components: response.components || [],
579
+ title: response.title || '',
580
+ description: response.description || '',
581
+ id: response.id || ''
582
+ }))
583
+ );
584
+ }
585
+
586
+ submitForm(formId: string, formData: FormComponentType[]): Observable<any> {
587
+ return this.http.post(`${this.apiUrl}/forms/${formId}/submit`, {
588
+ components: formData,
589
+ submittedAt: new Date().toISOString()
590
+ });
591
+ }
592
+ }
593
+ ```
594
+
595
+ ### 3. Form List Page
596
+
597
+ ```typescript
598
+ // pages/form-list/form-list.page.ts
599
+ import { Component, OnInit } from '@angular/core';
600
+ import { Router } from '@angular/router';
601
+ import { FormService } from '../../services/form.service';
602
+
603
+ @Component({
604
+ selector: 'app-form-list',
605
+ templateUrl: './form-list.page.html',
606
+ styleUrls: ['./form-list.page.scss']
607
+ })
608
+ export class FormListPage implements OnInit {
609
+ forms: any[] = [];
610
+ loading = false;
611
+
612
+ constructor(
613
+ private formService: FormService,
614
+ private router: Router
615
+ ) {}
616
+
617
+ ngOnInit() {
618
+ this.loadForms();
619
+ }
620
+
621
+ loadForms() {
622
+ this.loading = true;
623
+ this.formService.getForms().subscribe(
624
+ forms => {
625
+ this.forms = forms;
626
+ this.loading = false;
627
+ },
628
+ error => {
629
+ console.error('Error loading forms', error);
630
+ this.loading = false;
631
+ }
632
+ );
633
+ }
634
+
635
+ openForm(form: any) {
636
+ this.router.navigate(['/form-preview', form.id]);
637
+ }
638
+ }
639
+ ```
640
+
641
+ ### 4. Form Preview Page
642
+
643
+ ```typescript
644
+ // pages/form-preview/form-preview.page.ts
645
+ import { Component, OnInit } from '@angular/core';
646
+ import { ActivatedRoute, Router } from '@angular/router';
647
+ import { FormComponentType } from 'df-ae-forms-package';
648
+ import { FormService } from '../../services/form.service';
649
+ import { ToastController } from '@ionic/angular';
650
+
651
+ @Component({
652
+ selector: 'app-form-preview',
653
+ templateUrl: './form-preview.page.html',
654
+ styleUrls: ['./form-preview.page.scss']
655
+ })
656
+ export class FormPreviewPage implements OnInit {
657
+ formComponents: FormComponentType[] = [];
658
+ formTitle: string = '';
659
+ formDescription: string = '';
660
+ formTemplateId: string = '';
661
+ currentDevice: 'desktop' | 'tablet' | 'mobile' = 'desktop';
662
+ loading = false;
663
+
664
+ constructor(
665
+ private route: ActivatedRoute,
666
+ private router: Router,
667
+ private formService: FormService,
668
+ private toastController: ToastController
669
+ ) {}
670
+
671
+ ngOnInit() {
672
+ const formId = this.route.snapshot.paramMap.get('id');
673
+ if (formId) {
674
+ this.loadForm(formId);
675
+ }
676
+ }
677
+
678
+ loadForm(formId: string) {
679
+ this.loading = true;
680
+ this.formService.getFormById(formId).subscribe(
681
+ form => {
682
+ this.formComponents = form.components;
683
+ this.formTitle = form.title;
684
+ this.formDescription = form.description;
685
+ this.formTemplateId = form.id;
686
+ this.loading = false;
687
+ },
688
+ error => {
689
+ console.error('Error loading form', error);
690
+ this.loading = false;
691
+ this.showErrorToast('Failed to load form');
692
+ }
693
+ );
694
+ }
695
+
696
+ handleFormSubmit(formData: FormComponentType[]) {
697
+ this.loading = true;
698
+ this.formService.submitForm(this.formTemplateId, formData).subscribe(
699
+ response => {
700
+ this.loading = false;
701
+ this.showSuccessToast('Form submitted successfully');
702
+ // Navigate back or to success page
703
+ setTimeout(() => {
704
+ this.router.navigate(['/form-list']);
705
+ }, 2000);
706
+ },
707
+ error => {
708
+ this.loading = false;
709
+ this.showErrorToast('Failed to submit form');
710
+ }
711
+ );
712
+ }
713
+
714
+ handleFormDataChange(formData: FormComponentType[]) {
715
+ // Optional: Auto-save functionality
716
+ console.log('Form data changed', formData);
717
+ }
718
+
719
+ async showSuccessToast(message: string) {
720
+ const toast = await this.toastController.create({
721
+ message,
722
+ duration: 2000,
723
+ color: 'success',
724
+ position: 'top'
725
+ });
726
+ toast.present();
727
+ }
728
+
729
+ async showErrorToast(message: string) {
730
+ const toast = await this.toastController.create({
731
+ message,
732
+ duration: 3000,
733
+ color: 'danger',
734
+ position: 'top'
735
+ });
736
+ toast.present();
737
+ }
738
+ }
739
+ ```
740
+
741
+ ### 5. Template
742
+
743
+ ```html
744
+ <!-- pages/form-preview/form-preview.page.html -->
745
+ <ion-header>
746
+ <ion-toolbar>
747
+ <ion-buttons slot="start">
748
+ <ion-back-button></ion-back-button>
749
+ </ion-buttons>
750
+ <ion-title>{{ formTitle || 'Form Preview' }}</ion-title>
751
+ </ion-toolbar>
752
+ </ion-header>
753
+
754
+ <ion-content>
755
+ <div *ngIf="loading" class="loading-container">
756
+ <ion-spinner></ion-spinner>
757
+ </div>
758
+
759
+ <app-form-preview
760
+ *ngIf="!loading && formComponents.length > 0"
761
+ [formComponents]="formComponents"
762
+ [currentDevice]="currentDevice"
763
+ [isPreviewMode]="false"
764
+ [formTitle]="formTitle"
765
+ [formDescription]="formDescription"
766
+ [formTemplateId]="formTemplateId"
767
+ (formSubmit)="handleFormSubmit($event)"
768
+ (formDataChange)="handleFormDataChange($event)"
769
+ ></app-form-preview>
770
+ </ion-content>
771
+ ```
772
+
773
+ ## Summary
774
+
775
+ 1. **Install** the package and peer dependencies
776
+ 2. **Import** the CSS in your global styles
777
+ 3. **Set up** React bridge for Angular
778
+ 4. **Create** wrapper components
779
+ 5. **Load** form data from your API
780
+ 6. **Use** the component in your pages
781
+ 7. **Handle** form submission and data changes
782
+
783
+ The package is now ready to use in your Ionic/Angular application!