StorageIO.js - Utilizing Backbone.js MV* to build rich client-side application for HTML5 Storage.



Table of contents:


  1. Idea
  2. What is Backbone.js?
  3. Who uses it?
  4. Why would I use it?
  5. How do I set it up?
  6. Dependencies?
  7. Conclusion

Idea:

Good architecture/design on the client-side is sometimes an afterthought for some developers but in reality it is crucial and I’ve discovered a solution that will help me build a better StorageIO HTML5 Storage API. I know I need to store data but what about the overall structure of the applications? After another day of porting Adobe’s Brackets IDE to work in Firefox I experienced trouble integrating indexedDB with the Brackets IDE because it was originally created for working with physical file. We wanted to get Bracket IDE to work with data stored in IndexedDB.

We where lucky to have code that mimics a file-system that uses IndexedDB but if we could make it RESTful then maybe we could mimic an actual server. Usually we interact with servers by sending files through http/https using GET or POST and waiting for the server to respond but in our case we are doing everything in the client-side . The solution to many problems I'm facing in both projects is using "backbone.js". I will explain what backbone is and why it is useful.

What is Backbone.js ?

The short answer: Backbone.js is a framework that works almost like Model View Controller but is different because it uses Model View Collections. It helps you build rich client side applications.

Backbone

Helps you structure your code in Model View Collection but has a unique twist to it.
    • Model: The data layer in your application
    • View: The UI layer in your application
    • Collection: Lets you save your data to a url
Backbone has a little twist compaired to traditional MVC frameworks. It links the event processing and modification of models in the view.

Features

  • Light weight
  • Adds structure to your client-side code
  • more maintainable code in the long term
  • helps you build rich data-driven client-side applications
  • has helpful methods for querying and updating data

Who uses it?

Many companies are using it including Walmart, SoundCloud, LinkedIn and many more.

For the full list visit:
http://backbonejs.org/#examples

Why would I use it?

  • Code Reusability
  • Code Maintains
  • Rich library

Dependencies:

Backbone.js depends on Underscore.js and jQuery.

Prototype/ Mockup (Using backbone.js, underscore.js, require.js and indfs.js)



"use strict";

/* @Author: Zakeria Hassan 
 * @Date: Nov. 6, 2013
 * @Usage: Generally StorageIO uses IndexedDB http://www.w3.org/TR/IndexedDB/.  
 * If IndexedDB isn't isn't supported then it use as an alternative 
 * WebSQL http://www.w3.org/TR/webdatabase/.
 * 
 * The MIT License (MIT)
 * Copyright (c) 2013 Zakeria Hassan
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *  
 *  Dependencies:
 *  require.js  - http://requirejs.org/docs/release/2.1.9/comments/require.js
 *  jquery.js - http://jquery.com
 *  backbone.js - http://backbonejs.org/
 *  underscore.js - http://underscorejs.org/
 *  
 */

/* 
 * @parm global : 'this' object
 * @parm runner : 'callback' function
 */
(function (global, runner) {

  if (typeof exports === 'object' && typeof require === 'function') {
    module.exports = runner(require("underscore"), require("backbone"), require("idbfs"));
  } else if (typeof define === "function" && define.amd) {
    define(["underscore", "backbone", "idbfs"], function (_, Backbone, IDBFS) {
      return runner(_ || global._, Backbone || global.Backbone, IDBFS || global.IDBFS);
    });
  } else {
    // RequireJS isn't being used. Make sure underscore and backbone are loaded in script tags
    runner(_, Backbone, IDBFS);
  }
})(this, function (_, Backbone, IDBFS) {
  var global = window;
  // Use Backbone and RequireJS to improve code  
  var StorageIO = function (_dbname) {

      // USE IDBFS SOMEWHERE HERE.
      //Setting backbone models
      //1) Directory
      //2) File
      var Directory = Backbone.Model.extend({
        initialize: function () {
          // Triggered when you create a directory
        }
      });

      var File = Backbone.Model.extend({
        initialize: function () {
          // Triggered when you create a File
        }
      });
      return (global.indexedDB || global.mozIndexedDB || global.webkitIndexedDB || global.msIndexedDB) ? {
        indexedDB: global.indexedDB || global.mozIndexedDB || global.webkitIndexedDB || global.msIndexedDB,
        IDBTransaction: global.IDBTransaction || global.webkitIDBTransaction || global.msIDBTransaction,
        IDBKeyRange: global.IDBKeyRange || global.webkitIDBKeyRange || global.msIDBKeyRange,
        req: null,
        result: null,
        _fs: IDBFS,
        dbName: _dbname || "test",
        error: function (event) {
          // Should do some error handling
          // TODO: This code is not complete.. Will finish soon
          console.log("request failed!");
        },
        success: function (event) {
          this.result = this.req.result;
        },
        read: function () {
          //TODO:This code is not complete.. Will finish soon
        },
        rm: function () {
          //TODO:This code is not complete.. Will finish soon
        },
        /**
         *  @param {Object} has three keys and looks like this: {      "key" : string, 
         *                                                           "value" : string, 
         *                                                        "isUnique" : bool   }
         * Establishs a database connection and if this is a a new database
         * It creates the columns that will be used. It sets up the functions
         * that are executed if the req's fail or succeed
         */
        open: function (columns) {
          this.req = this.indexedDB.open(this.dbname);
          this.req.onerror = this.error;
          this.req.success = this.success;
          // Comment: the "onupgradeneeded" is triggered when a new database is created and   
          // TODO: Must be able to write key value pairs to the indexedDB.
          // TODO: This code is not complete.. Will finish soon
          this.req.onupgradeneeded = function (event) {
            try {
              var st = event.currentTarget.result.createObjectStore(this.dbname, {
                keypath: 'id',
                autoIncrement: true
              });
              if (!columns) throw new Error("Error code: 999 - Missing column variable in open function");
              // Setting columns up
              for (var i = 0; i < obj.length; i++) {
                st.createIndex(columns[i]["key"], columns[i]["value"], {
                  unique: columns[i]["isUnique"]
                });
              }
            } catch (e) {
              // TODO: Must handle exception 
            } finally {
              // TODO: clean up 
            }
          }
          return this;
        },
        /**
         * @param {Object} has three keys and looks like this: { "key":string, value":string, "isUnique":bool}
         */
        write: function (obj) {


        },
        close: function () {}

      } : {
        read: function () {
          /*
           * As a fallback solution to acheive cross browser compatibility 
           * I've included a Web SQL Backed solution.
           * TODO:This code is not complete.. Will finish soon
           */
        },
        write: function () {},
        rm: function () {}
      };
    };

  _.StorageIO = StorageIO;
});

Comments

  1. Great & Useful Articles

    The below website is developed using Backbone.js

    Backbone.js Course

    ReplyDelete

Post a Comment

Popular Posts