Giter VIP home page Giter VIP logo

editablecell's Introduction

Knockout-EditableCell

Knockout-EditableCell (or just editableCell) is an extension to Knockout for turning ordinary table cells into selectable, editable cells, behaving much like cells in Microsoft Excel.

It supports features like:

  • Keyboard and mouse navigation
  • Cell selection (both via the keyboard and the mouse)
  • In-place editing of a Knockout observable
  • Additional display customization of the observable value (via cellText and cellHTML functions)
  • Applying a new value to all selected cells (via Ctrl+ENTER)

Try out the demo! Or on JSBin!

Requirements

editableCell depends upon Knockout (and therefore has an implicit dependency on jQuery).

v2.1.1 supports Knockout v3.0.0+, and is compatible with any version of jQuery supported by Knockout.

Browser support

editableCell should support most modern browsers: IE8+, FF 31+, Chrome 31+, Safari 7+

Support will also depend on the versions of Knockout and jQuery in use.

Please file an issue or update our tracking issue if your run into any problems

Getting Started

Adding editableCell to your project

You can obtain editableCell in a number of ways:

  • Download the files in the out folder manually (shown below, assuming you've placed the files in the vendor folder)
  • NEW: editableCell is now available via Bower! The package name is knockout-editable-cell
$ bower install knockout-editable-cell
  • You can use a CDN: https://cdn.rawgit.com/gnab/editableCell/v2.1.1/out/editableCell.min.js
  • SOON: Via NuGet!

Loading editableCell

editableCell can be loaded via a normal script tag, or using and AMD loader (like RequireJS).

Via a script tag:

<!-- Add 'editableCell' right after your current Knockout script -->
<script type="text/javascript" src="http://knockoutjs.com/downloads/knockout-3.2.0.js"></script>
<script type="text/javascript" src="vendor/editableCell.js"></script>

Via RequireJS:

/* Add 'editableCell' to your existing requireJs configuration */

requirejs.config({
    paths: {
        knockout: './node_modules/knockout/build/output/knockout-latest',
        editableCell: './vendor/editableCell.min'
    }
});

Usage

editableCell is a Knockout binding targeting table cells (td). By default, they will be selectable and editable. You just need to pass a Knockout observable or computed property to the binding:

<table>
    <tr>
        <td data-bind="editableCell: name"></td>
    </tr>
</table>

To customize the default behaviour, you may use the following supplemental binding properties:

  • cellReadOnly - Whether the cell should be editable. It will always, however, remain selectable.
  • cellText - The text to display when the cell is not being edited.
  • cellHTML - A more advanced version of cellText that allows additional customization.

Typically, cellHTML is bound to function on your view model that returns a string of HTML. editableCell will automatically call this function with the bound observable's current value, and you can return a string containing arbitrary HTML that will be inserted inside the td.

<!-- Won't be editable-->
<td data-bind="editableCell: id, cellReadOnly: true"></td>

<!-- Will display '23 years' if age() === 23 -->
<td data-bind="editableCell: age, cellText: age() + ' years'"></td>

<!-- Turns a string into an HTML element inside the TD.
     If the user edits the cell, the function will be called
     with the new 'price' value -->
<td data-bind="editableCell: price, cellHTML: priceWithCurrencySpan"></td>

Selection

You can select cells using the mouse (by dragging), or by using the Shift + arrow keyboard shortcuts.

When you select multiple cells, you typically want to perform an action based on the contents. In order to get the currently selected cells in the table, you can bind an observable array (i.e., selection below) to your table using the editableCellSelection binding:

/* in your viewmodel */
var selection = ko.observableArray();
<!-- in your view -->
<table data-bind="editableCellSelection: selection">

Whenever the user selects one or more cells in the table, the observable array will be updated. The array will contain:

[
  {
    cell: elem /* HTMLTableCellElement */,
	value: val /* the (observable) property that editableCell is bound to */,
	text: txt /* the (observable) property that editableCell is bound to via the 'cellText' binding, or else the same as value */
  },
  /* { ... */
]

Rows / cells not using editableCell

If you have rows or cells that don't use the editableCell binding, or don't use Knockout bindings at all, then editableCell won't navigate to them (using the keyboard, for instance).

If there are rows or cells not using the editableCell binding separating rows or cells that are, then navigation will hop over the unbound cells, similarly to the way navigating between tables (see Sharing selection, below).

Copying & Pasting

editableCell supports both pasting in structured data to one or more cells, and copying values from table cells. In the latter case, the values will be pasted as a tab-delimited array of values (columns), and rows will be separated by cr-lf.

Sharing selection

The parent table uses the editableCellSelection binding for keeping track of selected cells. If two or more tables share the same Knockout observable array in their editableCellSelection bindings, then editableCell will:

  • ensure that the user can only select cells in one table at a time.
  • allow the user to navigate between the linked tables using the keyboard.

List of keyboard shortcuts

arrow keys
Navigate in the table.
Shift + arrow
Select cells in the table.
Ctrl + Shift + arrow
Select all cells in the table, starting from currently-selected cell.
Escape
Cancel editing
Enter
Complete editing. Your change will also be automatically applied if you navigate away from the cell.
Ctrl + Enter
If you have multiple cells selected, and begin editing, this will apply the value to all selected cells.
Delete or Ctrl + Backspace
Replaces the current value with `null`, if the underlying observable supports it.

Overriding Styling

Cell styling

For the table, tr, and td or th tags, editableCell does not add any styles itself. Feel free to style your table how you please.

When editing a cell, editableCell uses an input element with the CSS class editable-cell-input for editing. This is only directly visible when the user double-clicks on the cell.

If you wanted to make the text bold when it's being edited, you could:

    .editable-cell-input { font-weight: bold; }

Selection styling

The selection styling is done with a semi-transparent div that has the CSS class editable-cell-selection.

If you wanted to have a selection that was light blue, rather than orange, you could:

    .editable-cell-selection { background-color: rgba(200, 100, 30, .015) !important; }

Comparison to other editing libraries

Other 'editable' libraries approach the same problem in slightly-different ways.

Some, like x-editable don't fit particularly well with large amounts of table-structured data. We wanted an user-experience closer to Excel-style editing.

Others try to build a wrapper around contentEditable. An early version of editableCell tried this, but we ran into some issues. (For more details, see issue #3).

Finally, there are a large number of table or grid components, like Handsontable, <a href-"https://github.com/Knockout-Contrib/KoGrid">ko-grid, and others. These are great solutions, but the drawback is that they are very focused on controlling the entire table 'surface'. That is, they usually assume that you will configure the table definition in javascript and give them a container DOM element to render into. We wanted to embrace the existing layout, and (potentially) make only a single row (or even cell) editable.

And of course, we wanted to fit well in a project already using Knockout.

License

This project is licensed under the MIT license.

Contributing

Building editableCell

  • Clone the repository
  • Install dependencies
$ npm install
  • Run node make - both minified and non-minified versions of editableCell will be placed in the out folder

editablecell's People

Contributors

gnab avatar jstclair avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

editablecell's Issues

Use explicit publishing "step" to include output

In managing my other project, I looked at the Knockout build steps, and they have something similar to the following (except included as a Grunt task, so the version is automatically determined by tweaking the bower.json):

To publish, run:

git add bower.json
git add -f out/*
git checkout HEAD
git commit -m "Version {version} for distribution"
git tag -a v{version} -m "Add tag v{verson}"
git checkout master
git push origin --tags

This allows them to exclude the out/dist folder completely, and then just include it (without affecting future commits) only for the tags.

Thoughts?

Allow setting null

Once a value is written by editableCell, there's no way to return to a null value. For some implementers, null is a valid value, and we should provide a key/key combination to signal "write a null back"

Note that this doesn't mean that the underlying observable's validation will be bypassed. If you use an knockout extender, for instance, that ensures the observable is a number, you'd need to either:

  • modify the extender to allow nullable numbers
  • create a new nullableNumeric extender
  • continue on, and the attempt to write null would be treated like attempting to write 'A'

Cannot find module 'knockout'

I'm trying to use this plugin in a node-webkit project and I'm using RequireJS to load all of my dependencies. After adding editableCell to the project I get:

"Uncaught Error: Cannot find module 'knockout'", source: module.js (338)

It looks like the Require code setup doesn't work with the option of leaving "require" to nodejs and using "requirejs" instead.

Publish via NuGet

I've signed up for a free MyGet subscription (for open-source contributors) which is how @object builds his Simple.OData.Client library.

Issue when loading Knockout via AMD

Hello!

We have an issue when loading Knockout via require; editableCell fails to load, since it expects ko to be a global (i.e., window) variable.

I've created a minimal reproduction of the problem here: https://github.com/jstclair/ec-amd-bug

After cloning the repo,

  • Ensure you have the right npm globals installed:
npm install -g gulp typescript bower http-server 

The last one is optional, but I'm going to assume it's installed later.

  • Install local and bower deps
npm install
bower install
  • Build the site using gulp
gulp
  • Start http-server for the src/ folder (will work because of our tremendous hack)
http-server src/

Open a browser to http://localhost:8080/

EditableCell is working! This, however, is due to the preEditableCell.js script (in the src/vendor folder) and a shim (in the src/app/require.config.js file).

  • Quit the previous http-server instance, and run it from the dist folder.
http-server dist/

Opening a browser, you will see it doesn't work.

Espen and I have cloned the editableCell repo and tried to change options in the browserify config in order to force editableCell to externally require knockout, but the only thing we've been able to accomplish is including the entire knockout.js script in editableCell (not our preferred solution).

Any help would be greatly appreciated!

Clarify license

Is there an explicit license associated with editableCell? Shouldn't we do that?

Bower package

Should create a bower and publish a bower package

Copy images not only text

I have a request regarding the simple copy function via a normal shortcut.
If I have a image in a html table with a simple img balise, this balise refer to this image via a link, In a normal html table I can copy paste and I will get the image copied as well. In editableCell I have nothing.

Do you think it would be possible to implement this ?

Thanks for the great job.

Handle hidden cells

Hidden cells should:

  • not be included in the selection range
  • not be navigatable

When the focused cells becomes hidden (blur + offsetHeight == 0), the first visible cell above it should get the focus.

Clarify name

The repo is 'editableCell', The docs say 'knockout.editableCell'. For things like bower and npm, we should agree on the general name.

The main issue going forward is whether the name should reflect the connection to knockout or not. I know @gnab was planning to disentangle some of knockout.

In addition, at least in bower, a lot of packages are 'ko-{something}'.

Re-write landing page

Things I think need clarification:

  • connection to Knockout
  • other "default" features. There's no mention of advanced navigation or selection shortcuts, control-enter behavior, or copy-paste in either landing or demo pages.
  • show full range of bindings
  • styling tips

Extensibility when navigating inside a "virtual" table

Some implementers have implemented a virtual table; navigation of editableCell depends upon the ability to find the previous/next row or column. It would be nice to bake in a extensibility model here, so implementers can communicate with the bounds checking in editableCell and adjust their current "virtual" posiition before editableCell decides it can't move further.

Clarify version

I'm assuming we want to follow semantic versioning because we're down like that?

At least according to the spec, if you've got a version in production, you're already at 1.0.0. So perhaps we should bump the major of master to 1, and (when/if) we promote develop to master, mark that 1.1?

More idiomatic Javascript?

Working on a small side-branch to look at more modern javascript styling. Wonder what you think?

See, for example, selection.js

Took a while to figure out some of the scoping issues. One of the things it helps clear up is where editableCell was relying on implicit this being set in kinda-confusing ways. Note that in the above, I did convert all the functions to hang off the prototype (for ease in conversion), but obviously some of the ones which don't have a dependency on range, etc., could go back to being stand-alone functions.

I'd also like to bring in some of the bite-size pieces of lodash to simplify some of the iteration, etc.)

Comments?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.