Thursday, July 29, 2010

@flipboard - my personal magazine

I haven't tried this yet, and I don't have an iPad still, however this video is just screaming at me to go buy an iPad just for this app. It's kind of like how Shazam and UrbanSpoon apps in the iPhone ads were the "kick over fence" for me.



I'm not all that interested about using it for Facebook, the use case that appeals to me the most is its Twitter integration. Twitter is a brilliant way to keep up on news in any field, on any topic, any event.



I'm not that interested in reading any individual's Twitter feed on the Flipboard. What I'm interested in is something like NewsMap however personalized like Flipboard. For this to work the way I think I'll find it useful, it needs to support Twitter lists, more than off my feed. Following 350 people is not easy, it stopped being easy at 25, and this is where TweetAgora came to the rescue. TweetAgora tackles this problem from one angle, identify the noise to amplify the signal. Its a very good angle. I tried a lot of Twitter clients for the iPhone and Mac, and honestly no other app tackles it as effectively as TweetAgora.

There is another angle, the angle that Flipboard could come at it, from what I have learned from Bretton MacLean it doesn't support that angle yet. When the characteristics of the noise are known, we can improve the signal to noise ratio, however if you don't know these characteristics, then you could reduce the actual signal. One of the great things about Twitter is that it opened my mind to all sorts of different topics that I didn't know I was interested in, I can miss them in my global feed, and I won't have them in my agoras because the characteristics are still unknown to me.

So here is the meat of this post. I'm thinking some sort of crazy mashup of Twitter lists, combined with Twitter lists of members on Twitter lists I follow. Ex. If I follow list A, and user 2 is on list A and they own list B, perhaps mashing up the content in list A and list B will bring to my attention new stuff for me to read when I look at the Flipboard magazine that contains list A. After all, the magazine's soul purpose is to show you something you didn't know, and kill time. : )

Anyway, congratulations to Mike McCue and the Flipboard team. All the best. I can't speak for the app itself, but the video is sick! Help me kill time more effectively.

Monday, July 19, 2010

Dojo templates & Google Maps InfoWindow

I have been building mashups using Google Maps since 2007 and one problem I had is passing in the content for these bubbles that show up when you click on a marker i.e. the InfoWindow. One big annoyance with it, is that you have to pass in the HTML content as a string when opening the marker. I don't like it because I have to intertwine HTML inside of JavaScript. So how can we make this better?

Dojo Templates


Dojo Templates is the number one reason I love this library, I like the PubSub mechanism I posted about last time but not as much as the templates.

Dojo Templates allow you to associate HTML template files with your widgets, that get instantiated when Dojo parses your page and constructs the widget, basically replacing the references to your widgets with the widget's markup in the HTML template file.

First: my infowindow.html template file

<div class="infoWindowContainer" dojoattachpoint="infoWindow">
<h1>${title}</h1>
</div>

Don't worry about that ${title} thing just yet, but I guess you already can see where I am going with this.

Second: my infowindow.js widget

dojo.declare(
"nael.widgets.infowindow",
[dijit._Widget, dijit._Templated],
{
templatePath: new dojo.moduleUrl('nael.templates', 'infowindow.html'),
constructor: function(){

}
}
);

In this example, my infowindow widget's constructor is empty.

Next we create the marker. Here we using dojo.forEach to loop over all the points that were returned with our AJAX response to fetch points. this.map is the object within this map controller that references the Google Map. (This is the same controller from the previous post on Dojo PubSub mechanism)

dojo.forEach(pois, dojo.hitch(this, function(p){
var marker = new google.maps.Marker({
position: new google.maps.LatLng(p.lat, p.lng),
map: this.map
});
var content = "<div class='infoWindow' dojoType='nael.widgets.infowindow' title='"+p.Pois.name+"'>
" ;
this.addInfoWindowToMarker(marker,content);
}));


The important part is the line where we add the content. Yes, we still need markup in there, but now its just a placeholder for the real markup. We can pass attributes like title into the placeholder for nael.widgets.infowindow. So anything that you want displayed in the info window becomes an attribute. This allows you to focus on content, and not worry about presentation just yet.

The last method we call addInfoWindowToMarker creates a Google maps listener on the marker and connects the info window to it. Note, that the info window here, is not the widget we created in the beginning. The one at the top is "nael's infowindow" and only serves the purpose of templating.

addInfoWindowToMarker: function(marker,content){
google.maps.event.addListener(marker, 'click', dojo.hitch(this, function(){
this.infoWindow.content = content;
this.infoWindow.maxWidth = 300;
this.infoWindow.open(this.map, marker);
}));
}


