10 nights with Sencha Touch, developing the mobile portfolio tracker

10 nights with Sencha Touch …

Before we start the link to the final product is here: takeStock

How powerfull is Sencha touch from a development standpoint, well, in 10 nights you can code a pretty handy application while maintaining your day job. Sencha announced the developers contest to coincide with the Sencha conference in November on October 7th with a cutoff date of the 27th of the same month, but by the time I stumbled upon the entry 10 days had passed to with only ten days to go I wondered how easy would it be for someone with some javascript experience but zero mobile application development experience, could an app be built that wasn’t an embarrassment? Without giving much thought to the task at hand I entered the contest and started working diligently to port the stock game application to the mobile phone, night one whizzed by and I had just set up the library folders on the web server and started to map out the functions that I hoped I could accommodate over the next few nights.

Day two, to store local or not to store local, for that is the question.

Night two started and I was hopeful that the project would progress without a hitch as I already had the php functions written that would call my YQL queries and update the stock prices, but this being HTML5 I wanted to try something new and use the SqlLite database that is integrated in the webkit browser opposed to the usual MySQL setip that I relied on when doing the first program. Why? First, I thought it would be cool to get the data on your phone without the need to connect. so even if you were out of range of a wireless network and using the app on your iPad, or iPod touch you could still see where your portfolio stood. Second, I did not want the hassle of creating a user account for this demo as that would be the only way to manage which portfolio data to send back from the database. third, I really wanted to try out the new HTML local storage.  After some investigating I found the following could be used to create a database to hold portfolio information:

function initDatabase() {
  try {
      if (!window.openDatabase) {
          alert('Could not create local storage, please use the browser app at learnsomethings.com/stock_game/index.php!');
      } else {
          var shortName = 'TakeStockDB';
          var version = '1.0';
          var displayName = 'Take Stock Database';
          var maxSize = 100000; //  bytes
          TakeStockDB = openDatabase(shortName, version, displayName, maxSize);
      createTables();
      selectAll();
      }
  } catch(e) {
      return;
  }
}

Then you can call the second function that will create tables for the data only if there are no preexisting tables.

function createTables(){
  TakeStockDB.transaction(
        function (transaction) {
          transaction.executeSql('CREATE TABLE IF NOT EXISTS current_stocks(id INTEGER NOT NULL PRIMARY KEY, some_column TEXT NOT NULL, another_column TEXT, third_column TEXT, some_number INTEGER NOT NULL, some_other_text TEXT, date TEXT);', []);
        }
    );
}

The function that would get the data would be as simple as:

function getAllStockData(){
  TakeStockDB.transaction(
      function (transaction) {
          transaction.executeSql("SELECT * FROM current_stocks order by id desc;", [],  allDataSelectHandler);
      }
  );
}

Day three / four – just because we can get it in the browser doesn’t mean we can get it out!

Now that the storage was sorted out I was off, or so I thought, it looks like Sencha has a local storage method, http://dev.sencha.com/deploy/touch/docs/?class=Ext.data.LocalStorageProxy but it’s for the other local storage, not the SqlLite storage. I was back to square one and day three was running short on time as I had imposed an 11PM cutoff time so I could still function the next day. What could I do? I could try the Json store, or so I thought until I realized that I would have to write code to make the call to SqlLite outside of the javascript functions to provide the URL as I was unable to get the local Json object into the Json Store! Dead end 10:00 PM. Just then I found the memory proxy and what I thought would be the answer to all my problems, I would pass the data into an object and use the memory proxy to put stocks into a handy list.

Day five – the best laid plans of mice and men often go astray

Ok maybe a list doesn’t make a compelling interface for a portfolio program, after all don’t you want to see everything that’s important to you right up front, using your fingers to scroll. Lists are for lists, but I wanted this app to show much more than the usual list, I wanted tiles that contained your current value and the increase in price so I decided to scrap the work that was done on days four and five and forge ahead with a series of containers that would slide into place depending on the action the user wanted to make, view all stocks, add stocks, just get help, or get a more detailed view of the company information. Since this was all about HTML 5 I would set up the content using sections and articles, where all the pages were sections and all of the quotes themselves were articles. An example of the main help screen is shown below:

<section id="quotes">
<article>
<h1>New In Town?</h1> 
<p>To get started adding your stocks just click the + above and complete the form.</p><h1>There are thousands of stock quote apps, what makes this different?</h1>
<p>Well, we thought you might be more interested in how your particular stock is doing without having to break out a calculator whenever you look at the current stock price, so we built an app that takes the ticker, price of the stock when you purchased it, and the quantity that you purchased and paired that with a almost (okay we’re off about 5 minutes or so) real time price update to give you a real time look at your portfolio’s net worth - anytime - anywhere.</p>
<h1>How did we do it?</h1>
 <p>You are looking at a new breed of mobile application written using HTML5 and javascript with the help of the Sencha Touch framework. In other words whether you are holding an iPhone, iPad, Android, Google Tablet, or even your home PC using Chrome or Safari you are looking at the same app - written once - run anywhere, anytime.</p>
