|
1 .. _formhowto: |
|
2 |
|
3 |
|
4 How to create a form to a component |
|
5 =================================== |
|
6 |
|
7 |
|
8 When creating a new object to the zodb, the construction of the form can't be based on an object passed context. |
|
9 To build the form we use a default factory that is attached to the container of the element. |
|
10 |
|
11 |
|
12 1) Container factory |
|
13 -------------------- |
|
14 |
|
15 Declaration of the **factory** of `ContactPhoneParagraph` |
|
16 |
|
17 .. code-block:: python |
|
18 |
|
19 @utility_config(name=CONTACT_PHONE_PARAGRAPH_TYPE, provides=IParagraphFactory) |
|
20 class ContactPhoneParagraphFactory(BaseParagraphFactory): |
|
21 """Contact paragraph factory""" |
|
22 |
|
23 name = _("Contact Phone card") |
|
24 content_type = ContactPhoneParagraph |
|
25 secondary_menu = True |
|
26 |
|
27 |
|
28 |
|
29 For example :py:class:`IParagraphContainerTarget`, it's a marker interface for paragraph containers. |
|
30 We could use this interface as context to declare a new pagelet. |
|
31 |
|
32 |
|
33 .. code-block:: python |
|
34 |
|
35 from pyams_form.form import ajax_config |
|
36 |
|
37 |
|
38 @pagelet_config(name='add-contact-phone-paragraph.html', context=IParagraphContainerTarget, layer=IPyAMSLayer, |
|
39 permission=MANAGE_CONTENT_PERMISSION) |
|
40 @ajax_config(name='add-contact-phone-paragraph.json', context=IParagraphContainerTarget, layer=IPyAMSLayer, |
|
41 base=BaseParagraphAJAXAddForm) |
|
42 class ContactPhoneParagraphAddForm(AdminDialogAddForm): |
|
43 """Contact paragraph add form""" |
|
44 |
|
45 legend = _("Add new phone contact card") |
|
46 dialog_class = 'modal-large' |
|
47 icon_css_class = 'fa fa-fw fa-phone' |
|
48 edit_permission = MANAGE_CONTENT_PERMISSION |
|
49 |
|
50 #Retrieve fields from the interface of the component |
|
51 fields = field.Fields(IContactPhoneParagraph).omit('__parent__', '__name__', 'visible') |
|
52 |
|
53 |
|
54 def create(self, data): |
|
55 """Create one instance of the component""" |
|
56 return ContactPhoneParagraph() |
|
57 |
|
58 def add(self, object): |
|
59 """Add the new component to the container that implement the interface `IParagraphContainer` """ |
|
60 IParagraphContainer(self.context).append(object) |
|
61 |
|
62 The associate form field are generated automatically based on this interface attributes |
|
63 |
|
64 :py:function:`@ajax_config()` allows the form is working with ajax requests by providing `json` content. |
|
65 |
|
66 |
|
67 |
|
68 2) Edit form |
|
69 ------------ |
|
70 |
|
71 .. code-block:: python |
|
72 |
|
73 @adapter_config(context=(IContactPhoneParagraph, IPyAMSLayer), provides=IParagraphInnerEditor) |
|
74 permission=MANAGE_CONTENT_PERMISSION) |
|
75 @ajax_config(name='inner-properties.json', context=IContactPhoneParagraph, layer=IPyAMSLayer, |
|
76 base=BaseParagraphAJAXEditForm) |
|
77 @implementer(IInnerForm) |
|
78 class ContactPhoneParagraphInnerEditForm(ContactPhoneParagraphPropertiesEditForm): |
|
79 """Contact paragraph inner edit form""" |
|
80 |
|
81 legend = None |
|
82 |
|
83 @property |
|
84 def buttons(self): |
|
85 if self.mode == INPUT_MODE: |
|
86 return button.Buttons(IParagraphEditFormButtons) |
|
87 else: |
|
88 return button.Buttons() |
|
89 |
|
90 def get_ajax_output(self, changes): |
|
91 output = super(ContactParagraphInnerAJAXEditForm, self).get_ajax_output(changes) |
|
92 updated = changes.get(IBaseParagraph, ()) |
|
93 if 'title' in updated: |
|
94 output.setdefault('events', []).append(get_json_paragraph_refresh_event(self.context, self.request)) |
|
95 updated = changes.get(IContactParagraph, ()) |
|
96 if ('photo' in updated) or ('renderer' in updated): |
|
97 # we have to commit transaction to be able to handle blobs... |
|
98 if 'photo' in updated: |
|
99 ITransactionManager(self.context).get().commit() |
|
100 output.setdefault('events', []).append(get_json_form_refresh_event(self.context, self.request, |
|
101 ContactParagraphInnerEditForm)) |
|
102 return output |
|
103 |