Building Enterprise HTML5 Application

Step 3) Adding the DAOs

Abstracting the application logic from the data access layer is critical for real HTML5 applications. brite accomplishes this by offering an asynchronous and pluggable DAO (Data Access Object) model. brite DAO model provides an asynchronous (with jQuery.Deferred) CRUD access layer and a powerful eventing system (jQuery like syntax, and actually jQuery backed as well).

For this step, we will just replace the static data by the brite DAO access layer. We will use the provided InMemory Dao Handler (brite.InMemoryDaoHandler), but this can be easily switched to any custom remote or local storage DAO implementation later without changing the application UI code.

The application will look like the step #2, but with a completely asynchronous and plugable data access model.

Tutorial 03 - Source | Demo

Registering the DAO with the brite.InMemoryDaoHandler

For the taskmanager application, we have two DAOs, one for each entity type, Project and Task. Both of these DAOs backed by the provided brite in-memory DAOHandler brite.InMemoryDaoHandler.

The TaskManager DAOs created by registering their DAOHandler instance with brite.registerDAO(new DAOHandler(entityType)) as follow:

js/main.js


var main = main || {};
(function(){
  
  var seedProjects = [
    {id:"001",title:"Grocery List"},
    {id:"002",title:"House Remodeling"},
    {id:"003",title:"Learn HTML5"},
    {id:"004",title:"Learn Brite"}
  ]
  
  var seedTasks = [
    {id:"101",projectId:"001",done:false,title:"Heavy Whipping cream"},
    {id:"102",projectId:"001",done:true,title:"1 Garlic"},
    ...
    
    {id:"201",projectId:"002",done:true,title:"Take room dimensions"},
    ...    
  ]
  
  // Note: here we are using the provided brite.InMemoryDaoHandler for this tutorial,
  // but DaoHandler can easly implemented to fit your server or local storage need.  

  main.projectDao = brite.registerDao(new brite.InMemoryDaoHandler("Project",seedProjects));
  
  main.taskDao = brite.registerDao(new brite.InMemoryDaoHandler("Task",seedTasks)); 
})();  

Entity DAOs obey to the singleton pattern, meaning they can be reused many times, which is why we can store their reference in main.projectDao and main.taskDao for future access.

Making the ProjectListNav view DAO aware

Now that the data will be accessed asynchronously via the brite dao asynchronous (jQuery.Deferred based) API, we cannot render the HTMLs like this:

// won't work now that all data access must be async
renderedHTML = render("tmpl-ProjectListNav",{projects:main.projectListTestData});;

So, to render the list of project HTML elements, we will need to do it asynchronously. The code will look something like this:

// from the projectDao, list all the project, and when done
// update the view.$listContainer with the new HTML elements
main.projectDao.list().done(function(projectList){
  renderedHTML = (render("tmpl-ProjectListNav-list",{projects:projectList}));
});   

Here, we are using the previously registered main.projectDao, call the .list CRUD API implemented by the brite.InMemoryDaoHandler, which returns a jQuery.Deferred promise that will resolve with the project List. In the done function, we can then render the HTML.

There are many ways to support asynchronous APIs in brite Views. For ProjectListNav, the strategy is to first display the static part of the view right away, and then, on .postDisplay to get the list of projects and refresh the .list-container element with the sub template ProjectListNav-list.

For this, we just need to change the view HTML template a little, by adding a container HTMLElement (.list-container) and creating a sub-template ProjectListNav-list. add a container HTMLElement in the template that we will refresh.

tmpl/ProjectListNav.tmpl

<dscript id="tmpl-ProjectListNav" type="text/html">
  <div class="ProjectListNav">
    <h2>Projects</h2>
    <div class="list-container">

    </div>
  </div>
</script>

