You can also use grok’ed forms where you subclass the schema
from plone.directives.form.SchemaForm and declare
widgets witin the schema using form.widget().

Storage

The data can be stored as either a list of dicts or a list of objects.
If the data is a list of dicts, the value_type is DictRow.
Otherwise, the value_type is ‘schema.Object’.

If you are providing an Object content type (as opposed to dicts) you
must provide your own conversion class. The default conversion class
returns a list of dicts, not of your object class. See the demos.

Configuration

Row editor handles

The widget can be customised via the updateWidgets method.

def updateWidgets(self):
super(EditForm, self).updateWidgets()
self.widgets['table'].allow_insert = False # Enable/Disable the insert button on the right
self.widgets['table'].allow_delete = False # Enable/Disable the delete button on the right
self.widgets['table'].auto_append = False # Enable/Disable the auto-append feature
self.widgets['table'].allow_reorder = False # Enable/Disable the re-order rows feature
self.widgets['table'].main_table_css_class = 'my_custom_class' # Change the class applied on the main table when the field is displayed

The widget contains an attribute ‘columns’ which is manipulated to hide column
titles.

Block edit mode

A widget class variation BlockDataGridField is provided.
This widget renders subform widgets vertically in blocks instead
of horizontally in cells. It makes sense when there are many
subform fields and they have problem to fit on the screen once.

Example:

class EditForm9(EditForm):
label = u'Rendering widgets as blocks instead of cells'
grok.name('demo-collective.z3cform.datagrid-block-edit')
def update(self):
# Set a custom widget for a field for this form instance only
self.fields['address'].widgetFactory = BlockDataGridFieldFactory
super(EditForm9, self).update()

Manipulating the Sub-form

The DataGridField makes use of a subform to build each line. The main DataGridField
contains a DataGridFieldObject for each line in the table. The DataGridFieldObject
in turn creates the DataGridFieldObjectSubForm to store the fields.

There are two callbacks to your main form:

datagridInitialise(subform, widget)

This is called when the subform fields have been initialised, but before
the widgets have been created. Field based configuration could occur here.

datagridUpdateWidgets(subform, widgets, widget)

This is called when the subform widgets have been created. At this point,
you can configure the widgets, e.g. specify the size of a widget.

Here is an example how one can customize per-field widgets for the data grid field:

1.0 (2014-06-02)

Use BlockDataGridFieldObject for rows in a BlockDataGridField.
[gaudenz]

Filter out any auto append or template rows in updateWidgets.
[gaudenz]

Add row parameter to aftermoverow JS event
[gaudenz]

Don’t reset class attribute on cloned template rows
[gaudenz]

Replace row index in all template row elements, not just input elements.
Replace the index in id, name, for, href and data-fieldname attributes
when cloning the template row.
[gaudenz]

0.15 (2013-09-24)

Added possibility to define the CSS class for the main table when the field is displayed.
This way, you can use common Plone existing classes (like ‘listing’).
[gbastien]

Fixed auto-append bug when there is more than one datagrid field in page auto-appending one field binds
“change.dgf” to another field also. added “$(dgf).find(..” in datagridfield.js line 138 so it binds to right element only.
[tareqalam]

Only abort moveRow if the row is really not found and not if the row idx just happens to be 0.
[gaudenz]

Also update hidden data rows when reindexing in row mode. This fix was previously somehow only done for block mode.
[gaudenz]

0.12 (2012-10-30)

Added DataGridField.extra parameter, so you can pass out
application specific data to Javascript [miohtama]

0.11 (2012-05-16)

be able to use with plone.app.registry
[vangheem]

0.10 (2012-02-12)

Fix bug with moving the last row up.
[m-martinez]

0.9 (2011-10-27)

Clone events when adding new row - fixes bug where browse button of
plone.formwidget.contenttree did nothing for new rows
[anthonygerrard]

Reindex more indexed attributes of cloned row
[anthonygerrard]

0.8 (2011-09-24)

Avoid using the “row” CSS class.
[davisagli]

Fixes to work with jQuery 1.3.x (use .remove() instead of .detach(), fetch data
attributes a different way, and avoid live binding the change event).
[davisagli]

Don’t error out when getting a FormatterValidationError, pass
it on to z3c.form instead.
[claytron]

Give manipulator images a relative src rather than absolute. This
previously meant the widget didn’t work on sites without Plone/Zope at the
root of the domain.
[davidjb]

During auto-insert, add our new row into the document first, before reindexing
it and changing its elements’ IDs. This allows Javascript that depends on
these IDs (such as plone.formwidget.autocomplete) to pick up the correct
fields.
[davidjb]

Tidying up and reducing complexity of auto-insert functionality
[davidjb]

Removing unnecessary auto-insert bind and unbind as this is already covered
by jQuery’s live() function against the auto-append class. Adding/removing
this class against rows automatically does this.
[davidjb]

Resolved issue with auto-insert functionality not working by removing
table-specific check in Javascript.
[davidjb]