Terence Bennett - June 24, 2013
ToddAppleton

This blog post is about building a todo list app using DreamFactory for the backend. We provide a comprehensive REST API and an easy-to-use JavaScript SDK for making API calls. This example will show you how to authenticate to your DreamFactory instance and then make simple CRUD calls using the SDK.

If you don’t have a DreamFactory account, sign up here. This app can be installed as a sample app inside DreamFactory; just look for the app named “Todo List jQuery w/SDK”. If you don’t have it installed you can import it from GitHub using the apps tab in the admin console.

Code Walkthrough

This app consists of three files plus the SDK.

index.html – loads jQuery and Twitter Bootstrap and has a table to hold the list. It has an input field and add button for adding items to the list.

app.js – functions for creating, retrieving, updating, and deleting list items and building the list.

style.css – simple styling

The complete source code for this app is available on GitHub at https://github.com/dreamfactorysoftware/app-todo-jquery.  You can go there to clone this repo to your local machine.

In the SDK /lib directory there is a file sdk_init.js. This is where you specify the name of your app and the DreamFactory instance your app is talking to. For hosted apps that use the DSP for app file storage you could set dsp_url to use location.protocol and location.host and it would always init the SDK to use the “current” DreamFactory instance. If not a hosted app then dsp_url should be set to the DSP you want to use for that app.

When the SDK has been initialized the ‘apiReady’ event is triggered. At that point the app is ready to make API calls. The first thing we should do is check for a valid session and, if none exists, try to log in. The doLoginDialog() and login() methods take care of this.

$(window).on("apiReady", function () {

    checkSession();
});

function checkSession() {

    $("#loading").show();
    // check for existing session, relevant when code is hosted on the dsp
    window.df.apis.user.getSession({"body": {}}, function (response) {
        $("#loading").hide();
        // existing session found, assign session token
        // to be used for the session duration
        var session = new ApiKeyAuthorization(
            "X-Dreamfactory-Session-Token",
            response.session_id,
            'header');
        window.authorizations.add("X-DreamFactory-Session-Token", session);
        runApp();
    }, function (response) {
        $("#loading").hide();
        // no valid session, try to log in
        doLogInDialog();
    });
}

After a session has been established we call runApp() which is the main entry point into the app. The function getRecords() uses the SDK to retrieve all records from the database table named todo. You could easily use NoSQL storage such as MongoDB by adding it as a new service on your DSP, then changing df.apis.db to df.apis.mongodb in each SDK call.

function runApp() {

    // your app starts here
    getRecords();
}

function getRecords() {

    window.df.apis.db.getRecords({"table_name":"todo"},
    function (response) {
        buildItemList(response);
    }, crudError
    );
}
}

On success, an array of records is returned such as

{
   "record":[
      {
         "id":"35",
         "name":"item 1",
         "complete":false
      },
      {
         "id":"36",
         "name":"item 2",
         "complete":true
      },
      {
         "id":"38",
         "name":"item 3",
         "complete":false
      }
   ]
}

buildItemList() uses this array to populate a table inside the list-container div. Column 1 of the table is for the delete icon. Column two is for the item name. The id of each item is stored in data-id and used when the item is updated or deleted. Note the onclick handlers being set up for the update and delete ui elements. This is where the completion is toggled.

function buildItemList(json) {

    var html = '';
    if (json.record) {
        json.record.forEach(function (entry) {
            var name = entry.name;
            var id = entry.id;
            html += '';
            html += '';
            if (entry.complete === true) {
                html += '' + name + '';
            } else {
                html += '' + name + '';
            }
            html += '';
        });
    }
    $('table').html(html);
    $('#list-container .item').click(function (e) {
        var id = $(this).data('id');
        var complete = $(this).hasClass('strike');
        updateRecord(id, !complete);
    });
    $('#list-container i').click(function (e) {
        var id = $(this).data('id');
        deleteRecord(id);
    });
}

When you enter a new item and click the Add Item button, the function createRecord() is called. It grabs the item name from the input field and, if not empty, calls the SDK createRecords() method. The POST data is passed in as the “body” field and is an array of JS objects. In this case there’s only one element in the array. Since it’s a new item we will set the complete field to false. On success the input field is cleared and the list is rebuilt. To keep things as simple as possible we are calling getRecords() to retrieve and rebuild the entire list rather than updating the DOM with only the items that changed.

function createRecord() {

    var name = $('#itemname').val();
    if (name === '') return;
    var item = {"record":[
        {"name":name, "complete":false}
    ]};
    df.apis.db.createRecords({"table_name":"todo", "body":item},
    function (response) {
        $('#itemname').val('');
        getRecords();
    }, crudError
    );
}

You can click an item in the list to toggle its completion status. Each time you do this the function updateRecord() will be called. It calls the SDK method mergeRecords() with body containing an array of records to be updated. The database id must be included for each record being updated.

function updateRecord(id, complete) {

    var item = {"record":[
        {"id":id, "complete":complete}
    ]};
    df.apis.db.mergeRecords({"table_name":"todo", "body":item},
    function (response) {
        getRecords();
    }, crudError
    );
}

You can click the minus button next to an item to delete it from the list. Each time you do this the function deleteRecord() will be called. It calls the SDK method deleteRecords() with the ids field containing a comma-delimited list of ids to delete.

function deleteRecord(id) {

    df.apis.db.deleteRecords({"table_name":"todo", "ids":id},
    function (response) {
        getRecords();
    }, crudError
    );
}

Hopefully this gives you a basic understanding of how to use the SDK for CRUD operations. You can experiment directly with the API using the Live API Docs tab in the admin console of your DSP. You can use your developer tools to examine each API request in detail. Please post any questions or comments and we’ll get back to you.