Update (1/7/12): According to Ben Noordhuis, one of the core Node.js contributors and author of the buffertools module, you don’t really need to worry about using buffers when it comes to concatenating strings. Apparently V8 is extremely clever, so for example, a statement like a += b + c actually results in no copying whatsoever.

Andrew Maurer recently shared some test results showing how much more efficient it is to use Buffers when building strings in NodeJS. Although the value behind using buffers to concat strings was drilled into me over a decade ago while using Java, I’m embarrassed to admit it hadn’t occurred to me in my NodeJS work. I think it’s because, like most people, I picked up JavaScript a long time ago in the context of browser environment–a place where nobody really uses string buffers, and there aren’t any built-in mechanisms for doing so. With that in mind, I thought it was worth sharing this personal facepalm as reminder to others. It’s “101″ stuff that every Node developer should know.

To make things easier, I recommend using a module called buffertools (github / npm) which augments the out-of-box Buffers object and makes it super-easy to efficiently append strings (note that it was written by one of the core NodeJS deveopers). To borrow from the project’s own documentation, here’s an example:

require('buffertools');

// The next three lines are identical to doing "new Buffer('foobarbaz')"
a = new Buffer('foo');
b = new Buffer('bar');
c = a.concat(b, 'baz'); // non-standard function added by buffertools

console.log(a, b, c); // "foo bar foobarbaz"

// static variant
buffertools.concat('foo', new Buffer('bar'), 'baz');

Note that buffertools won’t work out-of-box on Windows since it uses UNIX-only native code.

Wireframe showing tree with both static and dynamically-loaded items

I recently needed to build an “admin” screen for a webapp using ExtJS 4. The wireframe called for a tree to navigate the various admin settings, including settings for individual users (something like what you see at right). To build a tree like this with ExtJS, you usually use the Ext.tree.Panel class (a.k.a., a TreePanel). Unfortunately I couldn’t find any examples of how to make a TreePanel with a mixture of both static and dynamic nodes, so figuring it out took longer than it should have. With that in mind, I thought I’d share what I learned.

A working example of the solution I came up with is shown below (if the embedded version doesn’t appear for some reason, you can open it here). Note that you can actually run the code in your browser and see the results–just click the play button. Or if you’d like to modify it, click the “+” button to copy the code into your own project on JSFiddle.

The first thing the code does is define a basic model class for user data, called UserModel:

Ext.define('demo.UserModel', {
    extend: 'Ext.data.Model',
    fields: ['id', 'name', 'profile_image_url']
});

The next thing it does is set up a TreeStore to load the UserModel instances:

var userTreeStore = Ext.create('Ext.data.TreeStore', {

    model: 'demo.UserModel',

    proxy: {
        type: 'jsonp', // Because it's a cross-domain request

        url : 'https://api.twitter.com/1/lists/members.json?owner_screen_name=Sencha&slug=sencha-team&skip_status=true',

        reader: {
            type: 'json',
            root: 'users' // The returned JSON will have array 
                          // of users under a "users" property
        },

        // Don't want proxy to include these params in request
        pageParam: undefined,
        startParam: undefined,
        pageParam: undefined,
        pageParam: undefined
    },
    ...
});

Note that for this example we’ll be using Twitter as our data source for faux “users”; the UserModel fields are set up to match JSON from the Twitter API (specifically, people who are a member of the “Sencha Team” Twitter list) and we need to use a JSONP proxy to make cross-domain requests (i.e., the demo is hosted at jsfiddle.net but it’s connecting to api.twitter.com). Here’s an easy-to-read sample of what the data looks like:

The JSON user data we're getting from Twitter (edited for easier reading)

The next part requires a little more explanation. First, let’s look at the code:

