Changing ships

The story so far

Yeeeeehaaaa! Creating! Reading! Deleting! We're almost done!

Two things left: Updating, and logging in. Let's do updating. You can try a new version of the ship app.

Edit buttons

Here's the new admin page, with Edit buttons, as well as delete buttons.

Admin

(The image is zoomed out to make it smaller.)

You can try it. Remember, you have to initialize the data first.

How does this compare to the previous version?

Adela
Adela
The only difference is the edit button for each row.

I'm guessing it's made in the same way as the delete button?

Yes, it is. Here's the delete button code:

var deleteButton = "<button class='btn btn-danger' "
    +    "onclick='Fleet.deleteShip(" + ship.id + ")'"
    +    "title='Permanently remove this ship' "
    + ">Delete</button>";

Here's the edit button code.

var editButton = "<button class='btn btn-primary' "
    +    "onclick='Fleet.editShip(" + ship.id + ") ' "
    +    "title='Change ship data' "
    + ">Edit</button>";

It calls editShip(), not deleteShip(), and it looks a little different, but it's basically the same thing.

Before we go into the code for editShip(), we need to talk about something else.

The edit form

Here it is:

Edit form

Georgina
Georgina
Wait, that's almost the same as the add form from last time.

What does the add form for this new app look like?

Here it is.

Add form

Ray
Ray
Georgina's right. Those last two screen shots are close.

They're almost identical. Ignoring the different headings, which are only so we call the apps apart, there are only three differences between the edit and add form. Here's the edit form again, with the differences highlighted:

Differences

  1. The instructions are different.
  2. The name field has data in it when the form loads.
  3. The displacement field has data in it when the form loads.

You can try it.

We could make two pages, one for add, and one for edit. But let's try something different. Let's make one form. We'll call its file new-edit-item.html. We'll use it for both purposes.

Add or edit

The form can do two operations on the data: the add operation, and the edit operation. But it can only do one at a time.

When the form loads, it has to know what operation the user wants: either add, or edit. How do we do tell the form which one?

Hint: here's the admin form again.

Admin

Five of the buttons will jump to new-edit-item.html.

Marcus
Marcus
Oh, I see where this is going!

Click on the Add button, and new-edit-item.html gets ready to add a new record.

Click on any of the edit buttons, and new-edit-item.html gets ready to edit a record.

Right!

There are several ways we could tell new-edit-item.html what operation the user wants. Let's so what we already know: localStorage.

Here's code for the Add and Edit buttons on the admin page:

<button class="btn btn-primary" onclick="Fleet.newShip()"
    title="Add a new ship">Add</button>
...
var editButton = "<button class='btn btn-primary' "
    +    "onclick='Fleet.editShip(" + ship.id + ") ' "
    +    "title='Change ship data' "
    + ">Edit</button>";

The add button is static HTML. The Edit button is created by JS code in a loop, with one button for each record.

The Add button calls Fleet.newShip(). Here's the function's code:

Fleet.newShip = function() {
    localStorage.setItem('operation', 'new');
    window.location.href = 'new-edit-item.html';
};

The edit button calls Fleet.editShip():

Fleet.editShip = function(shipId) {
    localStorage.setItem('operation', 'edit');
    localStorage.setItem('shipIdToEdit', shipId);
    window.location.href = 'new-edit-item.html';
};

Both functions set the operation key in localStorage, to either 'new', or 'edit'. When it loads, new-edit-item.html can check operation, to see what the user wants to do.

If new-edit-item.html is to edit a record, it needs to know what record the user wants to edit. Fleet.editShip() sends that through localStorage, in the shipIdToEdit key.

Adela
Adela
Cool! So when the page with the form loads, it checks operation, and sets itself up.

Right. Here's a diagram of that.

Setting form mode

  1. The user clicks Add (running newShip), or Edit (running editShip). operation is set to either 'new' or 'edit', depending on which function runs. If editShip runs, it does something extra: set shipIdToEdit to the id of the record the user wants to edit.
  2. The browser jumps to a new URL: new-edit-item.html.
  3. As it loads, new-edit-item.html reads operation, to find out what operation the user wants. If it should be in edit mode, it also reads shipIdToEdit.

When the add/edit form loads

As a reminder, here are the differences between add, and edit:

Differences

Here's pseudocode for the form's load event:

Connect to the TaffyDB database
Get the operation from localStorage: either 'new' or 'edit'
If the operation is edit:
    Show the edit instructions (1 in the figure)
    Get the id of the record to edit from localStorage
    Load that record from the database
    Show the record's data in the form fields (2 and 3 in the figure)