<dscript id="tmpl-ProjectListNav-list" type="text/html">
  <ul>
    {{#each projects}}
    <li data-entity="Project" data-entity-id="{{id}}">{{title}}</li>
    {{/each}}
  </ul>  
</script>

Note The data-entity="Project" data-entity-id="{{: id}}" attributes at the li elements is probably the simplest but most important technic of a DOM centric programming style, which is to embed entity reference (type and id) at the outter most HTML Element of the entity representation. By doing so, any user interface interaction at the DOM level can be easily related to the corresponding entity without any complex and costly binding. For example, any logic for entity selection, deletion, or even modification can be completely generic and implemented in delegated way, and the logic just have to do a $element.closest("[data-entity]") to identify which enitity this particular action applies to.

Then, on the JavaScript side, we will just render the top template first, and refresh the project list on postDisplay.

js/ProjectListNav.js

(function() {
  
  brite.registerView("ProjectListNav",{
    
    create: function(){
      return render("tmpl-ProjectListNav");
    },
    
    postDisplay: function(){
      var view = this;
      
      // caching for future use
      view.$listContainer = view.$el.find(".list-container");

      // call the view's private method to refresh the project list.      
      refreshList.call(view);
    }
  });
  
  
  // Private view method: refresh the project list. 
  function refreshList(){
    var view = this;
    
    // from the projectDao, list all the project, and when done
    // update the view.$listContainer with the new HTML elements
    main.projectDao.list().done(function(projectList){
      view.$listContainer.html(render("tmpl-ProjectListNav-list",{projects:projectList}));
    });   
  } 

})(); 

Note that we could have made the code much shorter by not splitting out the refresh list in its own method, but this will become handy later when integrating with application and data events.

Making the ProjectView DAO aware

Similarly, making the ProjectView DAO aware is trivial. For the sake of this tutorial, we will use another strategy to display the asynchronous content for ProjectView, by using the asynchronous nature of the brite view lifecycle management, which allows the .create method of a view to return a jQuery.Deferred promise (which must resolved with the intended HTMLElement result) rather than the direct HTMLElement result.

So, on create, we will first get the Project from the DAO, and then return a jQuery.Promise using the jQuery.Deferred.pipe method that will resolve in the view HTML. Then, in the postDisplay we will call the refreshTable private method which will call the taskDao to get the list of task and refresh the UI sub elements.

js/ProjectView.js

(function() {
  
  brite.registerView("ProjectView",{
    
    create: function(data){
      var view = this;
      
      return main.projectDao.get(data.projectId).pipe(function(project){
        view.project = project;
        view.projectId = data.projectId;
        return render("tmpl-ProjectView",{project:project});
      });   
    }, 
    
    postDisplay: function(){
      var view = this;
      
      // Persist this element at the view for future use
      view.$sectionContent = view.$el.find("section.content");
      
      refreshTable.call(view);  
    }
      
  });
  
  // --------- Private Methods --------- //
  function refreshTable(){
    var view = this;
    
    return main.taskDao.list({match:{projectId:view.projectId}}).done(function(taskList){
      var taskTableHtml = render("tmpl-ProjectView-taskList",{tasks:taskList});
      view.$sectionContent.html(taskTableHtml);     
    });
  }
  // --------- /Private Methods --------- //
  
})(); 

This Deferred code might look a little overwhelming at first, but learning asynchronous JavaScript programming is critical to build simple, scalable, and powerful HTML5 application code. Once mastered, making or using asynchronous APIs become almost as trivial as direct calls but unleash a new level of capabilities.

On the templating side, we also need to do some refactoring to split the task list as a sub template. This will allow, in the later steps to refresh the task list without refreshing the full view.

tmpl/ProjectView.tmpl

<dscript id="tmpl-ProjectView" type="text/html">
  <div class="ProjectView">
      <header>
        <h2>{{project.title}}</h2>
      </header>
      <section class="heading">
        <label>Tasks</label>
      </section>
      <section class="content">      
      </section>
  </div>
</script>

<dscript id="tmpl-ProjectView-taskList" type="text/html">
  <table class="table">
      {{#each tasks}}
      <tr data-entity="Task" data-entity-id="{{id}}" {{#if done}}class="done"{{/if}}>
        <td class="title">{{title}}</td>
      </tr>
      {{/each}}
  </table>
</script>
Step 2 - The Sub Views Step 4 - Adding Events

Ask, learn, share about brite.js

Go to brite.js G+ community