Skip to content

Editable / Excel style grid #5

@bakesteve

Description

@bakesteve

Tracker for what we'd like to have out of a react grid

See SlickGrid for a very strong implementation of features

Other Grid componnets

Griddle looks good, though missing number of features
React-Grid the original version of this. no edits/navigation
ReactiveGrid more of a PoC but has got keyboard navigation

Todo / Wish List

  • Keyboard Navigation In Progress
  • Basic Theme
  • Customise styles
  • Renderers (custom cell display)
  • Smart column widths - based on content, and decent styling for wrapping content
  • Editors
  • Undo / redo / track changes
  • Sorting
  • Drag Down
  • Copy and paste
  • Grouping
  • Filters
  • Subgrids (do this as a rowRenderer => new grid?)
  • Flux
  • Editors
    • Simple
    • DropDown
    • Checkbox
    • Datepicker
    • Autocomplete

Keyboard Navigation

Tasks

  • Basic nav
  • With vertical scroll
  • horizontal scroll
  • freeze panes
  • left into 1st column in non-frozen pane, doesnt fully scroll into view
  • left / right with freezepanes and horizontal scroll doesnt always scoll headers
  • loop at end of columns (last column -> right -> first column)
  • loop at end of rows (last row-> down -> first row)
  • Multiple select with shift key
  • click to select
  • pass through styling for selected cell
  • validate use of GetDomNode is neccessary
  • resizes on window resize
  • tests

Initial design thoughts

  • rows and cells need to know they are selected, and have some UX hint
  • other actions should be aware of this, ie hit enter to edit
  • default is 1 cell selected at any time
  • should design for multiple selection (using shift + )?
  • and select using mouse
  • the grid needs to know what is selected (for copy/paste, drag, commit edits, etc)
  • moving outside of the visible viewport needs to scroll the grid

One immediate issue is React doesnt delegate KeyUp unless you are in a form field, so will need to resort back to native / jQuery in ComponentDidMount
We also need to know what row we are on. Cells probably shouldnt be aware of that (though that may too restrictive)
Also need to be carefull about indexes for rows (needs to understand data index, not the display index) and columns (frozen columns, hidden cols, etc) < in both scenarios if we have a cell.idx and a row.idx we will be fine

Renderers

Initial thoughts

Controlled through column.celRenderer
Needs to control style and text display. Common use cases will be formatting a number as a currency
May need access to several data attributes, so need to think out how this is done

  • Work out how to allow a cell to require >1 attribute (ie CurrencyRenderer needs a value and a currency code/symbol:
var cellData = {
  value: 1000,
  currency: 'GBP',
  curencySymbol: '£'
}
//which means calling it with a custom func from row -> cell
//or mayeb use a lens? so:
col = {
  key: 'Price',
  cellRenderer: CurrencCell,
  cellDataLens: function(row) {
    return {
      value: row.Price,
      currency: row.PriceCurrencyCode,
      curencySymbol: row.PriceCurrencySymbol
     }
  }
}
//or only allow 1 attribute, and allow access to row data? <- feels like a bad thing
return (<div>{row.CurrencySymbol}{value}</div>);

Also need to think about allowing custom formulas, and allowing overrides for them - see locked editors. The renderer should indicate if a cell is ReadOnly, Overridable, or Editable. If the value has been overriden, this should be flagged in a consistent manner

Editors

Initial design thoughts

  • General principal is only show 1 editor at a time (though be nice if that was configurable
  • Want full keyboard support, including to begin (start typing, or hit enter), commit (enter, tabs, arrows) and cancel (esc)
  • Editors should be as unaware of context as possible, though may need access to row level data, not just the cell?
  • Should pass data back using callbacks? actions (flux)? or events?

We can control the editor easily enough through the column.renderer property, but need to know if the cell is being edited or not.
Grids are, by design, going to be killing off rows (and cells) as you scroll, so cant use state to manage that. We also want mouse clicks elsewhere to commit the edit, so that implies state is held at a higher level.
Using a prop, seems like a better choice.

Commiting an edit*
Assumed flow would be:
Editor.onCommit=>Editor.Valdate=>Cell.handleCommit=>Cell.onChange=>Row.handleCellChange=>Row.onChange
Canvas and Viewport make this chain a bit longer to then bubble up to the grid so that we can update the data store/state. We could probably jump from Row -> Grid/Store. May be a case where Flux helps out

Editor controls
Simple editors (numbers, dates, etc) will be straightforward. But some editors will require a lot more info than may be contained in a simple key/value set that a cell operates on. A few things to consider

  • Cells own editors, and should pass all the information the editor needs
  • Cells are ignorant about row data (this may be wrong)
  • ReadOnly / metadata, may be different, so a price editor may need the currency, but that cell may not own the currency code information. We should have a way to pass in immutable data. that may just be as props?
  • Composite properties, where a cell data contains several parts, so you may have a single address cell, that is actually a collection of several properties, a city, a postcode, etc

Keyboard navigation
We will want pressing Tab in an editor to either:

  • Tab to the next control in a composite editor
  • commit the edit and then pass control onto the cell, so it can do its [thang](Keyboard Navigation)
    (though as react events bubble, thats fine, so editor.onKeyPress can stopPropogation, or not)

Validation
commiting an edit should call a validate function. Needs to be a standard way to provide user feedback, and the commit edit shoudl be blocked till this returns true

Sorting

Should be easy enough, just need the UX and a sorting algorithm
Also need to ideally add custom sorting via drag handlers. Again, should just be the same
When designing, should extend the simple sample to give the capability for multiple levels of sorting, and sort by (ie sort by Name: Z-A, then by Country: A-Z (or Id, using ISO code?), then by Age: 0-9, then by Date: Oldest to Smallest)

Override Locked Editors

Need to distiunguish between cells that are Editable, ReadOnly, and Overidable
If it is overidable, the cell renderer shoudl indicate this in the same way as ReadOnly, but ideally we'd have teh same user experience for editing - possibly with some UX highlights to show this is overiding.

Drag Down

Ideally done as a form of UX mask

  • DragStart -> store cell value [somewhere](Copy and paste]
  • Drag -> mark cell UX + store which cells are marked for Drag
  • DragEnd -> Apply stored cell props onto marked cells, and infrom the owner of our state/store that this has happened

Need to think how we:

  • Store the data on data we drag from, and which cells we are dragging to
  • mark the ui to show whats going on
  • constrain selection to just this column?
  • horizontal drag?
  • drag multiple cells

Copy and paste

Ideally handled at a high level, using OnCopy and OnPaste events
Assuming we have an Active Cell concept, then should be ok to grab that in Copy, and push it on Paste

Undo / Redo

At first glance this is very, very easy (thanks react!)
however, want to be more efficient that just storing entire object graphs on every change. We want something that works with large collections (100 cols x 1000s rows) with a large number of edits
Maybe do something esoteric like storing individual changes with functional lens to apply that back ontop of the main data?

Performance

Should be bloody fast, but need to ensure we only update the dom if we need to
ideally that would just be using immutable data (by convention, or being clever

shouldComponentUpdate: function(object nextProps, object nextState) {
  return nextProps !== this.props;
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions