Yeah, I know, I’m not the first person to the “create an EditableList for Sencha Touch” party. In fact, if you Google “sencha touch editable list,” you’ll find a lot of really nice code that will let you pretty easily integrate basic delete/sort functionality into your Sencha Touch app.

However, none of the offerings I ran across really fit the bill of what I was wanting, in terms of interface. Plus, it’s so much MORE FUN to build your own, right? Right!

What I Wanted

My wish list for my EditableList was pretty straightforward: I wanted it to behave *more or less* like my iPhone’s Mail app list editing. This includes:

  • One click to do a batch deletion/archiving of list items (btw, I absolutely HATE the same interface in the default iPhone text message app…)
  • The ability to swipe-delete individual messages
  • Some animations to make it somewhat mimic the iPhone Mail app’s animations (think “sliding” the deletion selectors in and out)

In addition to this, I wanted more or less everything–functionality, layout, interface–to be baked into my one custom extension. One of the things I didn’t like about some of the other solutions I found is that they required a certain structure external to the list (e.g., docked toolbars in certain places, etc.) that had to be in place before even using the list.

While mine makes its own assumptions, it takes care of a lot of the list-manipulation interfacy-stuff on its own. This might create some conflicts in certain scenarios, but oh well :)

Some Highlights

There’s a fair amount of code, so I’m not going to walk through it line by line. It’s fairly well-commented, so feel free to walk through it on your own over at the GitHub. I did, however, want to call attention to some bits I thought were pretty cool.

This project was the first where I’ve ever really used the relayEvents() method. Here’s what the docs have to say about it:

Relays selected events from the specified Observable as if the events were fired by this.

So what does this mean? Well, suppose we’re adding events to our main Ext.ux.EditableList. In my example, I added “beginEdit” and “endEdit” events. I use these throughout to do certain things based on the “state” of editing that is currently in effect. However, my EditableList also has child objects, like buttons, toolbars, etc., which will more than likely need to know about the same “state” in order to do what they need to do (go hide themselves, change their text, whatever). So given this reality, wouldn’t it be nice if they could all participate in the same events? That is, instead of running every change to button X through the “endEdit” listener of the main EditableList, how great would it be if I could also have a listener on the button itself for the same “endEdit” event?

This is the magic of relayEvents(). By invoking relayEvents on my EditableList’s child components, they can all be “aware” of the same events that are happening within the lifecycle of the EditableList, and react accordingly to the events as they occur. Not only does this feel more intuitive, but it allows for much more segregation of logic within the code.

An Example

Within the EditableList, there is a Toolbar that gets added to the EditableList’s parent panel to house a delete button (sort of like the delete button at the bottom of the iPhone mail app when you click the “Edit” button).  Obviously, we only really want this Toolbar to display when we’re in “edit” mode, and would prefer that it go away when edit mode stops. Using relayEvents(), we can set up listeners on the Toolbar itself for the events that are raised by the EdtiableList.

Here’s a stripped-down example of what this looks like:

Ext.ux.EditableList = Ext.extend(Ext.List, {
   ...some config stuff...,
   initComponent: function() {
      this.listeners = {
         "beginEdit": function(list,mode) {
            ...logic here...
         },
         "endEdit": function(list,mode) {
            ....logic here...
         }
      };
      Ext.ux.EditableList.superclass.initComponent.call(this);
      // add new events
      this.addEvents("beginEdit","endEdit");
   },
   addDeleteBar: function() {
      var bbar = new Ext.Toolbar({
         ...some config...,
         listeners: {
            "endEdit": function(list,mode) {
               this.hide(this.showAnimation);
            }
         }
      });
      bbar.relayEvents(this,["endEdit"]);
      ...finish adding toolbar...
   },
   someOtherFunction: function() {
      this.fireEvent("endEdit",this,"multi");
   }
})

Above, we can see that two new events–“beginEdit” and “endEdit”–have been added to the EditableList, and we have listeners applied to the EditableList to execute certain functionality when those events fire. However, because we’ve used relayEvents() on our Toolbar, we can also listen for the same events in our Toolbar, even though these events haven’t been explicitly added to the Toolbar.

Wrapping Up

If you can’t tell, I think relayEvents() is really nifty. Yes, NIFTY. I really like the ability to manage the functionality of related, but disparate components off of the same events. As I mentioned before, not only does this help to maintain consistency with how each component within EditableList understands the “state”, but it also helps keep the code clean, since we’re dealing with component-specific logic within the listeners of the components themselves, rather than in one catch-all listener at the highest level.