diff -r 1de74ac0628f -r 31b3d00edb8a src/source/developer_guide/howto-form.rst --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/source/developer_guide/howto-form.rst Tue Dec 11 16:29:56 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 +