QConSF 2012: Mobile Web Tooling

Pete LePage (@petele) gives a great overview of all the different tools you should consider when embarking on mobile web application development.

Sublime – text editor for Mac

Codekit
  • Minify, compiles
  • live browser reloads
  • JSHint, JSLint
  • Watches all files in direcotry for reloads

Great sites for good design patterns for mobile dev:

Great HCI guidelines from Android, iOS, Safari, etc. can be found on their respective websites

Start with boilerplates from SenchaTouch, bootstrap, and maybe even jqueryMobile

github.com/ftlabs/fastclick for improving perfomance of button clicks (usually delayed by 300ms for pinch zoom, slide, etc.)

To debug, jsconsole.com can be used for remote debugging on other devices and will show stuff on site….coolio.

Hammer.js is cool for jestures to listen to those events

brian.io/lawnchair good to store some transient data by abstracting away for IndexDB, WebSQL or LocalStorage

@media, cool for high density resolution or using CSS -webkit-image-set for both 1x and 2x image densities for hi-rez icons

CharlesProxy good to test network latency or Network Link Conditioner on Mac

Chrome Dev Tools have cool features to override geolocation, user agent, and device orientation

Android and Safari remote debugging possible but need USB cable to connect.

m.chromeexperiments.com to show off your skills.

new.mcrbug.com for filing any bugs

User Experience is x-axis and Platforms is y when trying to decide whether to go native or not, lower-right native, upper-left is hybrid. Left of line is better for hybrid because of hardware acceleration and browser improvements.

PhoneGap Perf Tips:
  1. Keep small footprint by limiting libs
  2. Use touch events, not click events
  3. Use hardware accelerated CSS transitions
  4. Avoid network access and cache locally.

zepto.js is a lightweight version of jquery that doesn’t worry about legacy browsers

Phonegap API explorer is a reference application to look at from the AppStore
Checkout PhoneGap Build to target up to 6 platforms without having to load XCode, Eclipse, etc to build all the individual platforms by hand.

Mobile GeoLocation App in 30 minutes – Part 2: Sencha Touch

Overview

This is the second part of a three part series to show how we can use Sencha Touch (a mobile web JavaScript framework) to create the GUI to integrate with our Node.js REST API that we built in Part 1. As you may recall from the previous post, I’m tracking dogs and storing their coordinates in a MongoDB. Now we will create a mobile app that will list the dogs and when selected will show them on a Google Map relative to your current location. Let’s get started.

Connecting to Node.js using MVC

Connecting to Node or really any REST/JSONP service is fairly trivial. Since Sencha Touch supports MVC on the client side, I will illustrate how to create the application using that approach. This is very useful because it keeps with one of the main programming tenets: Separation of Concerns. In this way we can create concise JavaScript applications that break-up the application along the lines of model, view and controller components. First step is to create the model as follows:

Ext.define('MyApp.model.Pet', {
    extend: 'Ext.data.Model',
    config: {
        fields: [
            {
                name: 'name'
            },
            {
                name: 'description'
            },
            {
                name: 'longitude',
                type: 'float'
            },
            {
                name: 'latitude',
                type: 'float'
            },
            {
                name: 'coords'
            },
            {
                name: 'date',
                type: 'date'
            },
            {
                name: '_id'
            }
        ]
    }
});

Notice above that I’m defining a “Pet” model by extending the Ext.data.Model class and assigning the fields to the model. Additionally, I set types as needed so they aren’t considered strings. Next, we create the store that will populate the model:

Ext.define('MyApp.store.PetTracker', {
    extend: 'Ext.data.Store',
    requires: [
        'MyApp.model.Pet'
    ],
    config: {
        autoLoad: true,
        model: 'MyApp.model.Pet',
        storeId: 'PetTracker',
        proxy: {
            type: 'jsonp',
            url: 'http://localhost:8080/dogtag',
            reader: {
                type: 'json',
                idProperty: '_id',
                rootProperty: 'records',
                useSimpleAccessors: true
            }
        }
    }
});

The PetTracker Store uses a JSONP proxy and binds the output of the service to the model we previously created. Notice, that I simply put the URL to the Node.js URL binding that will list out all dogtags and use a JSON reader to put them in the model.

Binding the Model with the View and Controller

Now that I have the data, where do I put it in the GUI? Sencha Touch provides several mobile GUI widgets that look very much like native mobile apps. In my case, I decided to use the panel with a docked toolbar at the top. Let’s take a look:

Ext.define('MyApp.view.PetPanel', {
    extend:'Ext.Panel',
    alias: 'widget.petListPanel',
    config:{
        layout:{
            type:'fit'
        },
        items:[
            {
                xtype:'toolbar',
                docked:'top',
                title:'Pettracker'
            },
            {
                xtype:'list',
                store:'PetTracker',
                id:'PetList',
                itemId:'petList',
                emptyText: "<div>No Dogs Found</div>",
                loadingText: "Loading Pets",
                itemTpl:[
                    '<div>{name} is a {description} and is located at {latitude} (latitude) and {longitude} (longitude)</div>'
                ]
            }
        ],
        listeners:[
            {
                fn:'onPetsListItemTap',
                event:'itemtap',
                delegate:'#PetList'
            }
        ]
    },
    onPetsListItemTap:function (dataview, index, target, record, e, options) {
        this.fireEvent('petSelectCommand', this, record);
    }
});

In the example above, I create a panel with fit layout (aka, responsive web design) and put a toolbar and list component in it. To get the data in the list, all I have to do is set the store to the store name I created earlier (line 16). On line 22, you can see that I’m using expression language to templatize the output of the store data in each list row (look Ma, no FOR loops!). Finally, we need to create the Controller to respond to events in the code. In the View code, you see on line 36 that I fire the ‘petSelectCommand’ when a list item is tapped. Let’s look at the controller code for this.

Ext.define('MyApp.controller.PetTracker', {
    extend: 'Ext.app.Controller',
    markers: [],
    directionsDisplay: null,
    directionsService: null,
    config: {
        stores: ['PetTracker'],
        refs: {
            petListPanel: 'petListPanel',
            petList: '#PetList',
            petMap: 'petMap',
            radiusPicker: 'radiusPicker'
        },
        control: {
            petListPanel: {
                petSelectCommand: "onPetSelected"
            },
            petMap: {
                backButton: "onBackButton",
                mapRender: "onMapRender",
                nearButton: "onNear"
            },
            radiusPicker: {
                pickerChanged: "onPickerRadiusChange"
            }
        }
    },

    launch: function () {
        // Initialize Google Map Services
        this.directionsDisplay = new google.maps.DirectionsRenderer();
        this.directionsService = new google.maps.DirectionsService();

        var mapRendererOptions = {
            //draggable: true,  //Allows to drag route
            //hideRouteList: true,
            suppressMarkers: true
        };

        this.directionsDisplay.setOptions(mapRendererOptions);
    },

    // Transitions
    slideLeftTransition: { type: 'slide', direction: 'left' },
    slideRightTransition: { type: 'slide', direction: 'right' },

    onPetSelected: function (list, record) {
        var mapView = this.getPetMap();
        mapView.setRecord(record);
        Ext.Viewport.animateActiveItem(mapView, this.slideLeftTransition);


        this.renderMap(mapView, mapView.down("#petMap").getMap(), record.data);
    },

    onBackButton: function () {
        var store = Ext.getStore('PetTracker');
        store.getProxy().setUrl('http://nodetest-loutilities.rhcloud.com/dogtag/');
        store.load();
        Ext.Viewport.animateActiveItem(this.getPetListPanel(), this.slideRightTransition);
    },

    renderMap: function (extmap, map, record) {
        // erase old markers
        if (this.markers.length > 0) {
            Ext.each(this.markers, function (marker) {
                marker.setMap(null);
            });
        } 
        var position = new google.maps.LatLng(record.latitude, record.longitude);

        var dynaMarker = new google.maps.Marker({
            position: position,
            title: record.name + "'s Location",
            map: map,
            icon: 'resources/img/yellow_MarkerB.png'
        });

        this.markers.push(dynaMarker);
    }
});

Covering all that’s inside this controller is beyond the scope of this article and besides there’s already really good articles on this such as the one here. If we pick-up from the event we fired in the view, you can see on line 16 where I’ve bound the onPetSelected() method to the event. On line 47, you can see the implementation of that method where I do the slide transition to the map view panel and then render the map in that panel. Finally, there’s this small piece of code to bootstrap the application and launch it.

Ext.Loader.setConfig({
    enabled: true
});


Ext.application({
    models: [
        'Pet'
    ],
    stores: [
        'PetTracker'
    ],
    views: [
        'PetPanel',
        'MapPanel',
        'RadiusPicker'
    ],
    name: 'MyApp',
    controllers: [
        'PetTracker'
    ],
    launch: function() {
        var petList = {
            xtype: 'petListPanel'
        };
        var petMap = {
            xtype: 'petMap'
        };
        var radiusPicker = {
            xtype: 'radiusPicker'
        };
        Ext.Viewport.add([petList, petMap, radiusPicker]);
    }
});

