Editing rows

How to create a table that uses the editing component.

The editing component is half of the solution to providing a simple but effective row editing interface. It provides the table UI and logic while you provide the editor UI and logic.

To enable editing on a table the only option that must be set is the enabled option with a value of true. Once enabled an edit button is displayed in the footer of the table, when clicked it enables the editing UI showing the add, edit and delete buttons for rows. This behavior can be changed using the alwaysShow option that removes the first step and makes the add, edit and delete row buttons permanently visible.

ID First Name Last Name Job Title Started On Date of Birth
1 Dennise Fuhrman High School History Teacher November 8th 2011 July 25th 1960
2 Elodia Weisz Wallpaperer Helper October 15th 2010 March 30th 1982
3 Raeann Haner Internal Medicine Nurse Practitioner November 28th 2013 February 26th 1966
4 Junie Landa Offbearer October 31st 2010 March 29th 1966
5 Solomon Bittinger Roller Skater December 29th 2011 September 22nd 1964
6 Bar Lewis Clown November 12th 2012 August 4th 1991
7 Usha Leak Ships Electronic Warfare Officer August 14th 2012 November 20th 1979
8 Lorriane Cooke Technical Services Librarian September 21st 2010 April 7th 1969
9 Nelly Lusher Broadcast Maintenance Engineer October 21st 2013 February 16th 1983

Step 1: Create your editor UI

In the above example the editor is simply a Bootstrap modal with a form containing inputs matching our row. The below is the HTML markup to create it, if you are not using Bootstrap you will need to create this yourself. If you are using Bootstrap you can copy the below and simply change the form inputs to match your row data.

<div class="modal fade" id="editor-modal" tabindex="-1" role="dialog" aria-labelledby="editor-title">
	<style scoped>
		/* provides a red astrix to denote required fields - this should be included in common stylesheet */
		.form-group.required .control-label:after {
			content:"*";
			color:red;
			margin-left: 4px;
		}
	</style>
	<div class="modal-dialog" role="document">
		<form class="modal-content form-horizontal" id="editor">
			<div class="modal-header">
				<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
				<h4 class="modal-title" id="editor-title">Add Row</h4>
			</div>
			<div class="modal-body">
				<input type="number" id="id" name="id" class="hidden"/>
				<div class="form-group required">
					<label for="firstName" class="col-sm-3 control-label">First Name</label>
					<div class="col-sm-9">
						<input type="text" class="form-control" id="firstName" name="firstName" placeholder="First Name" required>
					</div>
				</div>
				<div class="form-group required">
					<label for="lastName" class="col-sm-3 control-label">Last Name</label>
					<div class="col-sm-9">
						<input type="text" class="form-control" id="lastName" name="lastName" placeholder="Last Name" required>
					</div>
				</div>
				<div class="form-group">
					<label for="jobTitle" class="col-sm-3 control-label">Job Title</label>
					<div class="col-sm-9">
						<input type="text" class="form-control" id="jobTitle" name="jobTitle" placeholder="Job Title">
					</div>
				</div>
				<div class="form-group required">
					<label for="startedOn" class="col-sm-3 control-label">Started On</label>
					<div class="col-sm-9">
						<input type="date" class="form-control" id="startedOn" name="startedOn" placeholder="Started On" required>
					</div>
				</div>
				<div class="form-group">
					<label for="dob" class="col-sm-3 control-label">Date of Birth</label>
					<div class="col-sm-9">
						<input type="date" class="form-control" id="dob" name="dob" placeholder="Date of Birth">
					</div>
				</div>
			</div>
			<div class="modal-footer">
				<button type="submit" class="btn btn-primary">Save changes</button>
				<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
			</div>
		</form>
	</div>
</div>

Step 2: Hooking up the editor

Now that we have our editor we need to hook it into the plugin using the editing callbacks and/or events. You can use the editing options addRow, editRow and deleteRow to provide callbacks to execute when the associated button is clicked. These callbacks can also be prevented from executing by calling e.preventDefault() in the corresponding add.ft.editing, edit.ft.editing and delete.ft.editing events.

In this example I've created some variables to cache various objects which are used in the callbacks.

var $modal = $('#editor-modal'),
	$editor = $('#editor'),
	$editorTitle = $('#editor-title'),
	// the below initializes FooTable and returns the created instance for later use
	ft = FooTable.init('#editing-example', {
		editing: {
			enabled: true,
			addRow: ...,
			editRow: ...,
			deleteRow: ...
		}
	}),
	// this example does not send data to the server so this variable holds the integer to use as an id for newly
	// generated rows. In production this value would be returned from the server upon a successful ajax call.
	uid = 10;

Step 2a: Adding a new row

First we will hook up the new row button so that our modal is displayed and the form cleared whenever a user clicks it.

