Agile software development using Kanban & Scrum. We code Flex & Ruby on Rails in Auckland, New Zealand.

  • Viewing all posts tagged "mediator"

  • Mediating ItemRenderers

    ListBase, what it is and is not.

    The ListBase classes are containers. In their simplest form, they mimic a typical OS list. In this capacity they work fairly well, and I see very little reason to mediate ItemRenderers. But they can be used for things far outside the scope of a typical list. This other use, I will refer to as the “Optimised Continuum Container”. Cool name eh? :)

    Continuum Containers.

    A “Continuum Container” is any container that presents a collection (the continuum) along an axis (1). VBox and HBox are prime examples. When the continuum get’s long, we need a scrolling mechanism to present the continuum to the user (2).

    When the continuum gets very long, we need to ‘Optimise’ the container such that it only instantiates enough children to represent what’s on screen (3). That’s what the ListBase classes do.

    A UX decision

    We decided that we wanted to present a list of items to the user in such a way that common goals (actions upon the items) were easy to find and use. Lets say its an employee list. Here’s a typical implementation of a list, with actions associated:

    Maybe not too typical, this obviously has some design challenges. Common actions for a list item should be readily locatable. One way of doing this is shown above, you keep the actions still (motionless, in one obvious place), and you select the item upon which to act.

    When your list window gets large, as ours often do, the travel time with the mouse to the action items becomes frustrating and can cause disorientation. So what we do is (and you’ve seen this many times before) is to group the actions with the list item:

    Not a typical ListItem

    So suddenly we don’t have typical list items. Each list item has more than one “concern” now:

    • Present the name
    • Present the state of “in/out”
    • Accept input to change “in/out” state
    • Accept input to launch the editor
    • Accept input to edit the item
    • Accept input to launch an email window

    It get’s even more complicated when there are modelled conditions that lie outside the VO, for example, if the user does not have permission to send emails from the application, we don’t want to show the email button.

    I personally believe that these concerns should be seperate. When I first saw an example of a view-mediator tuple for a single button, I thought “What horrendous overkill”. Now I’ve been Robotlegging it for a while, I can’t imagine a life less granular, and I always try to get my view/mediator “concern count” near to 1.

    If you don’t agree with that last paragraph, then you won’t need to mediate ItemRenderers.

    The view for my list item in that example includes several child views (and mediators) for each button. This is so clean and simple to refactor, and to read, that I would not have it any other way (pragmatically speaking).

    Mediating ItemRenderers

    ItemRenderers and ItemEditors lead a fragile existence and are not straight-forward to mediate. This does not mean you can’t mediate them, it means you must know your enemy.

    ItemRenderers are re-used.

    So when an item goes off the list, it’s renderer does not get destroyed, instead the ‘data’ property is set to a new item and the renderer is moved into place on the list.

    This means that you can’t simply rely on instantiation and the event bus to observe when you need to mediate your view. You need to also watch the data property. That’s not so hard now is it?

    Typically when you mediate, you establish state on instantiation (if necessary) and modify state as changes come off the event bus (and binding). This means that you establish an accurate reflection of state by knowing the previous “reflection of state” was correct

    That’s what makes ItemRenderers a little harder, you need to reset state more often, and there are more gotchas.

    For example, when we save an edit on a list item, we tell the Renderer (not the editor) to switch to a busy “spinny circle” state. If the item goes off screen, the Renderer get’s reused for something else, and we must reset it’s state such that it doesn’t look busy. If the item comes back on screen while still saving to the server (hello New Zealand ping times), then we need to reset it’s state to busy.

    I’ll try to write a follow up article on best practices for resetting ItemRenderer state.

    ItemEditors stand in for renderers.

    When an item is editable and the user begins an edit, the ItemRenderer is hidden, and a new ItemEditor is instantiated. This means that whatever mediation you use for the renderer, may well need to be duplicated for the editor. I keep these concerns seperate and look for common code via common refactoring methods (extract*).

    Stick with the basics.

    Despite all this, we do have a simple set of rules we always follow, no matter the renderer. I’ll spell them out here, and in my next article I’ll show some working code.

    • Use the VO dependency provided by the list (.data property)
    • OnItemEditBegin and OnItemEditEnd are handled at the parent (list) mediator.
    • When an edit begins (OnItemEditBegin), our list mediator asks the model for an editable VO and provides that to the list in place of the original VO.
    • When an edit ends (OnItemEditEnd) the list mediator issues a command to save the modified VO. This keeps us canonical with the server/services.