If you try the above, and click on the marker, the content will still be empty. Because this is a widget, it needs to be constructed. You need to tell Dojo when to parse the DOM to look for new widgets that you introduced since the last parse.


google.maps.event.addListener(this.infoWindow, "domready", dojo.hitch(this, function(){
dojo.parser.parse(this.mapCanvasNode.id);
}));


We don't want Dojo to go looking through the whole DOM for new widgets, we know where the widget was added. So we can just tell Dojo to look for widgets within the div referenced by the HTML id this.mapCanvasNode.id)

Finally, back to our infowindow.html template:

<div class="infoWindowContainer" dojoattachpoint="infoWindow">
<h1>${title}</h1>
</div>


We can now adjust the template as we please without trouble, and this sure is much cleaner than doing this like I used to for years.

var content = "<div class='infoWindowContainer'>";
content += "<h1>" + title + "</h1>";
content += "</div>";


Maybe one day Google Maps will support templating the HTML for InfoWindows internally, until then, I'm sticking to the above when I can.



The benefit of templating the InfoWindow becomes obvious when you are dealing with complex InfoWindows with functionality built into it such as sharing on social networks, embedded videos, AJAX requests, pictures, etc. All that stuff can be templated, and only the dynamic stuff that comes from the backend is passed through.

Of course, on top of being able to template your InfoWindow markup, it is much easier now to replace an InfoWindow with a version 2.0 of the InfoWindow. You just have to drop in the new and improved widget and template, then abide by the Pub Sub channels you have defined between the widget and the rest of the application.

Sunday, July 18, 2010

Dojo How To: Publish / Subscribe

I haven't been using Dojo for a very long time, just over a year now, but its time I blog about all the little great features I have learned.

One of the features I like the most in Dojo is the Publish / Subscribe mechanism. Its flexibility allows you to cleanly implement communication between different components like modules, widgets, portlets, etc.

Lets get down to business. Say I have two controllers, a map controller, and the main app controller. The map controller owns the map object in my application, in this case a Google Map object. The app controller owns the communication with the user, browser, AJAX, etc. When my app loads, I want the map to go right to the user's location. The map doesn't care where I get the coordinates from, it just needs the coordinates.


startup: function(){

//some other startup code

//subscribe to the event we will get back from the app when coordinates are available
dojo.subscribe("nael.controller.app.currentPosition", this, this.eventHandlers.updateMapCenter);

//when Im done starting up, yell to the app controller saying Im ready for coordinates
dojo.publish("nael.controller.app.requests",["getBrowserCoordinates"]);
},


So the map widget will initialize the Google Map I'm using, do some other stuff, and when it is done it will publish to the app controller's "nael.controller.app.requests" channel. The message it sends to the channel is an array of arguments. In this case it is the request ["getBrowserCoordinates"]. Your channel names can be anything, I just use the Dojo module path to that widget and end with a good description of the channel, i.e. "requests"

On to the app controller:

The startup function of the widget just subscribes to the required channels

startup: function(){
dojo.subscribe("nael.controller.app.requests",this,this.eventListener);
},


One event listener for the "nael.controller.app.requests" channel. Notice that the listener just passes it to the appropriate event handler, the one we passed in to the channel.

eventListener: function(event){
this.eventHandlers[event]();
},


Finally, the eventHandlers object which will contain all our actual event handlers. Here we have the "getBrowserCoordinates" handler which was the argument ["getBrowserCoordinates"] the map passed into the channel.