addRow: function(){
	$modal.removeData('row'); // remove any previous row data
	$editor[0].reset(); // reset the form to clear any previous row data
	$editorTitle.text('Add a new row'); // set the modal title
	$modal.modal('show'); // display the modal
}

Step 2b: Editing a row

Next we will hook up the row edit buttons so that our modal is populated with the correct row data and then displayed.

// the editRow callback is supplied the FooTable.Row object for editing as the first argument.
editRow: function(row){
	var values = row.val();
	// we need to find and set the initial value for the editor inputs
	$editor.find('#id').val(values.id);
	$editor.find('#firstName').val(values.firstName);
	$editor.find('#lastName').val(values.lastName);
	$editor.find('#jobTitle').val(values.jobTitle);
	$editor.find('#startedOn').val(values.startedOn.format('YYYY-MM-DD'));
	$editor.find('#dob').val(values.dob.format('YYYY-MM-DD'));

	$modal.data('row', row); // set the row data value for use later
	$editorTitle.text('Edit row #' + values.id); // set the modal title
	$modal.modal('show'); // display the modal
}

Step 2c: Deleting a row

Next we will hook up the row delete buttons so that a confirm dialog is displayed and then the row removed.

// the deleteRow callback is supplied the FooTable.Row object for deleting as the first argument.
deleteRow: function(row){
	// This example displays a confirm popup and then simply removes the row but you could just
	// as easily make an ajax call and then only remove the row once you retrieve a response.
	if (confirm('Are you sure you want to delete the row?')){
		row.delete();
	}
}

Step 2d: Saving a row

Lastly we will hook up the editor's submit button to save our row data.

$editor.on('submit', function(e){
	if (this.checkValidity && !this.checkValidity()) return; // if validation fails exit early and do nothing.
	e.preventDefault(); // stop the default post back from a form submit
	var row = $modal.data('row'), // get any previously stored row object
		values = { // create a hash of the editor row values
			id: $editor.find('#id').val(),
			firstName: $editor.find('#firstName').val(),
			lastName: $editor.find('#lastName').val(),
			jobTitle: $editor.find('#jobTitle').val(),
			startedOn: moment($editor.find('#startedOn').val(), 'YYYY-MM-DD'),
			dob: moment($editor.find('#dob').val(), 'YYYY-MM-DD')
		};

	if (row instanceof FooTable.Row){ // if we have a row object then this is an edit operation
		// here you can execute an ajax call to the server and then only update the row once the result is
		// retrieved. This example simply updates the row straight away.
		row.val(values);
	} else { // otherwise this is an add operation
		// here you can execute an ajax call to the server to save the values and get the new row id and then
		// only add the row once the result is retrieved. This example simply adds the row straight away using
		// a basic integer id.
		values.id = uid++;
		ft.rows.add(values);
	}
	$modal.modal('hide');
});

Finished!

That's it! Once the above has been implemented you should have a functioning editor for your table. The below shows the complete JavaScript code with all comments removed.

var $modal = $('#editor-modal'),
	$editor = $('#editor'),
	$editorTitle = $('#editor-title'),
	ft = FooTable.init('#editing-example', {
		editing: {
			enabled: true,
			addRow: function(){
				$modal.removeData('row');
				$editor[0].reset();
				$editorTitle.text('Add a new row');
				$modal.modal('show');
			},
			editRow: function(row){
				var values = row.val();
				$editor.find('#id').val(values.id);
				$editor.find('#firstName').val(values.firstName);
				$editor.find('#lastName').val(values.lastName);
				$editor.find('#jobTitle').val(values.jobTitle);
				$editor.find('#startedOn').val(values.startedOn);
				$editor.find('#dob').val(values.dob);

				$modal.data('row', row);
				$editorTitle.text('Edit row #' + values.id);
				$modal.modal('show');
			},
			deleteRow: function(row){
				if (confirm('Are you sure you want to delete the row?')){
					row.delete();
				}
			}
		}
	}),
	uid = 10;

$editor.on('submit', function(e){
	if (this.checkValidity && !this.checkValidity()) return;
	e.preventDefault();
	var row = $modal.data('row'),
		values = {
			id: $editor.find('#id').val(),
			firstName: $editor.find('#firstName').val(),
			lastName: $editor.find('#lastName').val(),
			jobTitle: $editor.find('#jobTitle').val(),
			startedOn: moment($editor.find('#startedOn').val(), 'YYYY-MM-DD'),
			dob: moment($editor.find('#dob').val(), 'YYYY-MM-DD')
		};

	if (row instanceof FooTable.Row){
		row.val(values);
	} else {
		values.id = uid++;
		ft.rows.add(values);
	}
	$modal.modal('hide');
});