var userTreeStore = Ext.create('Ext.data.TreeStore', {
    model: 'demo.UserModel',
    ...    
    listeners: {
        
        // Each demo.UserModel instance will be automatically 
        // decorated with methods/properties of Ext.data.NodeInterface 
        // (i.e., a "node"). Whenever a UserModel node is appended
        // to the tree, this TreeStore will fire an "append" event.
        append: function( thisNode, newChildNode, index, eOpts ) {
            
            // If the node that's being appended isn't a root node, then we can 
            // assume it's one of our UserModel instances that's been "dressed 
            // up" as a node
            if( !newChildNode.isRoot() ) {
                
                // The node is a UserModel instance with NodeInterface
                // properties and methods added. We want to customize those 
                // node properties  to control how it appears in the TreePanel.
                
                // A user "item" shouldn't be expandable in the tree
                newChildNode.set('leaf', true);
                
                // Use the model's "name" value as the text for each tree item
                newChildNode.set('text', newChildNode.get('name'));
                
                // Use the model's profile url as the icon for each tree item
                newChildNode.set('icon', newChildNode.get('profile_image_url'));
                newChildNode.set('cls', 'demo-userNode');
                newChildNode.set('iconCls', 'demo-userNodeIcon');
            }
        }
    }
});

userTreeStore.setRootNode({
    text: 'Users',
    leaf: false,
    expanded: false // If this were true, the store would load itself 
                    // immediately; we do NOT want that to happen
});

This doesn’t look like a “normal” Ext.data.Store. For one thing, it has an “append” event handler that receives “nodes”–objects that have methods and properties from the Ext.data.NodeInterface class. Secondly, the store has a setRootNode() method that we’re calling with a config object for NodeInterface. What’s going on?

The important thing to understand here is that a TreeStore manages Ext.data.Model instances–just like any other Store–but it copies NodeInterface methods/properties into every model so that they can be linked together into a hierarchy (i.e., a tree). In this case, every instance of demo.UserModel now has NodeInterface properties like “leaf” and “text” (which indicate if the item should be expandable when it’s displayed in a TreePanel, and what text should be shown).

Next, understand that when we call setRootNode({...}), the TreeStore implicitly creates a generic Ext.data.Model instance for us, adds the NodeInterface method/properties, and then makes it the root node; when the UserModels are loaded, they will be added as “children” to this node. What we end up with is a TreeStore with models organized into a hierarchy, each one having properties that a TreePanel can use for displaying it:

The "userTreeStore" builds a data structure like this

The next thing the code does is create a separate TreeStore with some “static” nodes (again, using NodeInterface config properties).

var settingsTreeStore = Ext.create('Ext.data.TreeStore', {
    root: {
        expanded: true,
        children: [
            {
                text: 'Settings',
                leaf: false,
                expanded: true,
                children: [
                    {
                        text: 'System Settings',
                        leaf: true
                    },
                    {
                        text: 'Appearance',
                        leaf: true
                    } 
                ]
            }
        ]
    }
});

Finally, we get the root of our userTreeStore and append it as a child to the “static” TreeStore. Then it’s just a matter of creating the TreePanel.

// Graft our userTreeStore into the settingsTreeStore. Note that the call
// to .expand() is what triggers the userTreeStore to load its data.
settingsTreeStore.getRootNode().appendChild(userTreeStore.getRootNode()).expand();

Ext.create('Ext.tree.Panel', {
    id: 'usersTreePanel',
    title: 'Admin Control Panel',
    renderTo: Ext.getBody(),
    height: 300,
    width: 300,
    store: settingsTreeStore,
    rootVisible: false
});

In other words, you can “graft” TreeStores onto other TreeStores–this is the key to creating tree panels with a mixture of different data sources and underlying Models. The prerequisite, however, is understanding the NodeInterface. Hopefully this post will help others learn how to get started with TreePanels and TreeStores more quickly.

ExtJS and External Template Files

by Clint on September 22, 2011

