FlyweightRepeater and interactive components

edited October 2012 in Enyo 2
Hi all.

So I have a flyweightrepeater list showing a list of patients. For each item, I show the doctor taking care of that particular patient. When user clicks on the patient, I have a page button appear next to the doctor's name so that the user can page the doctor. I've got it working such that the button shows up on the click and the event associated with ontap works correctly. However, when the list updates (I have an auto refresh for the list), clicking on the button doesn't do anything - the user has to select a different patient and then select the original patient.

Any thoughts on what is going on? I imagine that when it is rerendering/refreshing the list (via setCount(XX)), even though it renders the button, the event associated with button is lost? (on refresh, I'm programmatically setting the selected item).



  • When the list refreshes, the relationship between the Enyo controls and the DOM nodes is broken (the same control gets rendered multiple times, essentially).

    There's a prepareRow/lockRow API for this sort of thing, or you could handle it with the selection logic, depending on how you're doing things.

    Here's a quick example, based on some other things I was playing around with earlier:

    As you'll see, the contents of the list are constantly changing, and the "page" button always sends the page to the current person.

    This doesn't handle clearing the selection if you wanted to do that when a particular row changes, or if the number of rows changes (which would invalidate the indices stored in the selection), but you can presumably handle that by manipulating the selection manually, if necessary.
  • I've never understood when / where to use prepareRow / lockRow. Would you (@mbessey @unwiredben) be able to provide an example - I think it would be useful to a lot of us in better understanding what can/cannot be put into Lists/FlyweightRepeaters, etc.

    Also, something a colleague mentioned to me that wasn't obvious but should probably go in the documentation: manipulation of of a row should happen directly in onSetupItem function and not via a secondary function called from onSetupItem. Else the rowIndex could have changed and you'd be modifying data/CSS on a row you didn't intend to change.

  • We're working on a big list revamp, but the idea will be the same.

    When you think of a List, think of having a "prototype" set of enyo objects. Each time your setupRow handler is called, you have a chance to customize those objects, then when you return, they'll be asked to render themselves into the DOM, but the JS objects won't ever be connected to a particular copy of themselves. It's like they're the originals, but all the items you see on screen are photocopies.

    Calling prepareRow is like an episode of Quantum Leap. All of a sudden, those Enyo JS controls have their node properties set to map to one of the copies. So, if you called a method like "addClass" on them, they'd actually go and directly affect the DOM. You could use things like animation with callbacks and have them work.

    However, since there's only one original, it can only be mapped into one copy at a time. Calling lockRow undoes that association, releasing the copy to once again be an unassociated part of the page and making the original objects again be unmapped.

    Why do we do this? Primarily because creating and destroying Enyo objects can be expensive, so if the majority of rows in a list will just be seen and scrolled by, it's not cost-effective to actually make first-class objects; it's better to just stamp out these facades.
  • Thanks @unwiredben. An example would be useful since I've never been sure _where_ to use lockRow/prepareRow. I tried in a few different locations and could never tell whether it was accomplishing something or not (i.e., my test code worked the same with or without it).
  • The best advice I can give you about prepareRow & lockRow is to avoid using them whenever possible :-) For many applications, the List's renderRow() API is all you need.

    Because List doesn't maintain any state for the individual rows, you pretty much *have to* use some other data structure to hold the data to be displayed (typically, an array).

    If you need to change a particular row in response to some event, normally you'd just change your underlying data, then call renderRow() to update the List. This works for any kind of one-shot event, like a button click, or a callback from an external data source.

    Where prepareRow comes into play is when you want to modify the state of a row immediately, and over more than one event cycle. The best example I can come up with for this is dragging a control inside the row.

    Let's say you have a list with a Slider inside each item. If you set this up in the usual way, then try to drag the Slider, it throws an error, because the Slider instance isn't properly connected to the DOM nodes associated with that row, which it needs to have to know how to position the knob as you drag.

    In order to fix this, you can call prepareRow() on mousedown on the item, then lockRow when the mouse is released.

    Having done that, you can then also properly handle the onChanging event for the slider, because the row will have been locked in onmousedown.

    For example:
  • Awesome, Mark... we're going to turn that fiddle into a sampler page :)
  • Thanks a bunch, Mark! It makes things a lot clearer!
Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!