Idiomatic components and data awareness problems


#1

I have been developping with Ember for a couple of months now, embracing the component approach as much as possible and looking forward to the landing of routeable components. Throughout our projects we have seen some common problems arise and slowly came to the conclusion that not all components are born equal. Here are the different patterns I use and what I struggle with. Your opinions are most welcome.

Data down, Actions up (DDAU)

The most idiomatic use. Perfect for small components, the building blocks of any application, and the way they are advertised in Ember.

  • They enclose a generic, highly encapsulated, re-usable set of layouts or user interactions.
  • They get their data through readonly attributes.
  • They send back actions.

Typical examples: form-field, tabs-view, list-view

Editors

Using DDAU components, it is easy to encapsulate generic behaviors. The next step is to use those to build interface blocks. For instance, a post editor. A product review editor. An uploading interface.

When those interface blocks are used in several places, it comes naturally to make them components as well. However, the DDAU model starts to break apart, as upwards actions in the form “change data” explode either in size (if you send the whole dataset in each change action like sendAction('change', value)) or in number (if you send targeted change actions like sendAction('change', 'product.translations.en.name', 'Foobar'))

At this point, directly updating the data becomes an almost required step.

So this is how I would define an editor-type component: a component that has exactly one argument it updates automatically (still sending a ‘change’ action up though). Sort of a glorified {{input}}.

Typical examples: product-editor, integration-form.

Data-awareness

When dealing with related data, I often reach a point where I must let the user choose an association. For instance, select the owner of an object from a list. This can be neatly encapsulated in a DDAU component: pass it the current value, the list of options, get a select action back. Neat.

This model seems to fall short for more complex relations. Current example: I must let the user attach pictures from the picture database. It is huge, so a simple select won’t do.

Now, this picture database is organized: each user can have his personal, private Collections, and may build Galleries for publishing purposes. They provide natural organisation, so for this task of selecting pictures, I want the full deal: a modal split view with Collection and Gallery browser on the left, matching pictures on the right, upload tool on the bottom.

I am still trying to find a proper abstraction for this. Using the DDAU model would mean every-time I have a picture-select component, the parent component or the controller must pass it the gallery records, the collection records, and the picture records. And must know how to change the latter everytime the user chooses a gallery or collection in the browser. And must know how to handle uploads and react to dragndrop. In the end, this is a lot of duplicated code.

How would you handle this? Would it be acceptable to make the picture-select component directly fetch and save stuff from/to the store?

What if I wanted to add the ability to open the picture editor from the picture selection modal, change a few fields, and come back to the picture selection?

Miscellaneous concerns

I often find myself wondering where knowledge belongs. For instance, permissions? Suppose an editor should lock some fields depending on what the user can do. Maybe some choices are not available as well.

Should the component itself know this? Should it take foo-field-readonly, bar-field-readonly arguments? What about a component that shows an array of models?

Structure, structure, structure. Care to share whether you encountered similar problems (or other edge cases for the DDAU pattern) and how you solved them?


#2

Some good ideas in there. I also think that components are so generic, you really need some kind of “pattern catalogue” to be able to use them effectively.

I think that it is perfectly fine to have components that are aware of the store indirectly, although it is preferrable that they do not call necessarily methods on the store themselves, but only via a service. Ultimately, if that’s the component’s single responsibility, I do not see any problems with it. A good example is something like an autocomplete search field that is reused multiple times.


#3

The store already seems like a service to me and we use the store directly in many components including components used to select from a list of objects, components that specialize in creation of a record or records, and, of course, our autocomplete field.