ExtJS makes it easy to apply a template to a bunch of data (resulting in HTML output, for example). Most of the examples you’ll see show this being done with the template hard-coded as a JavaScript string. That’s fine, but what if you’d rather have your template in its own file? I recently had to do this and thought I’d share the code in case it’s helpful to anyone else.

First, here’s the usual example of a template hard-coded as a JavaScript string (click on the “Result” tab to run the code–it may take a few seconds for the output to appear):

In this case, the template is pretty small, so having it in the JavaScript isn’t too annoying. But for the sake of demonstration let’s pretend that putting in its own file makes it much easier to read/maintain. In this case, I’ve moved it to a GitHub Gist, which you can see here. To use it, we’ll modify our ExtJS code as follows:

How does this work? Every ExtJS component has the ability to remotely load and display HTML via the “loader” property, which you use to configure a Ext.ComponentLoader. The ComponentLoader lets you specify your own “renderer”–a function that handles the server response. What we’ve done is create our own “renderer” function that converts the server response–our template file–into an XTemplate. By making it a static function in our utility class, we can easily re-use it throughout the app.

This solution won’t make sense in every scenario, but if you’d prefer to keep your template in its own file and don’t mind the extra network traffic it’s a nice alternative to coding your templates as JavaScript strings.

An example of a wireframe made with Balsamiq Mockups

I’ve been using Balsamiq Mockups to make wireframes for my current project and it’s been great. There are a lot of tools for doing this kind of thing, and I’ve tried several of them (OmniGraffle, Visio, plain old Illustrator, etc.). It’s not perfect, but I’ve had a better experience with Mockups than anything else I’ve tried so far. Some perks:

  • at USD$80, it’s pretty affordable.
  • all the drawings have a deliberately “lo-fi” look. this helps keep you (and your client) focused on wireframing the ideas and not getting bogged down in nitty-gritty design stuff
  • the library of pre-built widgets is fantastic and pretty easy to configure. there’s also a website where you can download additional widgets that people have made.
  • the quick-search bar is fantastic for adding widgets quickly; hit the “/” key, type a few letters to select a widget, hit enter, and ZAP! the widget you want is added. much faster than using a mouse to find the widget you want and drag it on screen.
  • you can insert drawings from other files into your current mockup; changes to those drawings will show up in your mockup, too.
  • if you need to “override” a drawing that you’ve linked to, no problem. you can make one-off changes to that symbol without affecting the original.
  • you can make a collection of your own widgets that show up in a library for your current project, or across all projects.

Those last three points are huge. For example, I’ve downloaded a few standard widgets that I want available all the time (Mockups calls these “Account Assets”). But I also have the ability to see a library of widgets just for one client or project (Mockups calls these “Project Assets”). I can re-use any of those widgets and if I change the original file those changes are reflected everywhere else–this is a boon to anyone who has copy-pasted widgets around only to find themselves re-copy-pasting changes to that widget later. Lastly, if you reuse a widget somewhere but need to tweak it a bit for that one usage, you can do so without affecting the original. Awesome.

There is a small learning curve when it comes to figuring out how to work with groups, assets, and editing an original widget that you’ve linked to vs overriding it, but after a couple of hours of poking around and watching some of the video tutorials you’re pretty much ready to go. Also, it runs on Adobe Air which might explain while it’s a little less-than-snappy with some operations like switching between files. But on the upside, you can run it on almost every platform. And although there may be times when you crave a more traditional “drawing” app if you need to mock up a really complicated/custom widget, you can usually find a way to get the job done in Mockups.

In summary, it’s not perfect but it’s probably the best wireframing tool I’ve used so far.

I’m loving the new “class loader” mechanism that comes with ExtJS 4. That said, you’ve got to do a little extra configuration work if you have namespaces in difference directories–thought I’d share a quick example in case it’s helpful to anyone else. In this scenario, the ExtJS libraries are in one directory, the ‘myapp’ classes are in another, and ‘myapp.common’ (e.g., a shared library) classes live in yet a third directory.




Older Posts »