Commit | Line | Data |
---|---|---|
64423b13 | 1 | # Embedding Forms: Afform as reusable building-block |
8a0ffdf9 TO |
2 | |
3 | In the [quick-start example](quickstart.md), we registered a new route (`"server_route": "civicrm/hello-world"`) -- this created a | |
4f4b6487 | 4 | simple, standalone page with the sole purpose of displaying the `helloWorld` form. What if we want to embed the form |
9b5234b7 | 5 | somewhere else -- e.g. as a dialog inside an event-listing or membership directory? Afforms are actually *re-usable |
8a0ffdf9 TO |
6 | sub-forms*. |
7 | ||
4f4b6487 | 8 | How does this work? Every `afform` is an *AngularJS directive*. For example, `hello-world` can be embedded with: |
8a0ffdf9 TO |
9 | |
10 | ```html | |
4f4b6487 | 11 | <div hello-world=""></div> |
8a0ffdf9 TO |
12 | ``` |
13 | ||
4f4b6487 | 14 | Moreover, you can pass options to `helloWorld`: |
8a0ffdf9 TO |
15 | |
16 | ```html | |
4f4b6487 | 17 | <div hello-world="{phaseOfMoon: 'waxing'}"></div> |
8a0ffdf9 TO |
18 | ``` |
19 | ||
4f4b6487 | 20 | Now, in `ang/helloWorld.aff.html`, you can use `options.phaseOfMoon`: |
8a0ffdf9 TO |
21 | |
22 | ```html | |
23 | Hello, {{routeParams.name}}. The moon is currently {{options.phaseOfMoon}}. | |
24 | ``` | |
25 | ||
64423b13 | 26 | ## Example: Contact record |
8a0ffdf9 TO |
27 | |
28 | Is this useful? Let's suppose you're building a contact record page. | |
29 | ||
30 | First, we should make a few building-blocks: | |
31 | ||
4f4b6487 TO |
32 | 1. `ang/afformContactName.aff.html` displays a sub-form for editing first name, lastname, prefix, suffix, etc. |
33 | 2. `ang/afformContactAddresses.aff.html` displays a sub-form for editing street addresses. | |
34 | 3. `ang/afformContactEmails.aff.html` displays a sub-form for editing email addresses. | |
8a0ffdf9 | 35 | |
4f4b6487 | 36 | Next, we should create an overall `ang/afformContact.aff.html` which uses these building-blocks: |
8a0ffdf9 TO |
37 | |
38 | ```html | |
39 | <div ng-form="contactForm"> | |
40 | <div crm-ui-accordion="{title: ts('Name')}"> | |
41 | <div afform-contact-name="{cid: routeParams.cid}"></div> | |
42 | </div> | |
43 | <div crm-ui-accordion="{title: ts('Street Addresses')}"> | |
44 | <div afform-contact-addresses="{cid: routeParams.cid}"></div> | |
45 | </div> | |
46 | <div crm-ui-accordion="{title: ts('Emails')}"> | |
47 | <div afform-contact-emails="{cid: routeParams.cid}"></div> | |
48 | </div> | |
49 | </div> | |
50 | ``` | |
51 | ||
4f4b6487 | 52 | And we should create a `ang/afformContact.aff.json` looking like |
a8cb7414 TO |
53 | |
54 | ```json | |
55 | { | |
56 | "server_route": "civicrm/contact", | |
57 | "requires" : ["afformContactName", "afformContactEmails", "afformContactAddresses"] | |
58 | } | |
6a7e9d50 | 59 | ``` |
4f4b6487 | 60 | > *(FIXME: In the parent form's `*.aff.json`, we need to manually add `afformContactName`, `afformContactAddresses`, `afformContactEmails` to the `requires` list. We should autodetect these instead.)* |
8a0ffdf9 | 61 | |
4f4b6487 TO |
62 | We've created new files, so we'll need to flush the file-index |
63 | ||
64 | ``` | |
65 | cv flush | |
66 | ``` | |
67 | ||
68 | and now we can open the page | |
69 | ||
70 | ``` | |
71 | cv open 'civicrm/contact?cid=100' | |
72 | ``` | |
73 | ||
74 | What does this buy us? It means that a downstream admin (using APIs/GUIs) can fork `ang/afformContactName.aff.html` -- | |
8a0ffdf9 TO |
75 | but all the other components can cleanly track the canonical release. This significantly reduces the costs and risks |
76 | of manging upgrades and changes. |