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.

IDFirst NameLast NameJob TitleStarted OnDate of Birth
1DenniseFuhrmanHigh School History TeacherNovember 8th 2011July 25th 1960
2ElodiaWeiszWallpaperer HelperOctober 15th 2010March 30th 1982
3RaeannHanerInternal Medicine Nurse PractitionerNovember 28th 2013February 26th 1966
4JunieLandaOffbearerOctober 31st 2010March 29th 1966
5SolomonBittingerRoller SkaterDecember 29th 2011September 22nd 1964
6BarLewisClownNovember 12th 2012August 4th 1991
7UshaLeakShips Electronic Warfare OfficerAugust 14th 2012November 20th 1979
8LorrianeCookeTechnical Services LibrarianSeptember 21st 2010April 7th 1969
9NellyLusherBroadcast Maintenance EngineerOctober 21st 2013February 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');
});