Skip to main content

Version of DataGridField for use with Dexterity / z3c.form

Project description

Introduction

This module provides a z3c.form version of the Products.DataGridField . This product was developed for use with Plone4 and Dexterity.

https://travis-ci.org/collective/collective.z3cform.datagridfield.png

Requirements

  • Plone 4

  • z3c.forms

  • A browser with javascript support

  • jquery 1.4.3 or later

Installation

Add collective.z3cform.datagridfield to your buildout eggs.:

eggs=\
    ...
    collective.z3cform.datagridfield

Example usage

This piece of code demonstrates a schema which has a table within it. The layout of the table is defined by a second schema.:

from zope import schema
from zope import interface
from plone.directives import form
from z3c.form.form import extends
from z3c.form import field

from collective.z3cform.datagridfield import DataGridFieldFactory, DictRow

class ITableRowSchema(interface.Interface):
    one = schema.TextLine(title=u"One")
    two = schema.TextLine(title=u"Two")
    three = schema.TextLine(title=u"Three")

class IFormSchema(interface.Interface):
    four = schema.TextLine(title=u"Four")
    table = schema.List(title=u"Table",
        value_type=DictRow(title=u"tablerow", schema=ITableRowSchema))

class EditForm(form.EditForm):
    extends(form.EditForm)

    grok.context(IFormSchema)
    grok.require('zope2.View')
    fields = field.Fields(IFormSchema)
    label=u"Demo Usage of DataGridField"

    fields['table'].widgetFactory = DataGridFieldFactory

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

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:

from zope import schema
from zope import interface
from Products.CMFCore.interfaces import ISiteRoot

from five import grok

from plone.directives import form

from collective.z3cform.datagridfield import DataGridFieldFactory, DictRow
from .widget import DGFTreeSelectFieldWidget


class ITableRowSchema(form.Schema):

    form.widget(one=DGFTreeSelectFieldWidget)
    one = schema.TextLine(title=u"Level 1")

    form.widget(two=DGFTreeSelectFieldWidget)
    two = schema.TextLine(title=u"Level 2")

    # Uses the default widget
    three = schema.TextLine(title=u"Level 3")


class IFormSchema(form.Schema):

    form.widget(table=DataGridFieldFactory)
    table = schema.List(title=u"Nested selection tree test",
        value_type=DictRow(title=u"tablerow", schema=ITableRowSchema))

Working with plone.app.registry

To use the field with plone.app.registry, you’ll have to use a version of the field that has PersistentField as it’s base class:

from collective.z3cform.datagridfield.registry import DictRow

Javascript events

collective.z3cform.datagridfield fires jQuery events, so that you can hook them in your own Javascript for DataGridField behavior customization.

The following events are currently fired against table.datagridwidget-table-view

  • beforeaddrow [datagridfield, newRow]

  • afteraddrow [datagridfield, newRow]

  • beforeaddrowauto [datagridfield, newRow]

  • afteraddrowauto [datagridfield, newRow]

  • aftermoverow [datagridfield]

  • afterdatagridfieldinit - All DGFs on the page have been initialized

Example usage:

handleDGFInsert : function(event, dgf, row) {
    row = $(row);
    console.log("Got new row:");
    console.log(row);
},

// Bind all DGF handlers on the page
$(document.body).delegate(".datagridwidget-table-view", "beforeaddrow beforeaddrowauto", handleDGFInsert);

Demo

Examples are in the package collective.z3cform.datagridfield_demo.

See also

References

Changelog

0.13 (2013-04-09)

  • Fix to expect zope.schema.interfaces.ValidationError to work better with TooLong and TooShort exceptions. [datakurre]

  • Fix IE7 failing on <label> for manipulation [miohtama]

  • Deal with situations where there is zero rows on DGF and no auto-append row available [miohtama]

  • Correctly bind DGF events on DOM content loaded, not when Javascript is parsed [miohtama]

  • Don’t display movement handles if the row cannot be moved [miohtama]

  • Changed move up and down handlers to stay in fixed positions to make cells stay in the same width regardless of moving [miohtama]

  • Fixed checkbox saving, was broken by nested DGF support [miohtama]

  • Added block edit mode [miohtama]

  • “use strict;” and ECMAScript 5 compatible Javascript clean-up [miohtama]

  • Added afterrowmoved JS event [miohtama]

0.12 (2012-10-30)

  • Updated empty row selection. [jstegle]

  • Nested DataGridField support (yo dawg…) [miohtama]

  • Support plone.autoform and grok’ed row schemas [miohtama]

  • 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]

0.7 (2011-07-01)

  • Changed markup/javascript to prevent duplicate HTML id attributes. Changed Javascript to allow for datagrid page templates that don’t use tables. [dextermilo]

  • Improve spacing in CSS. [davisagli]

  • Revert my fix to ensure that blank rows are added, because it duplicated a fix in z3c.form resulting in extra rows. [davisagli]

0.6 (2011-05-17)

  • Search for datagridInitialise and datagridUpdateWidgets on the parent form, also when in a fieldset. [maurits]

  • Register templates on plone.app.z3cform.interfaces.IPloneFormLayer to take precedence over that packages list widget templates. [elro]

  • Make sure that updateWidgets is called to add blank rows even if the widget has no value. [davisagli]

  • When extracting a row value fails due to a validation error, convert widget values to field values so the value can be successfully applied to the grid widget. [davisagli]

  • Register a plone.supermodel handler for the DictRow so it can be used in supermodel models. [davisagli]

  • Depend on collective.z3cform.datagridfield_demo as a test extra; use the browser view from this package in the tests. [maurits]

  • _validate still used when import/exporting, fix up code so it works [lentinj]

  • Add a DictRow serializer for transmogrify.dexterity [lentinj]

  • Only use width:100% on input cells that are the only element in the cell [lentinj]

  • Reorder row indices backwards when adding rows. This means that adjacent rows don’t share the same index temporarily, for example:- - Row 1 and 2 contain input:radio based widgets - Row 0 added, row renumbering starts - Row 1 widgets renamed 2 - Both sets of input:radio share the same name, one deselected - Row 2 widgets renamed 3 - … [lentinj]

  • Use jQuery to clone rows, and clone the jQuery events on the rows. [lentinj]

  • Implemented reorder functionality

0.5 (2011-02-08)

  • Put in the DictRow class (tks Martin Aspeli)

  • Moved the demo code out to a separate package collective.z3cform.datagridfield_demo (tks Laurence Rowe).

  • Removed superfluous lines from setup.py (tks Laurence Rowe).

  • Removed unnessary dependency on dexterity (tks Laurence Rowe).

  • Removed unnessary dependency on grok (tks Laurence Rowe).

0.4 (2011-02-06)

  • Renamed the demo pages. The starting point is now @@demo-collective.z3cform.datagrid .

  • The widget can now be configured via the updateWidgets method. It is no longer necessary to create a custom factory.

  • The columns can now be omitted.

  • Provide a set of demo views for Object access.

0.3 (2011-02-04)

  • The auto-append functionality did not bind correctly for popup forms. I switched to using jQuery.live() instead of binding at document load time.

  • Added a menu to the demo pages

  • Added a display only form option.

  • Fixed the restructured text of the main README.txt so that it will show more friendly in PyPI.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

collective.z3cform.datagridfield-0.13.zip (65.0 kB view hashes)

Uploaded Source

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page