--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/source/dev_guide/howto-form.rst Tue Dec 11 17:00:42 2018 +0100
@@ -0,0 +1,103 @@
+.. _formhowto:
+
+
+How to create a form to a component
+===================================
+
+
+When creating a new object to the zodb, the construction of the form can't be based on an object passed context.
+To build the form we use a default factory that is attached to the container of the element.
+
+
+1) Container factory
+--------------------
+
+Declaration of the **factory** of `ContactPhoneParagraph`
+
+.. code-block:: python
+
+ @utility_config(name=CONTACT_PHONE_PARAGRAPH_TYPE, provides=IParagraphFactory)
+ class ContactPhoneParagraphFactory(BaseParagraphFactory):
+ """Contact paragraph factory"""
+
+ name = _("Contact Phone card")
+ content_type = ContactPhoneParagraph
+ secondary_menu = True
+
+
+
+For example :py:class:`IParagraphContainerTarget`, it's a marker interface for paragraph containers.
+We could use this interface as context to declare a new pagelet.
+
+
+.. code-block:: python
+
+ from pyams_form.form import ajax_config
+
+
+ @pagelet_config(name='add-contact-phone-paragraph.html', context=IParagraphContainerTarget, layer=IPyAMSLayer,
+ permission=MANAGE_CONTENT_PERMISSION)
+ @ajax_config(name='add-contact-phone-paragraph.json', context=IParagraphContainerTarget, layer=IPyAMSLayer,
+ base=BaseParagraphAJAXAddForm)
+ class ContactPhoneParagraphAddForm(AdminDialogAddForm):
+ """Contact paragraph add form"""
+
+ legend = _("Add new phone contact card")
+ dialog_class = 'modal-large'
+ icon_css_class = 'fa fa-fw fa-phone'
+ edit_permission = MANAGE_CONTENT_PERMISSION
+
+ #Retrieve fields from the interface of the component
+ fields = field.Fields(IContactPhoneParagraph).omit('__parent__', '__name__', 'visible')
+
+
+ def create(self, data):
+ """Create one instance of the component"""
+ return ContactPhoneParagraph()
+
+ def add(self, object):
+ """Add the new component to the container that implement the interface `IParagraphContainer` """
+ IParagraphContainer(self.context).append(object)
+
+The associate form field are generated automatically based on this interface attributes
+
+:py:function:`@ajax_config()` allows the form is working with ajax requests by providing `json` content.
+
+
+
+2) Edit form
+------------
+
+.. code-block:: python
+
+ @adapter_config(context=(IContactPhoneParagraph, IPyAMSLayer), provides=IParagraphInnerEditor)
+ permission=MANAGE_CONTENT_PERMISSION)
+ @ajax_config(name='inner-properties.json', context=IContactPhoneParagraph, layer=IPyAMSLayer,
+ base=BaseParagraphAJAXEditForm)
+ @implementer(IInnerForm)
+ class ContactPhoneParagraphInnerEditForm(ContactPhoneParagraphPropertiesEditForm):
+ """Contact paragraph inner edit form"""
+
+ legend = None
+
+ @property
+ def buttons(self):
+ if self.mode == INPUT_MODE:
+ return button.Buttons(IParagraphEditFormButtons)
+ else:
+ return button.Buttons()
+
+ def get_ajax_output(self, changes):
+ output = super(ContactParagraphInnerAJAXEditForm, self).get_ajax_output(changes)
+ updated = changes.get(IBaseParagraph, ())
+ if 'title' in updated:
+ output.setdefault('events', []).append(get_json_paragraph_refresh_event(self.context, self.request))
+ updated = changes.get(IContactParagraph, ())
+ if ('photo' in updated) or ('renderer' in updated):
+ # we have to commit transaction to be able to handle blobs...
+ if 'photo' in updated:
+ ITransactionManager(self.context).get().commit()
+ output.setdefault('events', []).append(get_json_form_refresh_event(self.context, self.request,
+ ContactParagraphInnerEditForm))
+ return output
+