Conclusion

Well there you have it: how to create a mobile web application integrated with Node.js and Google Maps. You can see this application in action by pointing your mobile device to this site, http://dogtags-loutilities.rhcloud.com/, or internally here. I hope you see the value in implementing client side MVC so that your code is concise and maintainable, especially if multiple developers were to work on it. You can view the complete code base here. Look for the final part of this series where I will show you how easy it is to deploy this application to the cloud using a PaaS like OpenShift, Heroku or Nodejitsu.

SenchaCon Day2: Serving Mobile Apps from CMS

James Pearce from Sencha gives this talk.

How is Mobile is changing the Web?  The overriding question for this talk.

A perfect storm for HTML5, CSS3, and JS++ on new platforms like iOS, Android, and webkit.  New innovation is coming from mobile browser experience itself together with very capable computing devices that are in our pockets.

Mobile should be used as an adjective instead of a noun to represent how we should treat the browser on mobile devices.

Simplest thing to do is to have a separate theme to present on mobile versus desktop.

Per the mobile evolution, things like UI and biz logic can now be run on the mobile device and syncing data sets between the device and the server. Sencha Touch does a great job at doing this, even when the user is offline.

Walkthrough of connecting WordPress with SenchaTouch to a mobile device to categorize and comment on posts:

  1. Create a simple switching plugin
  2. Use MVC to create app
  3. CMS categories and posts will be modeled
  4. Stores populated and synced with JSON

For item 1, he uses UA sniffing to see if the device iPhone and redirect to a new location that contains the Sencha Touch app. He creates a simple PHP plugin and enable in into WordPress.

For item 2, he uses a generator from cmd line to create a skeleton Sencha Touch app.  He shows how it stubs out the MVC elements and tests it in a iPhone emulator to show it works.

For item 3, he shows how to create categories on the left side and the posts on the right. He does this again with the CLI to create these elements.

For item 4, he shows how we can switch the store to “ajax” and extend the PHP plugin to iterate through the data and serve that up in a JSON response.

Things to consider:

  • Thematic consistency
  • Brand consistency
  • Smart sync for large data sets
  • Account management for security in the case of a lost phone
  • http://tinysrc.net will help with scale/resize graphics for mobile screens

Mobile devices are different…geolocation, telephony, camera, messaging, etc.  How can you incorporate this easily with your CMS?

Most importantly, Mobile users are different.  Don’t just throw up a desktop designed web app on the mobile device.

SenchaCon Day2: Designing for the Mobile Experience

Brian Fling gives talk on Designing for the Mobile Experience.

Brian starts off with a history lesson on Western civilization.  The Guttenberg press is how we came out of the dark ages but shows how knowledge is the essential component and it’s persistence and availability changes the human existence.

6 Rules for building amazing apps for the mobile and tablet:

  1. Understand the medium: phones are about making the most of the moment and its primary function is communication — sharing your experience in real time.  Tablets are about focus, consumption, simple tasks and portability over desktop computers.
  2. Getting your data dialed: 1 out 3 projects go sideways due to BAD DATA! Content is data! There is no Design without the Data. Brian actual starts with DB modeling versus UI design to understand the data.  #1 challenge with mobile experience is dealing with the “semantic web” where data can come from EVERYWHERE and is it push or pull! (See Pull).  Finally, figure how to push or pull data from its source before you begin.
  3. Be a Master of Context:  See “Context of Mobile Interaction” from David Crow. Ask, how to add value to the user’s context.  Requires insight into what the user is doing (PSYCH 101).
  4. Design for the Interaction: The thing they see is the medium, the Know is the context and the do is the action they perform. Lighting is becoming more important to give the impression of 3D to emote with the user (See Norman’s Emotional Design). In Maslow’s hierarchy of needs, what need does your experience fulfill? Fulfill down to the lower level to reach level above. Affect, behavior, and cognition are aspects to consider on the response of the user to your application.  Example is the “deck” in iTunes.
  5. Focus on the Details: The future is in the details.
  6. Allow for ample time: Forget the waterfall model and focus on a more iterative process where there’s more involvement of the designer up front but also some involvement of the developer.  They will intersect and transition involvement as the project moves into development.

Brian admit’s that it feels like it’s always the first day of school — he feels he doesn’t necessarily have the answer due to the changes in this medium.