Is the design of my List component flawed?


#1

I’m trying to build a list component that

  • keeps track of which element is selected
  • is keyboard navigable, i.e. if you tap the Up Arrow key, it selects the previous list item

So far I’ve got this

        {{#ow-list items=owListItems as |item isSelected selectPrevious selectNext selectItem|}}
          {{ow-entry selected=isSelected onUp=selectPrevious onDown=selectNext onClick=selectItem}}
        {{/ow-list}}

This is my first iteration but I think its flawed because it relies on elements within the list to listen for the Up keyboard event and pass it up the list component, even though keyboard events aren’t a concern of the the element within the list.

Can anyone help me articulate the antipatterns that exist in the snippet above?

Thanks!


#2

It looks like you’re yielding out a number of attributes (item, isSelected, selectPrevious, selectNext, and selectItem), only to pass them into an entry component.

One idea would be to yield out a partially applied entry component. For example, ow-list could…

{{#each items as |item|}}
  {{yield (hash
    entry=(component "ow-entry"
      item=item
      selected=(eq item isSelected)
      onUp=(action selectPrevious item)
      onDown=(action selectNext item)
      onClick=(action selectItem item)))}}
{{/each}}

Then your calling template can use…

{{#ow-list items=owListItems as |list|}}
  {{list.entry}}
{{/ow-list}}

This has the benefit of allowing you to refactor how the list internally uses the ow-entry component without having to change the API. This would let you move the keyboard events off the entry component and on to the ow-list component.

Also, I think you’re right. I would most likely put the keyboard events on the list component, not each individual entry, but I guess it really depends on your use case.


#3

Thanks for the suggestion Ryan.

As for yielding a partially applied component, I like that idea, one thing I want to make sure of is that my ow-entry component is useful in a non-list environment too so I’d want to be careful not to over-couple the two.

I also like the usage of yielding a hash instead of 4+ properties.