</article>
</section>

The section tag would be displayed as a table, which means that the articles in the section could be zebra striped by applying some new CSS 3 styling.

#quotes article:nth-child(odd) {
  background-color: #E3E3E3;
 } 
 #quotes article:nth-child(even) {
  background-color:#A0A0A0;
 } 

Day Six – cards, containers, panels and lists – what should I do?

Next I created four containers that held my four screens, learning that draggable:true really messed up the users ability to scroll on the iPhone:

var carousel = new Ext.Container({
       id:'news',
       ui:'dark',
       scroll:'vertical',
       draggable:false
});
var carousel2 = new Ext.Container({
       scroll:'vertical',
       id:'portfolio',
       ui:'dark',
       draggable:false
});     
var carousel3 = form = new Ext.form.FormPanel(formBase);
var carousel4 = new Ext.Container({
       html: aboutUs,
       scroll:'vertical',
       id:'about',
       ui:'dark',
       draggable:false
});

I would then change the content on the pages with:

Ext.getCmp('portfolio').update(tbl_jst);

Things were starting to pick up, now I had to assign a handler to the elements to set the primary key of the currently selected stock in a global variable so that I could pass it in an Ajax request to the PHP page that contained the YQL queries for the expanded data view. Do you think I could fit more acronyms into one sentence? I was mailed a handy piece of code just in time by the folks at Sencha that would do the trick:

 Ext.fly('quotes').on({
          tap: setSelectedPK,
          delegate: 'article'
      });

I could slide the pages from one to the next by hooking the following line to any button handlers:

 panel.setCard(carousel2,  'slide');

Days Seven through Ten have been spent making minor adjustments to CSS and button layouts with the hopes of getting to the next round, where I would like to add some more functionality .. and thinking about one thing … how do I monetize this this thing? The short answer appears to be phoneGap, I’ll let you know how that goes in the coming weeks!

Using Ext.Updater to update page contents at set intervals