Else (it's an add):
    Show the add instructions (1 in the figure)

Here's the code.

  1. $(document).ready(function () {
  2.     //Template stuff.
  3.     ...
  4.     //Create an empty Taffy DB.
  5.     Fleet.fleetDb = TAFFY();
  6.     //Link the DB to localStorage.
  7.     Fleet.fleetDb.store("fleet");
  8.     //If this is an edit...
  9.     if ( localStorage.getItem('operation') == 'edit' ) {
  10.         //Show the user some instructions.
  11.         $("#form-purpose").html('edit a ship record');
  12.         //Get id of ship to edit.
  13.         //Convert to integer, so Taffy lookup will work.
  14.         var shipId = parseInt(localStorage.getItem('shipIdToEdit'));
  15.         //Get that ship's data.
  16.         var shipArray = Fleet.fleetDb({id: shipId}).get();
  17.         var ship = shipArray[0];
  18.         //Copy ship data to the form fields.
  19.         $("#ship-name").val(ship.name);
  20.         $("#ship-displacement").val(ship.displacement);
  21.     }
  22.     else {
  23.         //Show the user some instructions.
  24.         $("#form-purpose").html('add a new a ship record');
  25.     }
  26. });
Lines 4 to 7 connect Taffy to localStorage as usual.

Line 9 checks if the user wants an edit operation:

if ( localStorage.getItem('operation') == 'edit' ) {

If it is, line 11 shows instructions:

$("#form-purpose").html('edit a ship record');

This is where form-purpose is defined:

<h1>Ships</h1>
<p>
  Use this form to <span id="form-purpose"></span>.
  Click Cancel to forghedaboudit.
</p>

Since this is an edit, the record's current data needs to be put into the form. First, the browser gets the id of the record from localStorage (line 14):

var shipId = parseInt(localStorage.getItem('shipIdToEdit'));

Then it tells Taffy to lookup that record (line 16):

var shipArray = Fleet.fleetDb({id: shipId}).get();

Taffy returns an array of records. The first element contains the record. So (line 17):

var ship = shipArray[0];

You don't need to understand the deets. Just copy-and-paste this line.

Finally, take the record's fields, and fill in the form's fields (lines 19 and 20):

$("#ship-name").val(ship.name);
$("#ship-displacement").val(ship.displacement);

What if it's an add operation?

if ( localStorage.getItem('operation') == 'edit' ) {
    $("#form-purpose").html('edit a ship record');
    ...
}
else {
    $("#form-purpose").html('add a new a ship record');
}

The only thing we need to do it set the instructions. The form fields are empty already, which is what we need for a new record

Saving

Here's the form again (it happens to be in edit mode).

Edit form

What happens when the user clicks one of the buttons?

The Cancel button is easy.

Fleet.forghedaboudit = function() {
    if ( confirm("Are you sure?") ) {
        window.location.href = "index.html";
    }
};

The Save button is more complex, though much of it we've done before. Here's the pseudocode:

  1. Validate the data, as in the previous app.
  2. If this is a new record:
  3.     Do what we did in the previous app for adding a new record.
  4. Else:
  5.     Change the existing record to the data in the input fields.
  6. Jump to the admin list page.
Here's some code:

  1. Fleet.save = function() {
  2.     //Validate.
  3.     ...Validation code here, as before...
  4.     //Data OK.
  5.     //Is this an add, or an edit?
  6.     if ( localStorage.getItem('operation') == 'new' ) {
  7.         //Add a new record.
  8.         ...Add code goes here, as before...
  9.     }
  10.     else {
  11.         //It's an edit.
  12.         ...Edit code goes here...
  13.     }
  14.     //Go to admin page.
  15.     window.location.href = "index.html";
  16. };
The jump to index.html is after the if. That means it happens after an add, or an edit.

Let's look at the edit code. We need to change the existing record to the data in the input fields. You can try the app.

Here's the code.

  1. //Make an updated record.
  2. var shipId = parseInt(localStorage.getItem('shipIdToEdit'));
  3. var updatedShip = {
  4.     id: shipId,
  5.     name: shipName,
  6.     displacement: shipDisplacement
  7. };
  8. //Update the DB.
  9. Fleet.fleetDb({id: shipId}).update(updatedShip);
First, we make an updated record. Recall that records have three fields:

{
    id: 11,
    name: "Stan",
    displacement: 26.3
}

The id we can get from localStorage. The others are in variables we've already validated. So this will make an updated record:

var shipId = parseInt(localStorage.getItem('shipIdToEdit'));
var updatedShip = {
    id: shipId,
    name: shipName,
    displacement: shipDisplacement
};

Next to update the DB with the new record:

Fleet.fleetDb({id: shipId}).update(updatedShip);

Fleet.fleetDb({id: shipId}) is a Taffy query. It grabs the record with the given id. update(updatedShip) updates the data in that record.

Summary

You can use the same page for editing and adding. Tell the page what operation to perform. Set the page up during page load.

Woohoo! We have all the CRUD letters.