eventHandlers:{
getBrowserCoordinates: function(){
if(navigator.geolocation){
navigator.geolocation.getCurrentPosition(function(position){
var coords = {lng:position.coords.longitude, lat:position.coords.latitude};

dojo.publish("nael.controller.app.currentPosition",[coords]);

}
);
}
},

Once the app controller receives the coordinates from the browser's geo location API, it publishes the coordinates to the "nael.controller.app.currentPosition" channel - which the map widget has subscribed to during its startup step. When the map receives that event, it tells the Google Map to re-center around the new point.

I'm doing it this way, to reduce the number of channels each module needs to listen to. I can easily bring the browser to its knees if I have a unique channel for each event I'm thinking of raising. Remember, kitchens get dirty one dish at a time. It makes sense to have one "requests" channel for the main app controller, (or every widget as a matter of fact) that all other components can just send requests to.

You may ask why I have a specific channel for the current position? I guess I could have done it similarly to the requests channel. However, I figured that all widgets will be asking the app controller for stuff, while not all widgets would need to know about the user's current position. If we have a "responses" channel that all widgets subscribed to, it could lead to a lot of unnecessary chatter amongst the widgets and too many event listeners. The second reason, is that the current position channel, may get pretty noisy if it is a mobile browser. Couple both reasons together, and you have a recipe for disaster

So why should you care about JavaScript Publish / Subscribe?


The same reason you would care about it for other technologies. Its a better and much more powerful interface between JavaScript modules. Without these channels and event listeners, you would have just called the getBrowserCoordinates method from the map, or worse, you would have called the GeoLocation API straight from the map. You don't have to use Dojo for this, other libraries also provide you with a pub sub mechanism, like YUI EventTarget. Other JavaScript libraries have it, or have plugins for it. Its a design pattern that makes sense.

Note: if you are still not using a JavaScript library for your web app development, you should seriously reconsider because you are wasting a lot of time re-inventing wheels and light bulbs.

Another example, say you need to add a new widget, instead of trying to figure out where you are all the right places to call a method in this widget from another, you just add the widget and subscribe to the event that is triggered. Change request done.

One final reason, Publish / Subscribe is an excellent way to build a mockup of application workflow. You can stub in some datsabase data and when the backend is ready, you just replace the stub module with the one that will listen to the right request channel, and publish to the right response channel. And as an added bonus, if you screw up the channels, nothing breaks, the messages just won't get passed and you won't see browser errors when functions aren't defined. It fails gracefully - which is important.

Sunday, July 04, 2010

John Underkoffler points to the future of UI

I caught this video by John Underkoffler - the science advisor for the movie Minority Report on TED the other day and it got me thinking about web interfaces, especially for online banking such as CIBC's and online billing such as Roger's. I'm not saying we need interfaces such as this for these kind of online applications, but we are surely due for a major overhaul of these interfaces. I sure hope we don't need movies about these before they become more mainstream.

Is technology capable of improving the interfaces for online banking/billing sites?



Hell yes! The customers just need to demand that. We have been stuck in this e-statement model for far too long. Technology isn't the hold up. We have had these brilliant interfaces in the wild for a while now. Consider Mint. That 15 person team was so successful they were even purchased by accounting software maker Intuit in 2009. So it is not technology that is limiting us, Mint did it and clearly they don't have as much resources as the banks or telecoms do. So what is the hold up?

Its a monopoly on my data


Consider the analyst who goes through some sort of overview of customer spending habits to figure out new plans or services to offer to these customers. Do they get a dump of the data? Probably not, you can't make sense of it. For these analysts to be able to see spending habits to justify new services they probably get to see some sort of visual, a chart, a graph, something. Human minds are visual, we are pretty good at spotting things if they are in a picture, not so good at spotting the one line in a contract that will
rip you a new one
cause you trouble in the future; that is why there are lawyers. Instead of dazzling me with loading icons please start focusing on delivering a little more value. I think as much right these analysts have to study my data to justify future products and services, I too have a right to my data to make sense of my spending habits. Here's a thought, I would happily pay $6 a month for that, instead of $6 a month for call display - which by the way probably requires you to do work to DISABLE. Why do we let these people reach into our pockets without providing anything of real value to us? Would you buy a car from a dealer who asks for more money to enable the 3rd gear? or charges you per minute per kilometer driving on an out of province highway? or you pay a service charge for filling up with a different grade gas?

Who would want this kind of stuff anyway?


Gen Y grew up in the Internet age, they expect this stuff to be the norm. Its only a matter of time before it becomes the norm so why fight it? I have been using Wesabe to make sense of my banking statements up until they posted a shut down notice. I didn't mind the hassle of exporting my statement and importing it in every month to see these beautiful spending charts. The tagging feature even allowed me to track my spending on smokes by making me more disciplined at buying my smokes from the same 2 places so that I could tag my spending at these 2 grocery stores as "smokes".


As much as I'd love to manipulate my phone bill in 3D space, I will be extremely happy if my interaction with it becomes more 2010, instead of 1997. All I'm asking at this point is for 3 fairly simple, yet significant improvements:
  1. The ability to tag transactions, and to view my statement by tag for both billing & banking. Rogers already allows me to tag numbers, so you are halfway there!.
  2. View tags as a pie chart -or any other visual- for both billing and banking
  3. For banking, graph my "income" against "expenses", month to month, year over year.


Simple? Can you do it for 2010? And then if you agree that these add value to your customer, then how about you replicate Wesabe for 2011?


Minority Report science adviser and inventor John Underkoffler demos g-speak -- the real-life version of the film's eye-popping, tai chi-meets-cyberspace computer interface. Is this how tomorrow's computers will be controlled?