The ext framework will allow you to update an element or object  periodically using just a few lines of code by calling the page specified in the startAutoRefresh property. The component is called the Updater and the API documentation can be found here ( http://dev.sencha.com/deploy/dev/docs/?class=Ext.Updater ).This is great if you need to call a page that will update something that is happening in real time, like, stock quotes, sports scores, or rss feeds for example. The code below passes the userID to the myPortfolio.php page every 10 seconds resulting in near real time price updates for all of the users stock picks.

var myPortfolioTab = new Ext.Panel({
autoLoad: {url: 'myPortfolio.php', params: {'userID':uid},discardUrl: true },
title: 'My Stock Ticker',
closable:false,
autoScroll:true
});
myPortfolioTab.on('render', function() {
myPortfolioTab.getUpdater().startAutoRefresh(10, 'myPortfolio.php', {'userID': }, updateParam );
});

Using div tags, CSS, and Image Sprites to create a rounded box for your content

One popular design feature of many sites these days continues to be a section of framed content in a box. Some examples include the boxes that you can see on sites like CNN, or twitter just to name a few.

A framed content box that is shown on twitter

A framed content box that is shown on twitter

CNN's take on the framed box

CNN's take on the framed box

This is a perfect example of how to use nested div tags to create such an effect that has the ability to scale in width so there is no need to change the top image every time you decide to change the width of the page. If you are new to html and css you probably read the title of the article and wondered to yourself what sprite has to do with any of this, right? Sprites are a series of images that have all been combined in one image, make sense? See when you design a user interface for a website some elements are bound to be repeated over and over again, and you may want to cut doen on the round trips to the server that are made when a resource like an image is requested by the browser, the answer is creating a sprite, or a collage of all the images that will be used by the interface in ‘background-image’ css declarations. Just like the screen the coordinates 0,0 are given to the top left hand pixel of an image, therefore you can pick just the slice of a large image that you want to show in the background of a div tag. A good example would be the left hand corner below, see you start at 0 pixels from the left and 0 pixels from the top (‘background: url(‘../../testsomethings/images/bg_sprite.gif’) 0px 0px;’ ) which happens to be right where the left hand curve is at, then you go 9 pixels wide and done. For the right we use the same image but we start from the far right and go 9 pixels back toward the left ( background: url(‘../../testsomethings/images/bg_sprite.gif’) -352px 0px; ). Now for the center piece we have to go down 100 pixels from the top or else we will see the curve appear in the center box, so we use ( background: url(‘../../testsomethings/images/bg_sprite.gif’) 0px -100px ; )

You can see that the classes involved in box include:

  • roundedbox – this is the container that holds the entire box
  • header – this is the top of the box and it contains the left corner, right corner, and center sections of the round box.
  • leftCorner – this holds the left hand corner so that the background image will give the box the effect of being rounded.
  • rightCorner – this holds the right hand rounded image in the background
  • center - this is the repeating center image and also contains the heading which has been placed in a h2 tag with the font properties adjusted for readability.
  • content – this div holds the actual story content and contains the gradient grey background slice which fades into white.

You can see the code below here ( http://www.learnsomethings.com/testsomethings/rounded_corners.html ).

You can see the sprite here, but you could probably do a much better job matching the boxes yourself ( http://www.learnsomethings.com/testsomethings/images/bg_sprite.gif ).

The CSS

<style>
.roundedbox .header {
                position: relative;
                height: 33px;
                width: 100%;
                z-index: 200;
}

.roundedbox .header h2 {
                font-size: 16px;
                color:#FFF;
                font-weight:200;
                margin-left: 3px;
                margin-top: 3px;  
                display: inline;
                float: left;  
                font-family:Verdana,sans;
}

.roundedbox .leftCorner {
                background: url('../../testsomethings/images/bg_sprite.gif') 0px 0px;
                height: 33px;
                width: 9px;
                position: absolute;
                left: 0;
                top: 0;
}

.roundedbox .center {
                background: url('../../testsomethings/images/bg_sprite.gif') 0px -100px ;
                height: 33px;
                position: absolute;
                left: 9px;
                right: 9px;
}

.roundedbox .rightCorner {
                background: url('../../testsomethings/images/bg_sprite.gif') -352px 0px;
                height: 33px;
                width: 9px;
                position: absolute;
                right: 0;
                top: 0;
}

.roundedbox {
                position:relative;
                display:block;
                float:right;
                margin:8 8 8 8;
                padding: 0;
                width:100%;
}
.content {
                position:relative;
                display:block;
                background: #fff url('../../testsomethings/images/widgetBG.gif') bottom repeat-x;
                padding:6px 10px 6px 10px;
                font-family:Verdana,sans;
                font-size:12px;
                line-height:1.4em;
                list-style-type: disc;
}
</style>

The html that is required to make one of the boxes to the left consists of several div tags to comprise the various parts of the container.

The HTML code

<div class="roundedbox" >
                <div class="header">
                  <div class="leftCorner"><!-- I'm just here to make
                        the left corner rounded--></div>
                  <div class="center">
                        <h2 title="" role="complementary">Headline News</h2>
                  </div>
                  <div class="rightCorner"><!-- I'm just here to make
                        the right corner rounded--></div>
                </div>
       <div class="content" >
             <p>Some great content would normally go here, and
               maybe even a thumbnail image!<b>Read More ... </b>
             </p><br />
       </div>
</div>

Session One Code

https://docs.google.com/document/edit?id=12p2KGhhd1AlX8OM9PBfHE7pHYKB3A8akaBcbL5-7bck&hl=en

37 Signals, Getting Real, one of the best e-books out there that you can read for free

Link http://gettingreal.37signals.com/toc.php

37 signals, the seven person start up from Chicago that has gown a web application business with more than one million users released a book, Getting Real, which sums up their development philosophy, which should scare the hell out of large businesses everywhere. Why? Because many of them are so enamored of the paper trail they are producing that in essence that 500 page ‘planning’ and functional requirements documents they produce quickly become the only product that they can ship. We even have a new word for this cottage industry that has grown up around the idea of reorganization, right sizing, and certifications of certifications (read CMMI), it’s called consulting. You know it’s time to call one when you realize that you have become just too large to ‘get real’, however, when you do finally make the call instead of getting the advice that you could have found in this handy book (http://gettingreal.37signals.com/toc.php), for free, you pay just to learn that you will need even more certifications, paper titles, and other ‘credentials’.

Fortunately, these companies competitors are out there innovating and will soon surpass them with products that people really want to use, that solve real problems, and isn’t that what this is all about, having fun coding, and solving real problems? I have seen this over and over again, instead of getting things done they spend time talking about how to do things, and my personal favorite, worrying about what could go wrong. It is often said that it is better to have made the wrong choices than no choices at all.

The web moves too fast to second guess. Problems that seemed insurmountable just 25 years ago can be solved in minutes using a desktop computer today, the intersection of fast network connections, cheap storage and processing costs, and the movement of applications from the desktop to the web produce the perfect storm for companies that can remember when disk space cost $75 dollars a megabyte, and you could get a hole puncher and double your floppy disk drive capacity (instantly like magic).

Traditional roadblocks have been torn down and time to market in many traditional business models have been slashed, entry barriers have been brought down to the point where a couple of people and a laptop can effectively change an industry. One by one industries that have largely relied on such protections are falling, the last frontier are those that are heavily regulated.